How to Configure OAuth Providers like Claude Code, Codex, and GitHub Copilot in OmniRoute

To configure OAuth providers in OmniRoute, send a POST request to /api/v1/providers/{providerId}/connections with authType set to "oauth", the provider id, and valid accessToken and refreshToken values; OmniRoute then encrypts, deduplicates, and persists the connection.

OmniRoute unifies LLM routing by storing every provider inside a central catalog. OAuth-only providers such as Claude Code, OpenAI Codex, and GitHub Copilot are defined in src/shared/constants/providers/oauth.ts and registered through a single REST endpoint. Understanding the exact payload structure and how the backend handles encryption and duplicate detection lets you integrate these tools securely without manual database edits.

Where OAuth Providers Are Defined in the OmniRoute Source Code

All OAuth providers live in the constant catalog at src/shared/constants/providers/oauth.ts. Each entry declares the provider id, display name, alias, icon, color, and the subscriptionRisk flag:

// src/shared/constants/providers/oauth.ts
export const OAUTH_PROVIDERS = {
  claude: {
    id: "claude",
    alias: "cc",
    name: "Claude Code",
    icon: "smart_toy",
    color: "#D97757",
    subscriptionRisk: true,
    riskNoticeVariant: "oauth",
  },
  antigravity: {
    id: "antigravity",
    name: "Antigravity",
    icon: "rocket_launch",
    color: "#F59E0B",
    subscriptionRisk: true,
    riskNoticeVariant: "oauth",
  },
  codex: {
    id: "codex",
    alias: "cx",
    name: "OpenAI Codex",
    icon: "code",
    color: "#3B82F6",
    subscriptionRisk: true,
    riskNoticeVariant: "oauth",
  },
  github: { id: "github", alias: "gh", name: "GitHub Copilot", icon: "code", color: "#333333" },
  cursor: {
    id: "cursor",
    alias: "cu",
    name: "Cursor IDE",
    icon: "edit_note",
    color: "#00D4AA",
    subscriptionRisk: true,
    riskNoticeVariant: "oauth",
  },
  // …other OAuth providers
};

Because every provider in this object carries riskNoticeVariant: "oauth", the UI renders them under the OAuth Providers tab and displays the corresponding warning icon next to each tile.

Required API Fields for Creating an OAuth Connection

The public API handler lives under src/app/api/v1/providers/[provider]/connections/route.ts. It forwards incoming JSON to createProviderConnection in src/lib/db/providers.ts.

Submit a POST request to:


POST /api/v1/providers/{providerId}/connections

The request body must include the following fields:

  • authType — Required. Must be the string "oauth" for all providers listed in this guide.
  • provider — Required. The provider id from the catalog (e.g., "claude", "github", "cursor").
  • accessToken — Required. The OAuth access token returned by the provider’s authorization flow.
  • refreshToken — Required. The token OmniRoute uses for automatic renewal.
  • expiresAt — Optional. ISO-8601 timestamp after which the access token is considered stale.
  • email — Optional. Used for duplicate detection; highly recommended for Codex and Claude.
  • displayName — Optional. Human-readable label (defaults to the email if omitted).
  • providerSpecificData — Optional. Provider-specific JSON such as workspaceId for Codex or projectId for Antigravity.

How to Register a Claude Code OAuth Connection

Use the provider ID claude and alias cc. The following curl command passes the minimal required fields plus an optional display name:

curl -X POST https://my-omniroute.example.com/api/v1/providers/claude/connections \
  -H "Content-Type: application/json" \
  -d '{
        "authType": "oauth",
        "provider": "claude",
        "accessToken": "ya29.a0AfH6SM....",
        "refreshToken": "1//04iZk....",
        "expiresAt": "2027-03-01T12:34:56Z",
        "email": "alice@example.com",
        "displayName": "Alice-Claude",
        "providerSpecificData": {}
      }'

How to Register a GitHub Copilot OAuth Connection

For GitHub Copilot, set provider to "github" and include the GitHub-issued tokens:

curl -X POST https://my-omniroute.example.com/api/v1/providers/github/connections \
  -H "Content-Type: application/json" \
  -d '{
        "authType": "oauth",
        "provider": "github",
        "accessToken": "gho_XXXXXXXXXXXXXXXXXXXX",
        "refreshToken": "ghr_XXXXXXXXXXXXXXXXXXXX",
        "expiresAt": "2027-01-15T08:00:00Z",
        "email": "bob@company.com",
        "displayName": "Bob-Copilot"
      }'

How to Register a Cursor IDE OAuth Connection

