Guides

Consumer OAuth for Custom MCP Servers

Configure per-user OAuth authentication so your AI agent's end-users can connect their own accounts to third-party services

|View as Markdown
Hunter HodnettCPTO at Chipp
|10 min read

Consumer OAuth allows each end-user of your Chipp app to authenticate with their own account on third-party services. Instead of using a single shared API key, each user connects their personal account (e.g., their Salesforce, HubSpot, or Google account), and the AI agent acts on their behalf.

When to Use Consumer OAuth

<FeatureComparison features={[ { name: "Consumer OAuth (per-user)", description: "Each end-user authenticates with their own account", useCases: [ "Users need to access their personal data", "Actions should be attributed to the specific user", "The third-party service has per-user rate limits", "Users need fine-grained permission control" ], examples: ["Personal CRM data", "User's calendar", "Individual email accounts"] }, { name: "Bearer Token (shared)", description: "All requests use a single app-level token", useCases: [ "Accessing shared company resources", "The service doesn't require user-specific auth", "You want simpler setup" ], examples: ["Company-wide database", "Shared knowledge base", "Internal APIs"] } ]} />

Use Consumer OAuth when:

  • Users need to access their own data (CRM contacts, calendar events, emails)
  • The third-party API requires user-specific authentication
  • You want accountability for which user performed each action
  • The service enforces per-user rate limits or permissions

Use Bearer Token when:

  • Accessing shared company resources that all users can see
  • The MCP server connects to internal APIs you control
  • You want the simplest possible setup

How Consumer OAuth Works

Consumer OAuth Flow

End User
Your Chipp Agent
MCP Server
OAuth Provider
  1. User initiates chat with your Chipp app
  2. AI agent calls a tool that requires user authentication
  3. Chipp detects the user hasn't connected their account
  4. User sees OAuth prompt and clicks to authenticate
  5. Browser opens the third-party's login page
  6. User authorizes your app to access their data
  7. Callback returns with authorization code
  8. Chipp exchanges code for access & refresh tokens
  9. Tokens stored securely per-user in the database
  10. Tool executes with the user's access token

Subsequent requests use the stored tokens. Chipp automatically refreshes expired tokens using the refresh token.


Configuration

Configure Consumer OAuth in the Pro Actions modal when adding a custom MCP server.

Step 1: Create OAuth App on Third-Party Service

First, register an OAuth application with the service you want to integrate (e.g., Salesforce, HubSpot, Google).

You'll need to configure:

SettingValue
Redirect URIhttps://app.chipp.ai/api/chat/mcp/oauth/callback
ScopesRequest the minimum scopes needed for your tools

After registration, you'll receive:

  • Client ID - Public identifier for your OAuth app
  • Client Secret - Private key (keep this secure!)

Step 2: Find OAuth Endpoints

Locate the OAuth 2.0 endpoints in the service's documentation:

EndpointDescriptionExample
Authorize URLWhere users grant permissionhttps://login.salesforce.com/services/oauth2/authorize
Token URLWhere codes are exchanged for tokenshttps://login.salesforce.com/services/oauth2/token

Step 3: Configure in Chipp

  1. Go to your app's Build tab
  2. Open the Pro Actions modal
  3. Click Add Custom MCP Server
  4. Enter your MCP Server URL
  5. Select Consumer OAuth (per-user) as the auth type

Fill in the OAuth configuration:

<FormFields fields={[ { name: "OAuth Client ID", type: "text", required: true, description: "The client ID from your OAuth app registration" }, { name: "OAuth Client Secret", type: "password", required: true, description: "The client secret (stored encrypted)" }, { name: "Authorize URL", type: "url", required: true, description: "The authorization endpoint where users grant permission" }, { name: "Token URL", type: "url", required: true, description: "The token endpoint where codes are exchanged for tokens" }, { name: "Scopes", type: "text", required: false, description: "Space-separated list of OAuth scopes (e.g., 'read write')" }, { name: "Token Request Style", type: "select", required: true, description: "How credentials are sent during token exchange", options: ["form_post", "json_basic", "form_basic"] } ]} />

Step 4: Test the Configuration

Click Test OAuth Configuration to verify your setup works:

  1. A new window opens with the third-party's login page
  2. Log in and authorize the connection
  3. The window closes and shows a success message
  4. If successful, your MCP server's tools are fetched and cached

Test with your own account first. If the OAuth flow completes and tools load successfully, the configuration is correct.


Token Request Styles

Different OAuth providers expect credentials formatted differently during the token exchange. Choose the style that matches your provider:

form_post (Most Common)

Credentials sent as form-encoded body parameters. Try this first.

POST /oauth/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=AUTH_CODE&
client_id=YOUR_CLIENT_ID&
client_secret=YOUR_CLIENT_SECRET&
redirect_uri=https://app.chipp.ai/api/chat/mcp/oauth/callback

Used by: Google, GitHub, LinkedIn, most OAuth providers

json_basic

Credentials sent in HTTP Basic Authorization header, body as JSON.

POST /oauth/token HTTP/1.1
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/json

{
  "grant_type": "authorization_code",
  "code": "AUTH_CODE",
  "redirect_uri": "https://app.chipp.ai/api/chat/mcp/oauth/callback"
}

Used by: Some enterprise APIs, Stripe

form_basic

Credentials in Basic header, body as form-encoded.

POST /oauth/token HTTP/1.1
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=AUTH_CODE&
redirect_uri=https://app.chipp.ai/api/chat/mcp/oauth/callback

