Skip to content

OAuth Basics

OAuth allows your agent to access user data from services like Gmail, GitHub, and Notion without handling passwords.

How It Works

  1. User clicks "Connect" in PIE
  2. PIE redirects to the service (e.g., Google)
  3. User authorizes your agent
  4. Service redirects back to PIE with a code
  5. PIE exchanges code for tokens
  6. PIE stores tokens securely (encrypted)
  7. Your agent can now make authenticated requests
┌──────┐     ┌─────┐     ┌─────────┐
│ User │────▶│ PIE │────▶│ Google  │
└──────┘     └─────┘     └─────────┘
   │            │             │
   │  Click     │  Redirect   │
   │  Connect   │  to OAuth   │
   │            │             │
   │            │◀────────────│
   │            │  Auth code  │
   │            │             │
   │            │────────────▶│
   │            │  Exchange   │
   │            │  for tokens │
   │            │             │
   │            │◀────────────│
   │            │  Tokens     │
   │            │  (stored)   │
   │            │             │
   │  Ready!    │             │
   └────────────┘             │

Setting Up OAuth

1. Create OAuth App

Register your app with the service:

ServiceDeveloper Console
GoogleCloud Console
GitHubDeveloper Settings
NotionIntegrations
SlackAPI Apps

2. Configure Redirect URI

Set the callback URL in your OAuth app settings:

https://your-pie-domain.com/api/oauth/plugin/{pluginId}/callback

3. Add OAuth Config to Manifest

For built-in providers:

json
{
  "oauth": {
    "provider": "google",
    "scopes": ["https://www.googleapis.com/auth/gmail.readonly"],
    "clientIdSecret": "GOOGLE_CLIENT_ID",
    "clientSecretSecret": "GOOGLE_CLIENT_SECRET"
  }
}

For custom providers:

json
{
  "oauth": {
    "provider": "custom",
    "providerName": "Notion",
    "authorizationUrl": "https://api.notion.com/v1/oauth/authorize",
    "tokenUrl": "https://api.notion.com/v1/oauth/token",
    "scopes": [],
    "clientIdSecret": "NOTION_CLIENT_ID",
    "clientSecretSecret": "NOTION_CLIENT_SECRET"
  }
}

4. Store Credentials

Add your OAuth credentials as developer secrets:

json
{
  "developerSecrets": {
    "GOOGLE_CLIENT_ID": {
      "description": "Google OAuth Client ID",
      "required": true
    },
    "GOOGLE_CLIENT_SECRET": {
      "description": "Google OAuth Client Secret",
      "required": true
    }
  }
}

Using OAuth in Code

Check Connection

Always check if the user has connected:

js
async function handler(input, context) {
  const isConnected = await context.oauth.isConnected();
  
  if (!isConnected) {
    return {
      error: true,
      message: 'Please connect the service first',
      requiresAuth: true,
    };
  }
  
  // Continue with authenticated requests...
}

Make Authenticated Requests

Use context.oauth.fetch() instead of context.fetch():

js
// PIE automatically adds: Authorization: Bearer {token}
const response = await context.oauth.fetch(
  'https://api.example.com/data'
);

The token is never visible to your code. PIE injects it automatically.

Full Example

js
async function handler(input, context) {
  // Check connection
  if (!await context.oauth.isConnected()) {
    return { error: true, requiresAuth: true };
  }
  
  // Make authenticated request
  const response = await context.oauth.fetch(
    'https://api.github.com/user/repos',
    {
      headers: { 'Accept': 'application/vnd.github.v3+json' }
    }
  );
  
  if (!response.ok) {
    return { error: true, message: `API error: ${response.status}` };
  }
  
  const repos = JSON.parse(response.body);
  return { repos: repos.map(r => r.name) };
}

Token Refresh

PIE handles token refresh automatically:

  1. Before making a request, PIE checks if token is expired
  2. If expired (or expiring soon), PIE uses refresh token
  3. New access token is stored
  4. Request proceeds with valid token

You don't need to handle this in your code.

Scopes

Scopes define what your agent can access:

json
{
  "oauth": {
    "scopes": [
      "https://www.googleapis.com/auth/gmail.readonly",
      "https://www.googleapis.com/auth/gmail.send"
    ]
  }
}

Best practice: Request minimal scopes. Only ask for what you need.

Security

Token Isolation

OAuth tokens are never exposed to your agent code:

  • context.oauth.fetch() - PIE adds the token
  • Tokens are encrypted at rest (AES-256-GCM)
  • Tokens are scoped to the agent that created them

User Control

Users can disconnect at any time:

  • Tokens are deleted from PIE
  • Revocation request sent to provider (if supported)
  • Agent loses access

Common Issues

"Not Connected" Error

The user hasn't authorized yet. Return requiresAuth: true:

js
return { error: true, requiresAuth: true };

Token Expired

PIE auto-refreshes, but if refresh fails:

  • User needs to reconnect
  • Check if refresh token was revoked

Wrong Scopes

If you get 403 errors, you may need additional scopes:

  • Update manifest with required scopes
  • Users need to reconnect to grant new scopes

Built with VitePress