---
name: google-workspace-directory-oauth-app
description: >-
  The Admin SDK Directory API layer on top of the shared
  `google-cloud-console-oauth` skill — why it only works against Google
  Workspace, never consumer Gmail, the `admin.directory.*` scopes (none
  restricted), the admin role checked in addition to the scope, domain-wide
  delegation as a per-customer super-admin task, `customer=my_customer`, users
  vs members vs org units, the lack of a delta or sync token, and Directory
  quotas and page-size caps. Use when asked to get Google Workspace Directory
  or Admin SDK OAuth credentials, scope an employee-directory or group-sync
  integration against Google, decide between user OAuth and a delegated
  service account, or explain a 403 on a token that authorized cleanly. Read
  `google-cloud-console-oauth` first for the console mechanics; use
  `microsoft-entra-directory-oauth-app` for the Microsoft equivalent.
---

# Google Workspace Directory OAuth2 App Registration

This is not a per-user product API. The Directory API is part of the **Admin SDK**, and Google describes it as the way
to "programmatically create and manage admin-controlled resources owned by a Google Workspace account." Two things
follow immediately, and they decide whether the integration is even possible:

- **It only exists inside Google Workspace.** There is no consumer equivalent. A personal `@gmail.com` account has no
  customer, no org units, no directory to read, and no admin console to consent from. A connector that lists "Google"
  as a directory source will be tried against consumer accounts and will fail every time.
- **The scope is not the gate.** Google checks the **admin privilege of the consenting user** on top of the OAuth
  grant. A perfectly declared, perfectly verified client, authorized by an ordinary employee, returns `403` on its
  first real call. Nothing in the Cloud console fixes that — the fix lives in the customer's Admin console (§3).

The compensation is that the paperwork is unusually light: checked against Google's restricted-scope list on
2026-09-20, **no `admin.directory.*` scope appears on it.** The expensive part of this registration is not
verification. It is that every customer needs an administrator to connect, and some of them will need a super admin
(§4).

## Built on: `google-cloud-console-oauth`

**Read `google-cloud-console-oauth` first, then this file.** It owns the console mechanics and this file does not
repeat them:

- The Cloud project and organization, enabling the API a scope belongs to, and who may administer the project.
- The Google Auth Platform pages (Branding, Audience, Data Access, Clients), the **Web application** client, and the
  redirect-URI matching rules with the per-data-center callback list.
- The generic scope model: declaring every scope, the three tiers and what each costs, the rule that an app takes the
  tier of its most sensitive scope, and the refresh-token conditions on the authorize URL — plus the authoritative
  restricted-scope list this file checks the Directory family against.
- The client secret's one-shot visibility, rotation, publishing status, audience, the user caps and verification.
- The Workspace admin's app-access controls, which can block or allowlist this client independently of everything
  below, and the generic OAuth failure table including what a quota-flavoured `403` means.

If you are reading only this file, you are missing all of the above.

## Inputs to collect before you start

The base skill lists the console inputs. These are the Directory-specific ones:

| Input | Notes |
| --- | --- |
| **Which directory objects does the product touch?** | Users, groups, group members, org units, aliases, custom schemas, roles, devices — each is its own scope pair (§2) |
| **Read-only, or does it provision?** | Read-only lands on `.readonly` scopes and on a read privilege; provisioning needs write scopes *and* write privileges (§2, §3) |
| **Who at the customer will click Connect?** | A super admin, a delegated admin, or an ordinary employee — this is the question that decides whether the integration works at all (§3) |
| **User OAuth, or a delegated service account?** | Different credential, different customer task, different failure modes (§4) |
| **Multi-domain customers?** | `customer` vs `domain` are not interchangeable and one of them silently under-returns (§5) |
| **How fresh must the directory be?** | There is no delta token; freshness comes from polling plus one push channel (§6) |
| **Largest expected customer, in users and groups** | Page-size caps and a per-account rate limit that cannot be raised (§7) |