Used by: Salesforce, some enterprise OAuth providers

⚠️

If token exchange fails, try a different token style. The error message often doesn't indicate the wrong style was used.


Passing User Tokens to Your MCP Server

When a user has authenticated, Chipp passes their access token to your MCP server in the Authorization header:

POST /mcp HTTP/1.1
Authorization: Bearer USER_ACCESS_TOKEN
Content-Type: application/json

Your MCP server can extract this token and use it for API calls:

// In your MCP server
server.tool(
  "get_my_contacts",
  "Fetch the current user's contacts from Salesforce",
  {},
  async (args, context) => {
    // The user's access token is in the Authorization header
    const userToken = context?.meta?.authorization?.replace("Bearer ", "");

    const response = await fetch("https://your-instance.salesforce.com/services/data/v58.0/sobjects/Contact", {
      headers: {
        "Authorization": `Bearer ${userToken}`
      }
    });

    const contacts = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(contacts, null, 2) }]
    };
  }
);
21 lines

Token Refresh

Access tokens expire. Chipp automatically handles token refresh:

  1. Before each MCP call, Chipp checks if the token is expired (with 5-minute buffer)
  2. If expired and a refresh token exists, Chipp requests a new access token
  3. The new token is stored and used for the request
  4. If refresh fails, the user is prompted to re-authenticate

Your MCP server doesn't need to handle token refresh - Chipp manages it automatically.

💡

Some OAuth providers (like Google) only return a refresh token on the first authorization. If users need to re-authenticate, they may need to revoke access in their account settings first.


User Experience

When a user chats with your app and the AI needs to access a tool requiring Consumer OAuth:

  1. First time: User sees a message prompting them to connect their account
  2. Click to connect: Opens the OAuth provider's login/consent page
  3. Authorize: User grants your app access to their data
  4. Automatic return: Browser closes, chat continues seamlessly
  5. Subsequent chats: No prompts - tokens are reused automatically

What Users See

🔐 This action requires access to your Salesforce account.

[Connect Salesforce Account]

Click above to securely connect. We'll only request access to the
data needed for this app.

After connecting:

✓ Connected to Salesforce as john@example.com

Now fetching your recent contacts...

Security Considerations

Security Checklist

0/6 complete

Troubleshooting

"Invalid redirect_uri" Error

The redirect URI in your OAuth app configuration doesn't match what Chipp sends.

Solution: Ensure your OAuth app's redirect URI is exactly:

https://app.chipp.ai/api/chat/mcp/oauth/callback

"Invalid client" Error

The client ID or secret is incorrect.

Solution: Double-check credentials. Some providers have separate credentials for production vs. sandbox environments.

Token Exchange Fails Silently

The token request style doesn't match what the provider expects.

Solution: Try each token request style (form_post, json_basic, form_basic) until one works.

"Access Denied" During Authorization

User declined the consent prompt, or the requested scopes aren't allowed.

Solution:

  • Check if the user clicked "Deny" instead of "Allow"
  • Verify your OAuth app has access to the requested scopes
  • Some scopes require app review/approval

Refresh Token Missing

The OAuth provider only issues refresh tokens on initial authorization.

Solution:

  • User should revoke access in the provider's settings
  • Re-authorize to get a new refresh token
  • Some providers require adding access_type=offline or prompt=consent to the authorize URL

Tools Don't Load After OAuth

The OAuth succeeded but tools aren't showing.

Solution:

  • Check that your MCP server is running and accessible
  • Verify the server URL is correct
  • Check MCP server logs for errors
  • Ensure the server responds to tools/list correctly

Example: Salesforce Integration

Here's a complete example configuring Consumer OAuth for Salesforce:

1. Create Connected App in Salesforce

  1. Go to SetupAppsApp Manager
  2. Click New Connected App
  3. Configure:
    • Connected App Name: My Chipp Integration
    • API Name: My_Chipp_Integration
    • Enable OAuth Settings:
    • Callback URL: https://app.chipp.ai/api/chat/mcp/oauth/callback
    • Selected OAuth Scopes: api, refresh_token, offline_access
  4. Save and wait for activation (can take 10 minutes)
  5. Copy Consumer Key (Client ID) and Consumer Secret

2. Configure in Chipp

FieldValue
OAuth Client ID3MVG9... (your Consumer Key)
OAuth Client SecretABC123... (your Consumer Secret)
Authorize URLhttps://login.salesforce.com/services/oauth2/authorize
Token URLhttps://login.salesforce.com/services/oauth2/token
Scopesapi refresh_token offline_access
Token Request Styleform_basic

3. Build Your MCP Server

server.tool(
  "search_salesforce_contacts",
  "Search for contacts in the user's Salesforce org",
  {
    query: z.string().describe("Search query for contact name or email")
  },
  async ({ query }, context) => {
    const token = context?.meta?.authorization?.replace("Bearer ", "");

    // Get instance URL from token info (simplified)
    const instanceUrl = "https://your-instance.salesforce.com";

    const soql = `SELECT Id, Name, Email, Phone FROM Contact WHERE Name LIKE '%${query}%' LIMIT 10`;

    const response = await fetch(
      `${instanceUrl}/services/data/v58.0/query?q=${encodeURIComponent(soql)}`,
      {
        headers: { "Authorization": `Bearer ${token}` }
      }
    );

    const results = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(results.records, null, 2) }]
    };
  }
);
27 lines