# Connect Google Workspace as the source directory

> Give AnySCIM read-only access to Google Workspace users, groups and org units with a service account or OAuth login, then pull the first snapshot.

AnySCIM reads your Google Workspace directory through the **Admin SDK Directory API** with read-only scopes only. It never creates, changes or deletes anything in Google. The data is stored as a local snapshot, and every SCIM connection provisions from that snapshot.

## Before you start

- A Google Workspace **super admin**, to create the role and authorize API access.
- A dedicated user for AnySCIM, for example `scim-reader@yourdomain.com`.
- A Google Cloud project, to create the service account or OAuth client.

## 1. Create a read-only admin role

1. In the Google Admin console, open **Account → Admin roles** and create a new role.
2. Under **Admin API privileges**, grant only the **read** privileges for **Users**, **Groups** and **Organizational units**.
3. Assign the role to the dedicated user (`scim-reader@yourdomain.com`).

Keeping this user read-only means that even a leaked credential cannot modify your directory.

## 2. Choose how AnySCIM signs in

There are two supported methods. Use a service account for unattended syncs.

| Method | Best for | What you create |
| --- | --- | --- |
| Service account | Scheduled, unattended syncs | A service account with a JSON key and domain-wide delegation |
| OAuth login | Quick tests, no delegation | An OAuth client (*Web application* on the AnySCIM site, *Desktop app* for the local `scim-web`); the read-only user signs in once |

### Service account with domain-wide delegation

1. In Google Cloud, create a service account and download a **JSON key**.
2. In the Admin console, open **Security → Access and data control → API controls → Domain-wide delegation**.
3. Add the service account's **client ID** with exactly these scopes:

```text
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.orgunit.readonly
```

AnySCIM impersonates the read-only user (the *subject*) with these scopes. Because the subject only holds read privileges, the delegation cannot write either.

### OAuth login

Create an OAuth client in Google Cloud → **APIs & Services → Credentials**. The read-only user signs in once from the browser and AnySCIM stores the refresh token, encrypted.

- **AnySCIM site**: choose the type **Web application** and add the **Authorized redirect URI** shown in Settings → Directory source when you pick OAuth sign-in (it ends in `/api/sources/oauth/callback`).
- **Local `scim-web`**: choose the type **Desktop app**. Google redirects to a loopback address, so the browser must run on the same machine as AnySCIM.

## 3. Add the source to AnySCIM

In the dashboard, open **Settings → Directory source** (when no source exists yet, the form is already open):

1. Choose **Service account** or **OAuth sign-in**.
2. Enter the email of the read-only admin user and a name for the source.
3. For a service account, upload the `key.json` file. AnySCIM shows the service account's **client ID** and the three scopes, ready to copy into the domain-wide delegation page.
4. Click **Test access**. AnySCIM reads one user, one group and the organizational units, and tells you which permission is missing if any check fails.
5. Click **Save and pull** to store the source and download the directory. With OAuth, click **Sign in with Google** instead: Google opens in a new tab, and the source is saved and pulled as soon as the read-only user signs in. The sign-in must be finished within 5 minutes.

The service account key, client secret and refresh token are encrypted at rest with your `SCIM_MASTER_KEY`.

## 4. Pull and keep the snapshot fresh

After the first pull, the dashboard shows your users, groups and organizational units under **Users & groups**. **Sync now** in the dashboard pulls Google again and then pushes every active connection. You can also schedule it in **Settings → Sync interval** (manual, every 5 minutes, 15 minutes or 1 hour).

## What AnySCIM reads

| Google attribute | SCIM attribute |
| --- | --- |
| `primaryEmail` | `userName` and work email |
| `name.givenName`, `name.familyName` | `name.givenName`, `name.familyName` |
| `name.fullName` | `displayName` |
| `suspended`, `archived` | `active` (inverted) |
| `id` | `externalId` |
| `organizations[primary].title` | `title` |
| `organizations[primary].department` | enterprise `department` |
| `organizations[primary].costCenter` | enterprise `costCenter` |
| `phones[type=work]`, `phones[type=mobile]` | `phoneNumbers` |
| Group membership | `Groups.members` (nested groups expanded) |

Next, connect your first app: [Slack](/docs/slack), [GitHub](/docs/github), [Atlassian](/docs/atlassian) or any [custom SCIM 2.0 endpoint](/docs/custom-scim).

## FAQ

### Does AnySCIM need a super admin account?

Only to set things up. The day-to-day sync runs as a dedicated user with a custom role that has read-only privileges on users, groups and organizational units.

### Can AnySCIM change anything in Google Workspace?

No. It requests only the three `readonly` Directory API scopes, so Google rejects any write.

### How are suspended users handled?

By default a suspended Google account is sent to every connected app as `active: false`. In **Settings → When a user is suspended** you can choose to ignore suspended users instead.
