# 37 Continuous OAuth re-authorization sweeps

> v0.1.2 · role: Detect · [policy: #29 · #19, #33](https://docs.google.com/spreadsheets/d/1nOztaPd1Y7eNeRSR_hdovYy-ncpx-bAx/edit?usp=sharing&ouid=115159875779023172526&rtpof=true&sd=true)

A scheduled sweep that snapshots every live OAuth grant in the tenant, diffs it against the approved-app register, sets the access decision in the console for anything unapproved so the grant cannot simply be re-issued, and then revokes it per user. It catches the app a user consented to last week and the malicious client an attacker authorised after a phish — neither of which shows up in any settings screen. The diff is routed to the security mailbox, so the sweep is continuous rather than a one-off.

Documentation: [How authorized access works](https://knowledge.workspace.google.com/admin/apps/how-authorized-access-works) · [OAuth log events](https://knowledge.workspace.google.com/admin/reports/oauth-log-events)

## Caveats

- Revoking a token without blocking the app in API controls is a treadmill — the user re-consents and the grant reappears within days.
- 'Trusted' in API controls means the app gets ALL OAuth scopes, including restricted ones — there is no partial trust unless you configure it scope by scope.
- Internal Apps Script and service-account grants do not always appear as third-party tokens — sweep Apps Script separately (№65) or they slip past the diff.

## Setup steps

1. Snapshot every live OAuth grant in the tenant to a local, dated CSV — the next step diffs it locally, so it must not disappear into Drive.

   ```
   gam all users print tokens > tokens-$(date +%F).csv
   ```

   docs: [Method: tokens.list](https://developers.google.com/workspace/admin/directory/reference/rest/v1/tokens/list)

2. Compare the snapshot against the approved-app register; any client id not on the register is a finding.

   comm -13 <(sort apps-register.csv) <(cut -d, -f<clientid-column> tokens-$(date +%F).csv | sort -u)

3. For each unapproved client ID, set its access decision in the console — the app-access list [№8](oauth-app-control.md) maintains — so the grant cannot simply be re-issued after you revoke it. — `Security › Access and data control › API controls › Manage Third-Party App Access`

   - **App access** = Blocked (or Limited to unrestricted Google services)

   docs: [Control which apps access Google Workspace data](https://knowledge.workspace.google.com/admin/apps/control-which-apps-access-google-workspace-data)

4. Revoke the surviving unapproved grants per user.

   ```
   gam user <user> delete token clientid <clientid>
   ```

   docs: [Method: tokens.delete](https://developers.google.com/workspace/admin/directory/reference/rest/v1/tokens/delete) · [Manage a user's security settings](https://knowledge.workspace.google.com/admin/security/manage-a-users-security-settings)

5. Schedule the sweep so it is continuous rather than a one-off, and route diffs to the security mailbox. Optionally, commit each run's output to a private GitHub repo and have a Claude Routine review the diff for suspicious changes — new grants with broad scopes, re-grants of blocked clients — and decide per finding whether to escalate to an admin by email or push notification.

   ```
   cron: daily or weekly; output diffed against apps-register.csv (optionally: git commit + scheduled Claude review of the diff)
   ```

## Ongoing maintenance

- **[automatable: script]** Weekly: run the token snapshot and diff against the approved-app register.
- **[automatable: AI agent]** Weekly: review the diff for new grants with broad scopes or re-grants of blocked clients.
- **[requires a human]** Per finding: decide block/revoke and execute it.

## How to verify

1. Check the newest sweep artifact is within the cadence and the diff was reviewed — then re-run the snapshot and confirm it matches.

   ```
   gam all users print tokens > tokens-verify.csv && diff <(sort tokens-verify.csv) <(sort tokens-<last-date>.csv)
   ```

## Settings screens

- Security > Access and data control > API controls > Manage Third-Party App Access (configured apps)
  - console: https://admin.google.com/ac/owl/list?tab=configuredApps
  - screenshot: ../screenshots/admin.google.com/ac/owl/list__tab-configuredApps.png
- Security > Access and data control > API controls (overview)
  - console: https://admin.google.com/ac/owl
  - screenshot: ../screenshots/admin.google.com/ac/owl.png
- Directory > Users > [user] > Security > Connected applications (per-user token review)
  - console: https://admin.google.com/ac/users
  - screenshot: ../screenshots/admin.google.com/ac/users.png
- Reporting > Audit and investigation > OAuth log events (token grants/revocations)
  - console: https://admin.google.com/ac/sc/investigation
  - screenshot: ../screenshots/admin.google.com/ac/sc/investigation.png
