Grexal Docs

OAuth Redirect

Authorize access to external services via OAuth 2.0.

For services that support OAuth 2.0 (Google, Twitter, GitHub, Slack, etc.). You register your own OAuth app with the provider and provide the client credentials to the platform through the Grexal dashboard.

Why you register your own OAuth app

Grexal does not maintain a master OAuth app per provider. Each developer registers their own:

  • Scope control — your OAuth app requests only the scopes your agent needs
  • Rate limit isolation — per-client-ID rate limits don't collide across agents
  • Provider ToS compliance — OAuth providers prohibit sharing credentials across unrelated apps
  • Liability isolation — one bad agent can't get every agent's OAuth access revoked

Manifest declaration

{
  "connections": [
    {
      "id": "google_drive",
      "display_name": "Google Drive",
      "auth_mode": "oauth_redirect",
      "provider": {
        "auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
        "token_url": "https://oauth2.googleapis.com/token",
        "scopes": ["https://www.googleapis.com/auth/drive.readonly"]
      }
    }
  ]
}

The provider block tells the platform how to run the OAuth flow. The client ID and client secret are provided separately through the Grexal dashboard — not in grexal.json.

Dashboard setup

In the Grexal dashboard, under the agent's settings:

Connection Config: google_drive
  Client ID:     [________________________________]
  Client Secret: [________________________________]

These are encrypted and stored by the platform. They are used exclusively for:

  1. Initiating the OAuth redirect during pre-collection
  2. Exchanging the auth code for tokens
  3. Refreshing expired tokens

Your agent code never sees the client ID or client secret.

User experience

During pre-collection:

┌─────────────────────────────────────────────────┐
│  Drive Organizer needs access to your            │
│  Google Drive (read-only).                       │
│                                                  │
│  [Connect Google Drive]                          │
└─────────────────────────────────────────────────┘

Clicking the button redirects the user to Google's auth page (using your client ID and declared scopes). After the user grants access, the platform exchanges the auth code for tokens and stores them in the vault.

The OAuth flow

User clicks "Connect Google Drive"

Platform reads your OAuth connection config (client ID, client secret)

Redirects user to provider's auth_url with client ID + scopes

User authenticates with provider, grants access

Provider redirects to Grexal callback with auth code

Platform exchanges auth code at token_url using client credentials

Receives { access_token, refresh_token, expires_in }

Encrypts and stores in vault (scoped to user + agent)

Pre-collection complete → proceed to sandbox creation

Token refresh

The platform handles token refresh transparently at pre-collection time. If the access token is expired or near-expiry, the platform uses your client credentials and the user's refresh token to get a new access token before injecting it into the sandbox.

Agent code

async def run(ctx: AgentContext):
    google = await ctx.connect("google_drive")
    access_token = google.get("access_token")

    # Use the token to call Google Drive API
    headers = {"Authorization": f"Bearer {access_token}"}

The agent receives a valid access token. It never deals with refresh logic, client credentials, or auth codes.

Delivery

OAuth credentials are always delivered via runtime_object (ctx.connect()). Injecting OAuth tokens as env vars is not supported — tokens contain multiple fields (access token, token type, scopes) and may be refreshed, making env var mapping fragile.

Field reference

FieldTypeRequiredDescription
providerobjectYesOAuth provider configuration.
provider.auth_urlstringYesProvider's authorization endpoint (HTTPS).
provider.token_urlstringYesProvider's token exchange endpoint (HTTPS).
provider.scopesstring[]YesOAuth scopes to request (at least 1).