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.