Skip to main content
Service accounts provide non-interactive authentication for server-to-server workflows. Unlike user OAuth credentials, service accounts:
  • Don’t require browser-based login
  • Don’t expire (until the key is rotated)
  • Can use Domain-Wide Delegation to act on behalf of users
  • Are ideal for production automation and CI/CD

When to Use Service Accounts

Use service accounts when:
  • Running automated workflows that access Google Workspace data
  • Building applications that need to access resources across multiple user accounts
  • Deploying to production environments (servers, Kubernetes, Cloud Run)
  • You have a Google Workspace domain with admin access (required for Domain-Wide Delegation)
Use OAuth instead when:
  • Developing locally on your personal machine
  • Accessing only your own Google account
  • You don’t have Google Workspace admin permissions

Setup Overview

1

Create service account

Create a service account in Google Cloud Console and download the key file.
2

Enable Domain-Wide Delegation (optional)

If you need to access other users’ data, enable Domain-Wide Delegation in Google Workspace Admin.
3

Configure gws to use the service account

Point gws to the service account key file via environment variable.

Creating a Service Account

1

Open Google Cloud Console

Navigate to IAM & Admin > Service Accounts:
https://console.cloud.google.com/iam-admin/serviceaccounts?project=YOUR_PROJECT_ID
2

Create service account

  1. Click Create Service Account
  2. Service account name: gws-automation (or your preferred name)
  3. Service account ID: gws-automation (auto-filled)
  4. Description: “Service account for gws CLI automation”
  5. Click Create and Continue
  6. Skip granting roles (click Continue, then Done)
For Workspace APIs, service accounts don’t need IAM roles in the GCP project. Permissions are granted through OAuth scopes and Domain-Wide Delegation.
3

Create and download key

  1. Click on the newly created service account
  2. Go to the Keys tab
  3. Click Add KeyCreate new key
  4. Select JSON format
  5. Click Create
A JSON key file will be downloaded automatically.
The private key cannot be recovered if lost. Store it securely and never commit to version control.
4

Enable required APIs

Enable the Google Workspace APIs you need:
gcloud services enable drive.googleapis.com \
  gmail.googleapis.com \
  calendar-json.googleapis.com \
  sheets.googleapis.com \
  --project=YOUR_PROJECT_ID
Or enable via API Library.

Using the Service Account

Basic Usage (No Domain-Wide Delegation)

For APIs that don’t require user impersonation (e.g., accessing the service account’s own Drive):
export GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/path/to/service-account.json
gws drive files list
The service account JSON file looks like:
{
  "type": "service_account",
  "project_id": "your-project-id",
  "private_key_id": "abc123...",
  "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
  "client_email": "gws-automation@your-project.iam.gserviceaccount.com",
  "client_id": "123456789",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/..."
}
gws automatically detects service account credentials by the "type": "service_account" field.

With Domain-Wide Delegation (Impersonation)

To access another user’s data (e.g., read their Gmail, Drive files), you must:
  1. Enable Domain-Wide Delegation for the service account
  2. Grant OAuth scopes in Google Workspace Admin Console
  3. Set the GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER environment variable

Enabling Domain-Wide Delegation

Domain-Wide Delegation requires Google Workspace Super Admin permissions. This feature is not available for personal Google accounts.
1

Enable Domain-Wide Delegation in GCP

  1. Go to Service Accounts
  2. Click on your service account
  3. Click Show advanced settings
  4. Under Domain-wide delegation, click Enable Google Workspace Domain-wide Delegation
  5. Product name for consent screen: gws CLI
  6. Click Save
Copy the Client ID (a long numeric string). You’ll need it in the next step.
2

Grant API scopes in Workspace Admin

  1. Open Google Workspace Admin Console
  2. Navigate to SecurityAccess and data controlAPI controls
  3. Click Manage Domain Wide Delegation
  4. Click Add new
  5. Client ID: Paste the service account’s Client ID from step 1
  6. OAuth scopes: Enter the scopes your automation needs (comma-separated):
https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/gmail.modify,https://www.googleapis.com/auth/calendar
  1. Click Authorize
3

Test with impersonation

Set the user to impersonate:
export GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/path/to/service-account.json
export GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER=user@example.com

gws drive files list
This command will list Drive files as if you were user@example.com.

Common OAuth Scopes for Domain-Wide Delegation

ServiceScope
Google Drive (read/write)https://www.googleapis.com/auth/drive
Google Drive (read-only)https://www.googleapis.com/auth/drive.readonly
Gmail (read/write)https://www.googleapis.com/auth/gmail.modify
Gmail (read-only)https://www.googleapis.com/auth/gmail.readonly
Google Calendarhttps://www.googleapis.com/auth/calendar
Google Sheetshttps://www.googleapis.com/auth/spreadsheets
Google Docshttps://www.googleapis.com/auth/documents
Google Slideshttps://www.googleapis.com/auth/presentations
You must list all scopes your automation will use in the Workspace Admin Console. Service accounts cannot request additional scopes at runtime.

