Google Workspace
Pulls Admin SDK directory data and Reports API audit events from Google Workspace, deriving KRIs for 2SV enrollment, super-admin sprawl, OAuth-app scope risk, and Drive external-share anomalies.
At a glance
| Vendor | Google Workspace |
|---|---|
| Source type | google_workspace |
| Vendor ID (slug) | google-workspace |
| Base URL | https://admin.googleapis.com — fixed for every Workspace tenant |
| Auth method | oauth2 — Authorization: Bearer <access_token> minted per run from a domain-wide-delegated service account JWT |
| Schedule default | daily |
| Availability | Stable — presentation refreshed 2026-04-18. |
Required scopes & roles
Draxis authenticates as a GCP service account with domain-wide delegation, impersonating a read-only Workspace admin. The service account needs exactly these three read-only OAuth scopes — nothing more:
https://www.googleapis.com/auth/admin.directory.user.readonly— list users, 2SV enrollment state, admin flags, suspended/archived state. Backs the/admin/directory/v1/userscall.https://www.googleapis.com/auth/admin.reports.audit.readonly— read Admin, Token, and Drive audit logs. Backs the/admin/reports/v1/activity/users/all/applications/{admin,token,drive}calls.https://www.googleapis.com/auth/admin.reports.usage.readonly— reserved for future usage-based KRIs; included now so you don’t need a second consent pass later.
On the Workspace side, the impersonated subject must be a user with a role that can read those APIs. The Google-provided “Services admin” predefined role works; for tighter least-privilege, create a custom admin role that grants only Admin API Privileges → Users → Read and Reports.
Do not grant the service account the Super Admin role — none of these scopes require it, and it would also grant write access.
Setup steps
- Create a GCP project and service account. In the Google Cloud Console, pick (or create) a project dedicated to third-party integrations, then go to IAM & Admin → Service Accounts → Create Service Account. Name it
draxis-workspace-reader. Skip the “Grant this service account access to project” step — it needs zero GCP IAM roles. - Enable the Admin SDK API on the project. APIs & Services → Library → Admin SDK API → Enable.
- Generate a JSON key. On the service account’s Keys tab, Add Key → Create new key → JSON. Save the file — you’ll paste the entire contents into Draxis in the final step. Treat it like a password.
- Enable domain-wide delegation. On the service account’s Details page, copy its Unique ID (OAuth 2.0 Client ID) — a numeric string. You’ll paste it in the next step.
- Authorize the scopes in the Workspace Admin Console. Go to admin.google.com → Security → Access and data control → API controls → Manage Domain Wide Delegation → Add new. Paste the numeric Client ID from step 4, then paste these three scopes (comma-separated):
Click Authorize.https://www.googleapis.com/auth/admin.directory.user.readonly,https://www.googleapis.com/auth/admin.reports.audit.readonly,https://www.googleapis.com/auth/admin.reports.usage.readonly - Pick (or create) a read-only admin user to impersonate. In the Admin Console, Directory → Users → Add new user, e.g.
draxis-reader@your-domain.com. Assign it the Services admin role (or the custom read-only role described above). This is the email you’ll put in the Draxis Client ID field — Draxis impersonates this user when calling Google. - Verify the customer ID (optional). Most tenants can leave
customer_idasmy_customer. If you’re a Workspace reseller or manage multiple customers, find the real customer ID under Account → Account settings and put it in the Draxis Extra Config JSON as{"customer_id":"C01xxxxxx"}.
Wire it into Draxis
- Open Settings → Integrations in your tenant.
- Click Add integration and pick Google Workspace as the source type.
- The vendor dropdown auto-selects Google Workspace (Admin SDK + Reports), and Draxis auto-fills the base URL, the OAuth auth method, the daily schedule, and seeds
extra_config_jsonwith{"customer_id":"my_customer"}. - In Client ID, paste the admin email from step 6 above (e.g.
draxis-reader@your-domain.com). This is the user Draxis impersonates — not the service-account numeric ID. - In Client Secret, paste the entire contents of the JSON key file from step 3 — every character including the enclosing
{ … }. Draxis encrypts it server-side withencryption.keybefore storage. - Click Test. Green means Draxis minted a JWT, exchanged it for an access token, and hit the Directory API successfully.
- Under KRIs to import, tick the KRIs you want Draxis to manage. All seven
gws_*KRIs are checked by default; uncheck any you don’t need. Selected rows are created on save with the seeded thresholds (tunable later in the KRIs tab). Unchecking a previously-imported KRI deletes it on save. - Save. The connector runs
dailyby default; use Run now from run history to trigger the first sync immediately.
KRIs produced
| Slug | Meaning | Derivation |
|---|---|---|
gws_2sv_enrollment_pct |
% of active users enrolled in 2-Step Verification | round(count(active[].isEnrolledIn2Sv) / count(active), 1) where active = users[!suspended && !archived] |
gws_super_admin_count |
Count of users flagged isAdmin=true in the Directory API |
count(users[].isAdmin == true) |
gws_ext_shared_sensitive_files |
Drive ACL changes that set visibility to an external audience, last 7 days | count(drive_events where name in (change_user_access, change_acl_editors, change_document_visibility) and visibility in (people_with_link, public_on_the_web, public_in_the_domain_with_link, shared_externally)) |
gws_oauth_high_risk_apps |
Distinct OAuth client_ids authorized with high-risk scopes in the last 7 days |
distinct(token_events[authorize].client_id where any(scope matches mail.google.com | gmail.send|modify|insert | drive | admin.directory | admin.reports | cloud-platform | cloud_search)) |
gws_suspended_active_ratio_pct |
Suspended users as a % of active users | round(count(suspended) / count(active) * 100, 1) |
gws_admin_audit_anomalies_7d |
Count of privileged admin events in the last 7 days | count(admin_events where name or type in (ASSIGN_ROLE, UNASSIGN_ROLE, CREATE_ROLE, DELETE_ROLE, UPDATE_ROLE, DELEGATED_ADMIN_SETTINGS, GRANT_ADMIN_PRIVILEGE, REVOKE_ADMIN_PRIVILEGE, TOGGLE_2SV_ENFORCEMENT, CHANGE_ALLOWED_TWO_STEP_VERIFICATION_METHODS, SSO_PROFILE_CREATED, SSO_PROFILE_DELETED)) |
gws_dlp_violations_7d |
Count of Drive DLP rule-violation events in the last 7 days | count(drive_events where name startsWith 'dlp_' or type contains 'dlp') |
Each row is a slug the connector writes to. Draxis creates the matching kri rows automatically when you check them in the KRIs to import section of the integration form — no manual API call or seed script needed. Thresholds shown in the table are the seeded defaults; you can edit them freely in the KRIs tab afterwards.
Vendor quirks
- Domain-wide delegation is mandatory. Without it the JWT-bearer token exchange returns
unauthorized_client. The scope list in Workspace must match exactly — a typo in one scope silently blocks access to that API. - Service-account impersonation is how Google Workspace does least-privilege. The service account itself has no powers; the impersonated subject’s Workspace role is what actually gates access. Keep that subject on a read-only custom role if you want the strictest least-privilege posture.
- Reports API has a ~20-minute lag. Events appearing in the Admin Console may take up to ~20 minutes to surface through
/admin/reports/v1/activity. Draxis’s 7-day window always trails real time, so this is invisible in practice. customer_id=my_customerworks for almost everyone. Only resellers or multi-customer setups need the real numeric customer ID. If Test returns HTTP 400 with “Invalid Input: customer”, replace it with your real ID from the Admin Console’s account settings.- Pagination is capped at 200 pages per endpoint. At 500 users/page that’s 100k users; at default Reports page sizes it’s well past any 7-day window we’ve seen. Very large tenants that hit the cap should open a support request — we’ll tune the window or paginate in chunks.
- Service-account JSON keys are credentials. If a key is ever exposed, revoke it in the GCP console (Keys → Delete) and generate a new one — the old key stops working immediately, so do this only after you’re ready to update Draxis.
Troubleshooting
- HTTP 401
unauthorized_clientat the token exchange — domain-wide delegation isn’t set up, or the scope list in the Workspace Admin Console doesn’t match the three scopes above. Re-check the numeric Client ID and the exact scope strings. - HTTP 403 on Directory or Reports calls — the impersonated user’s Workspace role is too narrow. Grant them Services admin (or add Users → Read and Reports privileges to your custom role).
- HTTP 400 “Invalid Input: customer” — you’re a reseller or multi-customer tenant and
my_customerdoesn’t resolve. Replace thecustomer_idin Extra Config with the real customer ID. - “Client Secret is not valid JSON” on Test — you pasted something other than the full service-account key file. Paste the entire JSON including the outer braces.
rowsSkipped > 0androwsWritten = 0— your tenant hasn’t imported any KRIs for this integration yet. Open the integration in Settings → Integrations, tick the KRIs under KRIs to import, and save.- Still stuck? Open a support ticket with the run ID (from Run history) and we’ll dig in.