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

> Learn to configure OAuth providers like Claude Code Codex and GitHub Copilot in OmniRoute. Send a POST request to establish secure authenticated connections easily and efficiently.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-07-27

---

**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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/providers/oauth.ts). Each entry declares the provider `id`, display `name`, `alias`, `icon`, `color`, and the `subscriptionRisk` flag:

```ts
// 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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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:

```bash
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:

```bash
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`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/providers/zed/manual-import/route.ts), but the standard REST flow is preferred:

```bash
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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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:

```ts
// 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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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.