RouterMCP
SDKsTypeScript

OAuth Adapters

Configure token storage with memory, file, or cloud adapters.

OAuth Adapters

OAuth adapters handle storage and retrieval of OAuth tokens for upstream MCP servers that require authentication (e.g., GitHub, Gmail, Slack).

Available Adapters

AdapterUse CasePersistenceMulti-Process
memoryAdapterTesting, short-lived processesNoNo
fileAdapterCLI tools, local developmentYesLimited
cloudAdapterProduction, multi-instanceYesYes

Memory Adapter

Stores tokens in memory. Tokens are lost when the process exits.

import { RouterMCPClient } from '@routermcp/sdk';
import { memoryAdapter } from '@routermcp/sdk/oauth';

const client = new RouterMCPClient({
  url: 'https://gateway.routermcp.com/v1/mcp/my-project',
  oauth: {
    adapter: memoryAdapter(),
  },
});

Only use the memory adapter for testing or short-lived processes. Tokens will be lost on restart.

File Adapter

Stores tokens as JSON files on disk. Compatible with the RouterMCP CLI's token storage.

import { RouterMCPClient } from '@routermcp/sdk';
import { fileAdapter } from '@routermcp/sdk/oauth';

// Default: ~/.routermcp/mcp-oauth/
const client = new RouterMCPClient({
  url: 'https://gateway.routermcp.com/v1/mcp/my-project',
  oauth: {
    adapter: fileAdapter(),
  },
});

// Custom path
const client2 = new RouterMCPClient({
  url: 'https://gateway.routermcp.com/v1/mcp/my-project',
  oauth: {
    adapter: fileAdapter('/path/to/tokens'),
  },
});

File Structure

Tokens are stored as:

~/.routermcp/mcp-oauth/
  {userId}/
    {serverId}.json

The file adapter is compatible with the RouterMCP CLI. Tokens authorized via the CLI will be available to the SDK and vice versa.

Cloud Adapter

Stores tokens in RouterMCP Cloud via API. Ideal for production deployments with multiple instances.

import { RouterMCPClient } from '@routermcp/sdk';
import { cloudAdapter } from '@routermcp/sdk/oauth';

const client = new RouterMCPClient({
  url: 'https://gateway.routermcp.com/v1/mcp/my-project',
  oauth: {
    adapter: cloudAdapter({
      apiKey: 'rmc_...', // Your RouterMCP API key
    }),
  },
});

// Custom API endpoint
const client2 = new RouterMCPClient({
  url: 'https://gateway.routermcp.com/v1/mcp/my-project',
  oauth: {
    adapter: cloudAdapter({
      apiKey: 'rmc_...',
      baseUrl: 'https://custom.routermcp.com',
    }),
  },
});

Multi-User OAuth

For applications serving multiple users, each user needs their own OAuth tokens:

import { RouterMCPClient } from '@routermcp/sdk';
import { cloudAdapter } from '@routermcp/sdk/oauth';

const client = new RouterMCPClient({
  url: 'https://gateway.routermcp.com/v1/mcp/my-project',
  userId: 'default-user',
  oauth: {
    adapter: cloudAdapter({ apiKey: 'rmc_...' }),
    autoRefresh: true,
  },
});

await client.connect();

// Create sessions for different users
async function handleUserRequest(userId: string, toolName: string, args: object) {
  const session = client.createSession({ userId });
  await session.connect();
  
  try {
    const result = await session.callTool(toolName, args);
    return result;
  } finally {
    await session.disconnect();
  }
}

// Each user's OAuth tokens are stored separately
await handleUserRequest('user-1', 'gmail_send', { to: 'a@test.com', body: 'Hi' });
await handleUserRequest('user-2', 'slack_post', { channel: '#general', text: 'Hello' });

OAuth Flow

When a tool requires OAuth and no valid token exists:

  1. The tool call returns an OAuth authorization URL
  2. Your application redirects the user to this URL
  3. User authorizes the application
  4. RouterMCP stores the tokens via your configured adapter
  5. Subsequent tool calls use the stored tokens
try {
  const result = await client.callTool('gmail_send', { to: 'test@example.com' });
} catch (error) {
  if (error instanceof OAuthError && error.authorizationUrl) {
    // Redirect user to error.authorizationUrl
    console.log('Please authorize:', error.authorizationUrl);
  }
}

Custom Adapters

Implement the OAuthAdapter interface for custom storage:

interface OAuthAdapter {
  getTokens(userId: string, serverId: string): Promise<OAuthTokens | null>;
  setTokens(userId: string, serverId: string, tokens: OAuthTokens): Promise<void>;
  deleteTokens(userId: string, serverId: string): Promise<void>;
}

interface OAuthTokens {
  accessToken: string;
  refreshToken?: string;
  expiresAt?: number;
  tokenType: string;
}

Example with Redis:

import { createClient } from 'redis';

function redisAdapter(redisUrl: string): OAuthAdapter {
  const client = createClient({ url: redisUrl });
  
  return {
    async getTokens(userId, serverId) {
      const key = `oauth:${userId}:${serverId}`;
      const data = await client.get(key);
      return data ? JSON.parse(data) : null;
    },
    
    async setTokens(userId, serverId, tokens) {
      const key = `oauth:${userId}:${serverId}`;
      await client.set(key, JSON.stringify(tokens));
    },
    
    async deleteTokens(userId, serverId) {
      const key = `oauth:${userId}:${serverId}`;
      await client.del(key);
    },
  };
}

const client = new RouterMCPClient({
  url: 'https://gateway.routermcp.com/v1/mcp/my-project',
  oauth: {
    adapter: redisAdapter('redis://localhost:6379'),
  },
});

On this page