## Quick Start

1. Work the base skill's console steps, and **enable the Directory API** on the project (Google's quickstart carries
   the enable link). A perfect client against a project with the API off fails at the first call, not at consent.
2. Pick the narrowest scope pair per object type from §2 and declare exactly those.
3. **Decide the credential model before registering anything** (§4): a user OAuth client an admin authorizes, or a
   service account each customer's super admin delegates. They are different products for the customer.
4. Write the admin requirement into the product's connect instructions (§3). It is the single largest source of
   "your integration is broken" tickets and the single thing a console cannot fix.
5. Finish the base skill's capture, round-trip and handoff steps, adding the Directory checks in §8 — and do the round
   trip **from a non-admin account too**, because that is the failure you are shipping to customers.

## Directory platform state (verified 2026-09-20 — re-verify before trusting)

- **Base URL `https://admin.googleapis.com/admin/directory/v1/`.** Google's own guides still show a few legacy
  `www.googleapis.com/admin/directory/...` forms, notably around notification channels; prefer the `admin.googleapis.com`
  host everywhere and treat a legacy host as something to verify, not inherit.
- **Scope tiers: none of the `admin.directory.*` family appears on Google's restricted-scope list** (the base skill
  holds that list). The Directory API's own scope page publishes the family with meanings but **no tier labels at
  all**. Resolving a tier for one of them is therefore the negative test the base skill's §5 sets out, run against
  this family.
- **The scope family is one pair per object area:** devices (`device.chromeos`, `device.mobile`, `.readonly`,
  `device.mobile.action`), groups and members (`group`, `group.readonly`, `group.member`, `group.member.readonly`),
  org units (`orgunit`, `orgunit.readonly`), users and aliases (`user`, `user.readonly`, `user.alias`,
  `user.alias.readonly`), user security (`user.security`), role management (`rolemanagement`, `.readonly`), custom
  schemas (`userschema`, `.readonly`), customers (`customer`, `.readonly`), domains (`domain`, `.readonly`) and
  calendar resources (`resource.calendar`, `.readonly`).
- **`users.list` and `users.watch` also accept `https://www.googleapis.com/auth/cloud-platform`.** It is a
  project-wide Cloud scope that happens to satisfy these methods. Do not reach for it — it is enormously broader than
  `admin.directory.user.readonly` and will dominate a consent screen and a review.
- **Page-size caps differ per resource:** users default 100, **maximum 500**; groups and group members default and
  maximum **200**; Chrome and mobile devices default and maximum 100. **User aliases and org units do not paginate at
  all.** A `pageToken` **is only valid for three days.**
- **There is no sync token and no delta method anywhere in `users.list`'s documented parameters.** Incremental sync is
  polling plus, for users only, a push channel (§6).
- **Push notifications exist for the Users resource only** — no group, member or org-unit channels.

If the scope page or the caps do not look like this, stop and report what you actually see rather than proceeding.

## 1. The API this actually is

Directory is one API inside the Admin SDK, alongside Reports, Data Transfer, Groups Settings and others. Its
vocabulary is the vocabulary the rest of this file uses, and Google defines it on the overview page:

| Term | What it is |
| --- | --- |
| **Customer** | The entity owning the Workspace account. Everything is scoped to one. |
| **Domain** | A DNS domain attached to the account — **an account can have many**, and not all accounts have one. |
| **Organizational unit (OU)** | A sub-unit of the account's tree, used to apply policy. Users sit at an `orgUnitPath`. |
| **Privilege** | The ability to perform an action. This is what an admin role is made of, and what §3 turns on. |
| **Role / role assignment** | A named collection of privileges, and the record granting it to a user. |
| **User / Group / Member / Schema** | The resources the connector actually reads. |

Google's quickstart states the prerequisites plainly: "A Google Workspace domain with API access enabled. A Google
Account in that domain with administrator privileges." Treat that second sentence as a product requirement, not a
developer convenience.

