Skip to content

Connect a corporate directory

Let sluis read a Google Workspace tenant's users, groups and domains. Create the OAuth client once, then consent per tenant. Microsoft Entra has no backend (extending sluis).

Before you start

  • Enable the Admin SDK API first, or the first read is refused after consent.

  • Publish the consent screen (In production). In Testing a second tenant gets Error 403: access_denied and refresh tokens expire after seven days.

  • Consent as a Super Admin. The token dies with that account; a narrower role fails with a 403.

Every credential reads these four read-only scopes. The domain scope also feeds Slack domain discovery.

https://www.googleapis.com/auth/admin.directory.user.readonly
https://www.googleapis.com/auth/admin.directory.group.readonly
https://www.googleapis.com/auth/admin.directory.group.member.readonly
https://www.googleapis.com/auth/admin.directory.domain.readonly

Create a project and enable Admin SDK API. In Google Auth Platform, set the audience to External, press Publish app, and add the four scopes under Data access. Admins click through the unverified-app warning. A tenant that blocks unconfigured apps must trust the client id.

2. Create the OAuth client

Create a Web application client with both redirect URIs:

https://<host>/connect/google/callback    # an administrator granting read access; demands an operator
https://<host>/login/google/callback      # a person signing in

3. Hand the client to sluis

Create a Secret with keys client-id and client-secret; the console shows the client read-only. Use idKey and secretKey for other names.

config:
  oauthClient:
    secretName: google-oauth-client
    idFile: /var/run/sluis/oauth-client/client-id
    secretFile: /var/run/sluis/oauth-client/client-secret
secretMounts:
  - { secretName: google-oauth-client, mountPath: /var/run/sluis/oauth-client }

4. Connect a tenant

An operator presses Connect Google Workspace, and a Super Admin signs in and consents. A refused first read usually means the Admin SDK API is off.

Then choose domains. The admin's domain is preselected, and all, including ones added later is an option. Unselected domains are never read. First snapshot pending shows for up to two minutes.

Alternative: a service-account key

Create a service account and JSON key with domain-wide delegation for the four scopes. Choose Upload key on the console, or declare it in values (read-only there; remove it to disconnect):

directory:
  workspaces:
    - id: C0example              # the backend's tenant id (Google: the customer id)
      backend: google
      admin: [email protected]   # the account the key impersonates
      secretName: example-sa-key # a Secret in this namespace, key.json holding the JSON key
      serve: [example.com]       # optional; omitted serves every domain the tenant owns

All values, including syncGroups, are in declared workspaces.

Verify

The workspace appears with its tenant id, and the served domains read authoritative.

Roll back

  • Disconnect revokes the token and deletes the credential and record; consumers get in_domain=false. Delete a service-account key yourself.

  • Reconnect repairs a failed probe, for the same tenant only.

  • To move a domain, connect the new tenant serving all domains, including later ones. The console shows the domain contested during the overlap.

The credential is in Secret <release>-workspace-credentials, part of the backup set; directory.push renders a recovery copy.