Google Workspace Integration

Google Workspace (formerly G Suite) is Google's cloud-based productivity and collaboration platform. This guide shows how to integrate Google Workspace with the Tailor Platform Auth service for enterprise SSO using SAML.

Prerequisites

  • Google Workspace admin account
  • A Tailor Platform workspace with Auth service enabled
  • Basic understanding of SAML protocols

Setting up Google Workspace for SAML

Step 1: Access Admin Console

  1. Sign in to the Google Admin Console
  2. Navigate to Apps > Web and mobile apps
  3. Click Add app > Add custom SAML app

Step 2: Configure SAML Application

App details:

  • App name: Your application name
  • Description: Brief description
  • App icon: Upload your application logo (optional)

Google Identity Provider details:

  • Download the metadata XML file from Google (you'll need this for the Auth service configuration)

Service Provider details:

  • ACS URL:
    https://{your-app-domain}/oauth2/callback
    
  • Entity ID:
    https://api.tailor.tech/saml/{workspace_id}/{auth_namespace}/metadata.xml
    
  • Name ID format: EMAIL
  • Name ID: Basic Information > Primary email

Step 3: Configure Attribute Mapping

Map Google Workspace attributes to your application:

Google Directory attributesApp attributes
Primary emailemail
First namefirstName
Last namelastName

Configuring Auth Service

To configure the Auth service, you’ll need to download the Google Workspace IdP metadata XML and provide it as a string value.

1. Set the Metadata Variable

You can define the variable in one of two ways, depending on your setup:

Option A. Terraform variable file (terraform.tfvars)

Store the XML directly in your variables file

<span><span style="color: var(--shiki-color-text)">google_saml_metadata </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">&lt;&lt;EOF</span></span>
<span><span style="color: var(--shiki-token-string)">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span></span>
<span><span style="color: var(--shiki-token-string)">&lt;EntityDescriptor entityID=&quot;https://accounts.google.com/o/saml2?idpid=C123abc&quot; xmlns=&quot;urn:oasis:names:tc:SAML:2.0:metadata&quot;&gt;</span></span>
<span><span style="color: var(--shiki-token-string)">  ...</span></span>
<span><span style="color: var(--shiki-token-string)">&lt;/EntityDescriptor&gt;</span></span>
<span><span style="color: var(--shiki-token-keyword)">EOF</span></span>
<span></span>

Option B. Environment variable

<span><span style="color: var(--shiki-token-keyword)">export</span><span style="color: var(--shiki-color-text)"> TF_VAR_google_saml_metadata</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-string-expression)">&quot;&lt;?xml version=&#39;1.0&#39; ... &lt;/EntityDescriptor&gt;&quot;</span></span>
<span></span>

2. Reference the variables in the Auth configuration

<span><span style="color: var(--shiki-token-function)">resource</span><span style="color: var(--shiki-color-text)"> &quot;tailor_auth&quot; &quot;main_auth&quot; {</span></span>
<span><span style="color: var(--shiki-color-text)">  workspace_id </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> var.workspace_id</span></span>
<span><span style="color: var(--shiki-color-text)">  namespace    </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;main-auth&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)"># SAML Configuration</span></span>
<span><span style="color: var(--shiki-token-function)">resource</span><span style="color: var(--shiki-color-text)"> &quot;tailor_auth_idp_config&quot; &quot;google_saml&quot; {</span></span>
<span><span style="color: var(--shiki-color-text)">  workspace_id </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> var.workspace_id</span></span>
<span><span style="color: var(--shiki-color-text)">  namespace    </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_auth.main_auth.namespace</span></span>
<span><span style="color: var(--shiki-color-text)">  name         </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&quot;google-saml&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">  </span></span>
<span><span style="color: var(--shiki-color-text)">  saml_config </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    raw_metadata </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> var.google_saml_metadata</span></span>
<span><span style="color: var(--shiki-color-text)">    sp_cert_base64 </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">      vault_name  </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_secretmanager_vault.default.name</span></span>
<span><span style="color: var(--shiki-color-text)">      secret_name </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_secretmanager_secret.saml_cert.name</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">    sp_key_base64 </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">      vault_name  </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_secretmanager_vault.default.name</span></span>
<span><span style="color: var(--shiki-color-text)">      secret_name </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> tailor_secretmanager_secret.saml_key.name</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">package</span><span style="color: var(--shiki-color-text)"> auth</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> (</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">github.com/tailor-platform/tailorctl/schema/v2/auth</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">github.com/tailor-platform/tailorctl/schema/v2/secretmanager</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">)</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)">// SAML Configuration</span></span>
<span><span style="color: var(--shiki-color-text)">googleSaml: auth.#Spec </span><span style="color: var(--shiki-token-keyword)">&amp;</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">  Namespace: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">main-auth</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">  IdProviderConfigs: [</span></span>
<span><span style="color: var(--shiki-color-text)">    auth.#IDProviderConfig </span><span style="color: var(--shiki-token-keyword)">&amp;</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">      Name: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">google-saml</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">      Config: auth.#SAML </span><span style="color: var(--shiki-token-keyword)">&amp;</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">        RawMetadata: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">{GOOGLE_SAML_METADATA}</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">        SpCertBase64: secretmanager.#SecretValue </span><span style="color: var(--shiki-token-keyword)">&amp;</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">          VaultName: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">default</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">          SecretKey: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">saml-cert</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">        }</span></span>
<span><span style="color: var(--shiki-color-text)">        SpKeyBase64: secretmanager.#SecretValue </span><span style="color: var(--shiki-token-keyword)">&amp;</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">          VaultName: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">default</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">          SecretKey: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">saml-key</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">        }</span></span>
<span><span style="color: var(--shiki-color-text)">      }</span></span>
<span><span style="color: var(--shiki-color-text)">    }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">  ]</span></span>
<span><span style="color: var(--shiki-color-text)">  UserProfileProvider: auth.#UserProfileProviderType.TailorDB</span></span>
<span><span style="color: var(--shiki-color-text)">  UserProfileProviderConfig: auth.#TailorDBProviderConfig </span><span style="color: var(--shiki-token-keyword)">&amp;</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">    Namespace:     </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">main-db</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    Type:          </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">User</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    UsernameField: </span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">email</span><span style="color: var(--shiki-color-text)">&quot;</span></span>
<span><span style="color: var(--shiki-color-text)">    AttributesFields: [</span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-token-string-expression)">roles</span><span style="color: var(--shiki-color-text)">&quot;</span><span style="color: var(--shiki-color-text)">]</span></span>
<span><span style="color: var(--shiki-color-text)">  }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>

Domain Verification

For Google Workspace SAML integration, you may need to verify domain ownership:

  1. In Google Admin Console, go to Security > Set up single sign-on (SSO)
  2. Add your application domain to the verified domains list
  3. Follow Google's domain verification process

Troubleshooting

Common Issues

Domain Not Verified

  • Complete Google's domain verification process
  • Ensure DNS records are properly configured

SAML Assertion Errors

  • Verify Entity ID matches exactly
  • Ensure user has access to the application

Next Steps