## 2. Scopes: narrow pairs, and the cost of getting greedy

Each object area has a full scope and a `.readonly` scope; a handful have extra action scopes. The ones an
employee-directory or group-sync product actually needs:

| Capability | Read scope | Write scope |
| --- | --- | --- |
| Users and user profiles | `https://www.googleapis.com/auth/admin.directory.user.readonly` | `https://www.googleapis.com/auth/admin.directory.user` |
| Groups (and, per the reference, listing their members) | `https://www.googleapis.com/auth/admin.directory.group.readonly` | `https://www.googleapis.com/auth/admin.directory.group` |
| Group membership specifically | `https://www.googleapis.com/auth/admin.directory.group.member.readonly` | `https://www.googleapis.com/auth/admin.directory.group.member` |
| Org units | `https://www.googleapis.com/auth/admin.directory.orgunit.readonly` | `https://www.googleapis.com/auth/admin.directory.orgunit` |
| Custom user fields | `https://www.googleapis.com/auth/admin.directory.userschema.readonly` | `https://www.googleapis.com/auth/admin.directory.userschema` |

Three things worth saying out loud:

- **`members.list` accepts `admin.directory.group.readonly` on its own.** Its documented scope list is
  `group`, `group.readonly`, `group.member` and `group.member.readonly`. So a read-only group-sync product does not
  strictly need the member scope to enumerate members — verify against the exact method list before declaring both,
  because each extra scope is another consent line an admin has to accept and another thing to justify at review.
- **`.readonly` still means the whole directory.** `admin.directory.user.readonly` reads every user in the customer,
  including fields an ordinary employee cannot see. It is read-only, not narrow, and there is no per-OU scope. The
  narrowing that exists is done by the admin role (§3), not by the scope string.
- **Write scopes are a different conversation with the customer's security team** than read ones, because the same
  token that patches a job title can suspend an account. Ask whether provisioning is genuinely in the product before
  declaring the non-`.readonly` variants.

Reading the customer's directory structure — `orgunits.list` — needs the org-unit scope; it is not implied by the
user scope, and a product that renders an org chart from `orgUnitPath` strings on user records may not need it at all.

## 3. The admin role is checked in addition to the scope

**This is the section that decides whether a customer can connect.** A Google OAuth grant proves the user agreed to
the scope. It does not prove the user is allowed to do the thing.

Google's privilege documentation is explicit that the Admin console privilege is what carries into the API: of the
**Users** privilege (Create, Read, Update, Delete) it says "This privilege grants API permissions you can use to
perform these operations with the Directory API," and it says the same of the **Organizational Units** privilege.
The prebuilt roles page names which roles work "using the Admin API" — **Super Admin**, **User Management Admin**,
**Groups Admin** and **Help Desk Admin** among them.

So:

- **A super admin is not required for ordinary directory reads and writes.** A delegated admin holding the right
  privilege — Users ▸ Read for a read-only people sync, Groups for group management — is enough, and asking a
  customer for a super admin when a scoped delegated admin would do is a real objection in an enterprise security
  review. Say which privilege you need, not "make them an admin."
- **A super admin *is* required for the things that manage admins themselves**, including promoting a user
  (`users.makeAdmin` — Google notes "delegated administrators cannot promote users to administrative roles") and role
  management, and for domain-wide delegation (§4).
- **The role is per customer.** Nothing about it is visible from your Cloud project, and it cannot be pre-arranged.
  Every new customer repeats it.

### The one thing a non-admin can do

There is a real exception, and it is useful. Google documents that "while user accounts can only be modified by
administrators, any user on the domain can read user profiles": a non-admin can call `users.get` or `users.list` with
**`viewType=domain_public`**, and Google says `admin.directory.user.readonly` "is ideal for this use case." Two
caveats it attaches: the domain-public view returns only a standard set of core fields (custom fields are public or
private by schema definition), and **"Contact sharing must be enabled for the domain. Individual users with contact
sharing disabled are not returned in the results."**