CI/CD Integration

GitHub Actions

name: Service Account Automation

on:
  schedule:
    - cron: '0 9 * * 1'  # Every Monday at 9 AM

jobs:
  workspace-sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install gws
        run: npm install -g @googleworkspace/cli
      
      - name: Set up service account credentials
        run: |
          echo '${{ secrets.GWS_SERVICE_ACCOUNT }}' > /tmp/sa-key.json
      
      - name: Run automation as user
        env:
          GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE: /tmp/sa-key.json
          GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER: admin@example.com
        run: |
          gws drive files list --params '{"pageSize": 100}'
To set the secret:
  1. Go to repo Settings → Secrets → Actions
  2. Add GWS_SERVICE_ACCOUNT
  3. Paste the entire contents of the service account JSON file

Docker

FROM node:20-alpine

RUN npm install -g @googleworkspace/cli

COPY service-account.json /app/service-account.json

ENV GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE=/app/service-account.json
ENV GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER=admin@example.com

CMD ["gws", "drive", "files", "list"]
Build and run:
docker build -t gws-automation .
docker run gws-automation

Kubernetes Secret

apiVersion: v1
kind: Secret
metadata:
  name: gws-service-account
type: Opaque
stringData:
  key.json: |
    {
      "type": "service_account",
      "project_id": "your-project",
      ...
    }
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: workspace-sync
spec:
  schedule: "0 9 * * 1"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: gws
            image: node:20-alpine
            command: ["/bin/sh", "-c"]
            args:
              - |
                npm install -g @googleworkspace/cli
                gws drive files list --params '{"pageSize": 100}'
            env:
            - name: GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE
              value: /secrets/key.json
            - name: GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER
              value: admin@example.com
            volumeMounts:
            - name: service-account
              mountPath: /secrets
              readOnly: true
          volumes:
          - name: service-account
            secret:
              secretName: gws-service-account
          restartPolicy: OnFailure

Environment Variables Reference

VariableDescriptionExample
GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILEPath to service account JSON/app/service-account.json
GOOGLE_WORKSPACE_CLI_IMPERSONATED_USERUser email to impersonate (requires DWD)admin@example.com

Security Best Practices

  • Grant the minimum OAuth scopes required in Workspace Admin
  • Use separate service accounts for different automation workflows
  • Regularly audit service account usage in the Admin Console
  • Never commit service account keys to version control
  • Store keys in encrypted secrets managers (GitHub Secrets, Vault, Cloud Secret Manager)
  • Rotate keys every 90 days
  • Delete unused service account keys immediately
  • Only impersonate the specific users required
  • Avoid impersonating super admin accounts
  • Log all impersonated actions for audit trails
  • Enable audit logging in Google Workspace Admin
  • Set up alerts for unexpected API usage
  • Review service account activity monthly

Troubleshooting

”Subject (user to impersonate) is required” Error

You’re trying to access user data without setting GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER:
export GOOGLE_WORKSPACE_CLI_IMPERSONATED_USER=user@example.com

“Not authorized to access this resource” Error

Possible causes:
  1. Domain-Wide Delegation not enabled: Follow steps in “Enabling Domain-Wide Delegation”
  2. Scopes not granted in Workspace Admin: Verify scopes in Admin Console → Security → API Controls → Domain Wide Delegation
  3. Wrong Client ID: Ensure you used the service account’s Client ID (not the numeric User ID)
  4. API not enabled: Enable required APIs in GCP Console

”Invalid JWT Signature” Error

The service account key file is corrupted or invalid:
  • Re-download the JSON key from GCP Console
  • Verify the file contains -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY-----
  • Check that the file wasn’t modified (no extra whitespace, encoding issues)

Credential Precedence

When both user OAuth and service account credentials are available:
  1. GOOGLE_WORKSPACE_CLI_TOKEN (pre-obtained access token, highest priority)
  2. GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE (can be user OAuth or service account)
  3. Encrypted user credentials (~/.config/gws/credentials.enc)
  4. Plaintext user credentials (~/.config/gws/credentials.json)
gws detects service account vs user OAuth by inspecting the "type" field in the JSON file.

Comparison: Service Accounts vs User OAuth

FeatureService AccountUser OAuth
Setup complexityHigh (requires Workspace admin)Low (just gws auth login)
Requires browserNoYes (for initial setup)
Credential lifetimeUntil key is rotatedUntil refresh token revoked
Access multiple usersYes (with DWD)No (only authenticated user)
Works in CI/CDYesYes (after export)
Audit trailService account nameUser email
Best forProduction automationLocal development

Next Steps

Headless/CI Auth

Learn about user OAuth credentials in CI/CD

Interactive Auth

Set up OAuth for local development