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:
- Initiating the OAuth redirect during pre-collection
- Exchanging the auth code for tokens
- 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 creationToken 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
| Field | Type | Required | Description |
|---|---|---|---|
provider | object | Yes | OAuth provider configuration. |
provider.auth_url | string | Yes | Provider's authorization endpoint (HTTPS). |
provider.token_url | string | Yes | Provider's token exchange endpoint (HTTPS). |
provider.scopes | string[] | Yes | OAuth scopes to request (at least 1). |