That gives a genuine product option — a lightweight "read the company directory" connector that any employee can
authorize — but it is a different product from an HR-grade sync. The admin-only view is `viewType=admin_view`, and
some query capability is admin-only with it: the `orgUnitPath` search field "can only be used when
`viewType=admin_view`." A connector that hard-codes the admin view will fail for a non-admin no matter how modest
the data it wanted.

### The failure it produces

A connection authorized by a non-admin looks perfect: consent completes, the token exchange returns an access token
and a refresh token, and then the first directory call returns **`403`**. Field reports quote the message as
"Not Authorized to access this resource/api" — **that exact wording is not on a Google page this skill could verify**,
so treat the string as a hint rather than a contract, and diagnose on the documented causes instead. Google documents
these 403 reasons for the Directory API:

| Reason | Meaning |
| --- | --- |
| `usageLimits.accessNotConfigured` | The API is not enabled in the Cloud project. |
| `domainCannotUseApis` | The customer has disabled access to the Admin SDK API. |
| `forbidden` | The caller does not have rights over that customer (the reseller page's framing; the same shape covers a caller without the privilege). |

The practical triage order is: is the API enabled → does the customer allow the Admin SDK API → **does the consenting
user actually hold the privilege** → is the request using `admin_view` when the consenting user is not an admin. Only
the first is yours to fix.

## 4. Domain-wide delegation — the other path, and why it is per-customer

The alternative to "an admin clicks Connect" is a service account the customer's Workspace pre-authorizes to
impersonate its users. It removes the consent screen entirely and it is how a lot of Workspace tooling works — but it
is not something you register once and ship.

Google's help documentation is specific: **"You must be signed in as a super administrator for this task,"** and the
task lives in the customer's Admin console under **Menu ▸ Security ▸ Access and data control ▸ API controls ▸ Manage
Domain Wide Delegation**, where the admin enters your **client ID** and each **OAuth scope** the application may
access — Google advises the scope list "should be appropriately narrow." Other facts that change project plans:

- **"Changes can take up to 24 hours but typically happen more quickly."** A customer who just saved the delegation
  and reports failure may simply be early.
- **If Multi-party approval is enabled, a second super admin has to approve it.** That is a scheduling problem, not a
  technical one, and it surfaces at onboarding.
- **"With domain-wide delegation, the app has access to the data belonging to all of your users."** Google recommends
  reviewing and deleting unused service accounts. Expect a security review; expect some customers to refuse outright.
- **It is per customer, every time.** Each new Workspace repeats the whole ceremony. There is no marketplace listing,
  no consent screen and no self-service path that skips it.

Neither model dominates. User OAuth reaches only what the authorizing admin may reach and dies when that admin leaves
the company; delegation survives staff changes and reaches everything, which is exactly why some customers will not
grant it. Decide deliberately, and note that scopes change on the *customer's* delegation entry — adding one later
means going back to every customer's super admin.

## 5. Customer, users, members, org units

The shapes here are not interchangeable, and each has a way of quietly returning the wrong set.

- **`customer=my_customer` is the convention for "the account this token belongs to."** Google documents `my_customer`
  as an alias for the caller's own `customerId`, and a resold customer's real `customerId` in its place. **You must
  provide either `customer` or `domain`**, and Google's own troubleshooting is emphatic that they are not
  interchangeable: for `customer`, "Only use the `customerId` that was generated by Google. Don't use the actual
  customer's domain," and it recommends `customer` over `domain` "because if a customer has secondary domains, using
  the `domain` parameter only returns users with email addresses on that particular domain." A multi-domain customer
  whose sync is missing half its people is usually this.
- **Users are not members.** Group membership is its own resource: "A group member can be a user or another group,"
  so a members list can contain nested groups, and flattening it to people is your job. `members.list` takes
  **`includeDerivedMembership`** (default `false`) to expand indirect membership — omit it and members who belong only
  through a nested group are simply absent. Two Google-documented timing traps go with it: adding a group as a member
  of another group "may be a delay of up to 10 minutes before the child group's members appear as members of the
  parent group," and the API rejects membership cycles.
- **Listing a user's groups is a different call shape.** `groups.list` takes a `userKey` to return only the groups a
  given user belongs to, and Google notes it **"Cannot be used with the `customer` parameter."** Per-user group
  resolution over a large directory is therefore one call per user, which is where an initial sync meets §7.
- **Org units are a tree with no pagination.** `orgunits.list` takes an `orgUnitPath` and a `type` of `CHILDREN`
  (default), `ALL` or `ALL_INCLUDING_PARENT`, and returns the whole requested set in one response — there is no
  `pageToken` and no `maxResults`. Google's limits page bounds it instead: an OU hierarchy is **limited to 35 levels
  of depth** and **40,000 org units per customer**, and you cannot create or update **more than one OU per customer
  per second**.

## 6. There is no delta: how freshness actually works

`users.list` has no `syncToken`, no `updatedMin` and no change-feed parameter — its documented parameters are
`customer`/`domain`, `query`, `projection`, `customFieldMask`, `showDeleted`, `viewType`, `orderBy`, `sortOrder`,
`maxResults`, `pageToken` and `event`. So an integration that wants "what changed since yesterday" has three honest
options, and each has a documented catch:

1. **Full re-list and diff.** Simple, correct, and bounded by §7's page-size caps and rate limits. Note that
   **`pageToken` is only valid for three days**, so a paused long sync cannot be resumed later from a stored token.
2. **Search-based filtering.** `users.list` accepts a `query` with clauses over name, email, org fields, manager,
   `orgUnitPath`, `isSuspended`, `isArchived` and custom indexed attributes — but the documented field list has **no
   created-at or updated-at field**, so there is no timestamp predicate to filter on. It also carries a freshness
   warning: "Most user data updates within 1 hour; however, it may take up to 36 hours for new data to be reflected
   in all search results." A sync that trusts search results to be current will drop recent changes.
3. **Push notifications, for users only.** `users.watch` opens a channel for one `event` at a time — `add`, `update`,
   `delete`, `makeAdmin` or `undelete` — against a `domain` or a `customer`, posting to an HTTPS `address` with a
   valid certificate (Google explicitly rejects self-signed, untrusted, revoked and mismatched certificates). The
   channel takes a caller-generated `id` (max 64 characters), an optional `token` echoed back in a header for
   spoof-checking — Google says "Don't include sensitive data such as OAuth tokens" in it — and an optional `ttl` or
   `expiration`. **Channels expire and must be renewed**, and they are stopped through the channels-stop method
   rather than by deleting anything. There is **no equivalent for groups, members or org units**: those are polling,
   always.

Two staleness facts that ruin naive change detection: Google warns that **"when retrieving all users in a domain, the
value of `lastLoginTime` might be inaccurate"** and to fetch a single user for an accurate value; and renaming a user
"can take up to 10 minutes to propagate across all services," with the old username retained as an alias. Anything
keyed on email address rather than the immutable user ID will double-count across a rename — Google's own advice is
"we also recommend not using the user email address as a key for persistent data because the email address is subject
to change."

## 7. Quotas and hard limits

Directory's rate-limit story is its own, and one half of it cannot be bought out of:

| Code | Reason | What it is |
| --- | --- | --- |
| `403` | `userRateLimitExceeded` | Per-user, per-Cloud-project. **Default 2,400 queries per minute**, and raisable from the Admin SDK API quotas page of your Cloud project. |
| `403` | `quotaExceeded` | Concurrent-request limit for an operation. Back off. |
| `429` | `rateLimitExceeded` | Concurrency limit **per Google Workspace account, not per API client or per user — and Google states this limit "can't be increased."** |

That last row is the one to design around: a busy customer can throttle every integration they use at once, including
yours, and no amount of quota paperwork on your side changes it. Google's documented remedy is truncated exponential
backoff with jitter, terminating after five retries at roughly 32 seconds of total delay. (The base skill's symptom
table covers how to read a `403` that is really flow control.)

Hard limits worth knowing before promising a sync window:

- **Page sizes** (§ platform state): users max 500 per page, groups and members 200, devices 100; aliases and org
  units do not paginate.
- **`members.list` "times out after 60 minutes."** A pathologically large group is a real failure mode.
- **Provisioning throughput**: no more than **10 users per domain per second**, and **one OU create/update per
  customer per second**.
- **Account shape**: up to **600 domains** per account (1 primary + 599 additional), **30 aliases per user**, **20
  domain aliases**, group descriptions capped at 4,096 characters, and **20 users moved between OUs at a time**.
- **Billing**: Google notes that on a flexible plan, creating users through this API "will have monetary impact" for
  the customer. A provisioning bug is a customer invoice, not just a data problem.

## Product fact — what the Workspace Directory connector asks for

> **As of 2026-09-20, Unified.to's Google Workspace Directory connector requests**, per capability and direction —
> every configuration on top of `openid`, `profile`, `email`, `https://www.googleapis.com/auth/userinfo.email` and
> `https://www.googleapis.com/auth/userinfo.profile`, which are also the login-only set:
>
> - **Employee read:** `https://www.googleapis.com/auth/admin.directory.user.readonly`
> - **Employee write:** `https://www.googleapis.com/auth/admin.directory.user`
> - **Group read:** `https://www.googleapis.com/auth/admin.directory.group.readonly` and
>   `https://www.googleapis.com/auth/admin.directory.group.member.readonly`
> - **Group write:** `https://www.googleapis.com/auth/admin.directory.group` and
>   `https://www.googleapis.com/auth/admin.directory.group.member`
>
> **No org-unit, custom-schema, alias, customer, domain, device or role-management scope is requested**, so those
> areas of the directory are out of reach for this connector as configured — relevant if a customer asks for an org
> chart or custom HR fields.
>
> **The connector reads with the account-wide, administrator-facing shape**: requests are scoped with
> `customer=my_customer`, the full user projection, and the administrator view. Per §3 and §5, that means **an
> ordinary employee cannot connect it** even though consent will succeed, and the lighter domain-public path in §3 is
> not what this connector uses. Put "connect as a Workspace administrator" in the customer-facing instructions.
>
> Other behaviour worth carrying into a handoff: employee change events are delivered through Google's Users push
> channel (created / updated / deleted), which per §6 expires and must be renewed and has no group equivalent — group
> membership is read per group on demand instead. Listing is cursor-paged with a **page size capped at 200**, which is
> right for groups and members and leaves headroom unused for users (§7). The authorize request carries `access_type`
> and `prompt`, so the base skill's refresh-token conditions are wired in and should be verified rather than assumed,
> and quota-flavoured `403` responses are remapped to `429` so reads back off instead of being read as auth failures.
> The connector also supports a **Google service-account credential** minting the user, group and group-member
> scopes — that is the domain-wide delegation path in §4, and it needs each customer's super admin. Separately, the
> connector carries Google's SAML single-sign-on setup path; that is an Admin-console configuration and has nothing to
> do with this OAuth client.
>
> Scope sets change. This note is dated, not live — **confirm the current set with the connector's owner** before
> declaring scopes, writing customer instructions or submitting anything for review.

## 8. Directory-specific end-to-end checks

On top of the base skill's authorize → refresh round trip:

1. **Enable the Directory API on the project**, then make one real `users.list` call — a client that authorizes
   cleanly against a project without the API fails at the first call with an enablement error.
2. **Authorize once as a super admin, once as a delegated admin holding only the privilege you claim to need, and
   once as an ordinary employee.** The third is not a negative test you can skip: it is the experience some fraction
   of your customers will have, and you need to know exactly what it looks like to write the error message.
3. **Test against a multi-domain customer, or at least prove the call uses `customer` and not `domain`** (§5). A
   single-domain test account hides this defect completely.
4. **Test a group containing a nested group**, with and without `includeDerivedMembership`, and confirm the product's
   member list is what it claims to be (§5).
5. **Page past the caps**: more than 500 users, more than 200 members. Confirm the client follows `nextPageToken` and
   does not assume one page.
6. If change detection is a feature, open a `users.watch` channel, confirm the callback receives a notification,
   confirm the channel is **renewed before expiry**, and confirm it is stopped on disconnect. Then confirm what
   happens for groups — which is polling (§6).
7. If the product provisions, confirm on a throwaway account that the write privilege is checked separately from the
   read one, and that the flexible-plan billing note in §7 has been surfaced to whoever owns the customer
   relationship.
8. Inspect the granted `scope` against what was requested; a granular-consent screen lets an admin drop, say, the
   member scope, and the failure then appears later as an empty group rather than as a consent error.

| Symptom | Cause |
| --- | --- |
| Consent succeeds, first directory call returns `403` | The consenting user has no admin privilege, or the request uses the admin view for a non-admin (§3) |
| `403` for one customer only, everyone else fine | That customer disabled Admin SDK API access, or the base skill's Workspace app-access controls block the client |
| Every call fails immediately after a clean registration | Directory API not enabled on the Cloud project (§3) |
| Sync returns only some of a customer's people | `domain` used where `customer` was needed on a multi-domain account (§5) |
| Members of a group are missing | Nested-group membership without `includeDerivedMembership`, or within the 10-minute propagation delay (§5) |
| A new user does not appear in search for hours | Search index lag — up to 36 hours for new data to reach all search results (§6) |
| "Last updated" never changes, or changes at random | There is no updated-at field; `lastLoginTime` is documented as possibly inaccurate on a list (§6) |
| A renamed user appears twice | Keyed on email rather than the immutable user ID; the old address survives as an alias (§6) |
| A long sync cannot be resumed the next week | `pageToken` is valid for three days (§6, platform state) |
| `429` that no quota increase fixes | The per-Workspace-account concurrency limit, which Google says cannot be increased (§7) |
| Delegation saved by the customer but calls still fail | Domain-wide delegation changes can take up to 24 hours, or a second super admin's approval is pending (§4) |
| Nothing works for a `@gmail.com` account | Expected — the Admin SDK has no consumer equivalent (lede) |

## Stop and ask

Beyond the base skill's list:

- **Nobody has confirmed that a Workspace administrator will be the one connecting.** That is the whole feasibility
  question; do not register scopes against an assumption about it.
- The plan requires **domain-wide delegation** and nobody has confirmed that customers' super admins will do it, or
  that the scope list is final — changing it later means going back to every customer (§4).
- Someone proposes **write scopes** without a named owner for what happens when the connector suspends, renames or
  deletes the wrong account — this API provisions real identities, and on a flexible plan it also bills (§7).
- Someone proposes `cloud-platform` because a method's scope list accepts it (§ platform state). That is a
  project-wide Cloud scope standing in for a directory read; it is a security conversation, not a shortcut.
- The product needs org units, custom schemas, aliases, devices or role management and the declared scope set does
  not include them — adding one later re-consents every customer.
- A customer's security review asks for **per-OU or per-group restriction of the token**. There is no such scope; the
  narrowing is the admin role they assign (§2, §3), and that answer has to come from you, accurately.
- The scope family, the page-size caps or the privilege model do not match the **Directory platform state** section
  above.

## References

Directory-specific only; the base skill carries the generic Google OAuth, verification and Workspace-admin-control
references. Verified to resolve on 2026-09-20.

- Directory API overview (Admin SDK framing; customer, domain, OU, privilege, role vocabulary) — https://developers.google.com/workspace/admin/directory/v1/guides
- Choose Directory API scopes (the full `admin.directory.*` family, with no tier labels) — https://developers.google.com/workspace/admin/directory/v1/guides/authorizing
- Prerequisites (delegated administrators and resellers; device-operation exceptions) — https://developers.google.com/workspace/admin/directory/v1/guides/prerequisites
- Directory API Python quickstart (the Workspace-domain and administrator-privileges prerequisites) — https://developers.google.com/workspace/admin/directory/v1/quickstart/python
- Manage user accounts (`my_customer`, `viewType=domain_public` for non-admins, `makeAdmin` is super-admin only, rename propagation, `lastLoginTime` accuracy) — https://developers.google.com/workspace/admin/directory/v1/guides/manage-users
- Search for users (query fields and operators; no timestamp field; the 1-hour / 36-hour index lag) — https://developers.google.com/workspace/admin/directory/v1/guides/search-users
- Manage groups — https://developers.google.com/workspace/admin/directory/v1/guides/manage-groups
- Search for groups — https://developers.google.com/workspace/admin/directory/v1/guides/search-groups
- Manage group members (a member can be a user or a group; nested-membership delay; cycles rejected) — https://developers.google.com/workspace/admin/directory/v1/guides/manage-group-members
- Manage organizational units — https://developers.google.com/workspace/admin/directory/v1/guides/manage-org-units
- Push notifications (channel setup, HTTPS certificate rules, `token` guidance, Users resource only) — https://developers.google.com/workspace/admin/directory/v1/guides/push
- Directory API limits and quotas (403/429 reasons, the uncappable per-account limit, page-size caps, OU and provisioning limits, flexible-plan billing) — https://developers.google.com/workspace/admin/directory/v1/limits
- `users.list` reference (parameters — note the absence of any sync token; three-day `pageToken`; scopes) — https://developers.google.com/workspace/admin/directory/reference/rest/v1/users/list
- `users.watch` reference (event enum, `viewType`, scopes) — https://developers.google.com/workspace/admin/directory/reference/rest/v1/users/watch
- `Users` resource reference — https://developers.google.com/workspace/admin/directory/reference/rest/v1/users
- `groups.list` reference (`customer` vs `domain`, `userKey` exclusivity, 200-result cap, scopes) — https://developers.google.com/workspace/admin/directory/reference/rest/v1/groups/list
- `members.list` reference (`includeDerivedMembership`, 200-result cap, 60-minute timeout, scopes) — https://developers.google.com/workspace/admin/directory/reference/rest/v1/members/list
- `orgunits.list` reference (no pagination; `CHILDREN` / `ALL` / `ALL_INCLUDING_PARENT`) — https://developers.google.com/workspace/admin/directory/reference/rest/v1/orgunits/list
- `channels.stop` reference (closing a push channel) — https://developers.google.com/workspace/admin/directory/reference/rest/v1/channels/stop
- Troubleshoot Directory API issues (the documented 403 reasons, and `customer` vs `domain` guidance) — https://developers.google.com/admin-sdk/reseller/v1/support/directory_api_common_errors
- Troubleshoot Directory authentication and authorization — https://developers.google.com/workspace/admin/directory/v1/guides/troubleshoot-authentication-authorization
- Control API access with domain-wide delegation (super admin only, console path, client ID + scopes, 24-hour propagation, multi-party approval) — https://knowledge.workspace.google.com/admin/apps/control-api-access-with-domain-wide-delegation
- Prebuilt administrator roles (which roles work through the Admin API) — https://knowledge.workspace.google.com/admin/users/prebuilt-administrator-roles
- Administrator privilege definitions (Users and Organizational Units privileges grant Directory API permissions) — https://knowledge.workspace.google.com/admin/users/administrator-privilege-definitions
- Create access credentials, including the service-account and delegation path — https://developers.google.com/workspace/guides/create-credentials
- Using OAuth 2.0 for server-to-server applications (service accounts and delegated authority) — https://developers.google.com/identity/protocols/oauth2/service-account