Cursor uses the provider ID cursor. IDE-based OAuth providers can also follow the manual import pattern demonstrated in src/app/api/providers/zed/manual-import/route.ts, but the standard REST flow is preferred:

curl -X POST https://my-omniroute.example.com/api/v1/providers/cursor/connections \
  -H "Content-Type: application/json" \
  -d '{
        "authType": "oauth",
        "provider": "cursor",
        "accessToken": "cursor-access-token",
        "refreshToken": "cursor-refresh-token",
        "expiresAt": "2026-12-31T23:59:59Z",
        "email": "carol@dev.com",
        "displayName": "Carol-Cursor"
      }'

Duplicate Detection and Encryption Logic

All CRUD operations run through src/lib/db/providers.ts, specifically the createProviderConnection function. Before inserting a row, OmniRoute performs four critical steps:

  1. Validates the payload.
  2. Normalizes provider-specific data via normalizeProviderSpecificData.
  3. Detects duplicates by matching provider, auth_type, and email. For Codex, it can also disambiguate by workspaceId inside providerSpecificData.
  4. Encrypts secret fields through encryptConnectionFields before persistence.

If an existing connection matches the same email and provider, the function performs an upsert rather than creating a second row, preventing quota-splitting bugs:

// src/lib/db/providers.ts – creation flow
export async function createProviderConnection(data: JsonRecord) {
  const db = getDbInstance() as unknown as DbLike;
  const now = new Date().toISOString();
  const normalizedProviderSpecificData = normalizeProviderSpecificData(
    toStringOrNull(data.provider),
    data.providerSpecificData
  );

  // ---- OAuth duplicate detection (email + workspace) ----
  if (data.authType === "oauth" && data.email) {
    const existing = db.prepare(
      "SELECT * FROM provider_connections WHERE provider = ? AND auth_type = 'oauth' AND email = ?"
    ).all(data.provider, data.email) as JsonRecord[];
    // …additional disambiguation logic omitted for brevity…
    if (existing.length) existingRow = existing[0];
  }

  // If a matching row exists, update it; otherwise insert a new connection.
  if (existingRow) { /* …update logic… */ } 
  else { /* …insert logic… */ }
}

After persistence, OmniRoute calls _reorderConnections to rebuild the routing priority list automatically.

Automatic Token Refresh and Connection Priorities

OmniRoute does not leave tokens to expire silently. The background logic in src/lib/oauth/refresh.ts periodically calls each provider’s token-refresh endpoint. The newly obtained access token is written back to the database via updateProviderConnection, so your routing pipeline stays active without manual re-authentication.

Once the POST succeeds and tokens are refreshed automatically, the connection appears on the Providers page under the OAuth Providers tab. It immediately becomes eligible for model queries through src/app/api/v1/providers/[provider]/models/route.ts.

Summary

  • OmniRoute catalogs OAuth providers in src/shared/constants/providers/oauth.ts, where each entry uses riskNoticeVariant: "oauth" to flag the authentication method.
  • Register a connection by sending a POST to /api/v1/providers/{providerId}/connections with authType: "oauth", accessToken, and refreshToken.
  • The backend at src/lib/db/providers.ts deduplicates by email and provider, normalizes metadata, and encrypts secrets before storage.
  • Duplicate credentials trigger an upsert instead of a new row, preventing connection sprawl.
  • OmniRoute automatically refreshes tokens via src/lib/oauth/refresh.ts and re-orders connection priorities after every create or update.

Frequently Asked Questions

How does OmniRoute prevent duplicate OAuth connections?

OmniRoute detects duplicates inside createProviderConnection in src/lib/db/providers.ts by querying provider_connections for a matching provider, auth_type = 'oauth', and email. For Codex, it can also factor in workspaceId from providerSpecificData. If a match exists, the function updates the existing row instead of inserting a new one.

Does OmniRoute support automatic OAuth token refresh?

Yes. The system runs periodic refresh logic defined in src/lib/oauth/refresh.ts. It exchanges the stored refresh token for a new access token and persists the result through updateProviderConnection, keeping the connection alive without user intervention.

What provider-specific data can I include for Codex or Antigravity?

You can pass a JSON object in the providerSpecificData field. For OpenAI Codex, this may include a workspaceId. For Antigravity, it may include a projectId. OmniRoute normalizes this data through normalizeProviderSpecificData before writing it to the database.

Where can I verify that my OAuth connection was created successfully?

After the API returns success, the connection appears in the Providers page of the OmniRoute UI under the OAuth Providers tab. You can also verify programmatically by querying GET /api/v1/providers/{providerId}/models, which reads active connections in src/app/api/v1/providers/[provider]/models/route.ts to determine reachable models.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →