> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentfront.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Remote OAuth Providers

> Connect to external identity providers like Auth0, Okta, and Azure AD

FrontMCP supports two approaches for integrating external identity providers:

<CardGroup cols={2}>
  <Card title="Transparent Mode" icon="arrow-right-arrow-left">
    Pass-through tokens from the IdP. FrontMCP validates but doesn't issue tokens.

    **Best for:** Single IdP, existing auth infrastructure
  </Card>

  <Card title="Orchestrated Remote" icon="sitemap">
    FrontMCP acts as OAuth server, proxying user authentication to upstream IdP.

    **Best for:** Multi-provider, progressive auth, federated scenarios
  </Card>
</CardGroup>

***

## Transparent Mode

Direct token pass-through from external identity provider.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@FrontMcp({
  info: { name: 'MyServer', version: '1.0.0' },
  auth: {
    mode: 'transparent',
    remote: {
      provider: 'https://auth.example.com',
    },
    expectedAudience: 'https://api.myservice.com',
  },
})
export class Server {}
```

### Configuration Options

| Option             | Type                 | Default         | Description                          |
| ------------------ | -------------------- | --------------- | ------------------------------------ |
| `remote.provider`  | `string`             | Required        | Base URL of the identity provider    |
| `remote.jwksUri`   | `string`             | Auto-discovered | Custom JWKS endpoint                 |
| `remote.jwks`      | `JSONWebKeySet`      | -               | Inline JWKS for offline verification |
| `expectedAudience` | `string \| string[]` | Issuer URL      | Required audience claim value(s)     |
| `requiredScopes`   | `string[]`           | `[]`            | Scopes that must be present in token |
| `allowAnonymous`   | `boolean`            | `false`         | Allow requests without tokens        |

### Provider Examples

<Tabs>
  <Tab title="Auth0">
    ```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    @FrontMcp({
      info: { name: 'MyServer', version: '1.0.0' },
      auth: {
        mode: 'transparent',
        remote: {
          provider: 'https://your-tenant.auth0.com',
          // JWKS auto-discovered from /.well-known/jwks.json
        },
        expectedAudience: 'https://api.yourservice.com',
        requiredScopes: ['openid', 'profile'],
      },
    })
    export class Server {}
    ```
  </Tab>

  <Tab title="Okta">
    ```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    @FrontMcp({
      info: { name: 'MyServer', version: '1.0.0' },
      auth: {
        mode: 'transparent',
        remote: {
          provider: 'https://your-org.okta.com/oauth2/default',
        },
        expectedAudience: 'api://default',
      },
    })
    export class Server {}
    ```
  </Tab>

  <Tab title="Azure AD">
    ```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    @FrontMcp({
      info: { name: 'MyServer', version: '1.0.0' },
      auth: {
        mode: 'transparent',
        remote: {
          provider: 'https://login.microsoftonline.com/{tenant}/v2.0',
          jwksUri: 'https://login.microsoftonline.com/{tenant}/discovery/v2.0/keys',
        },
        expectedAudience: 'api://{client-id}',
      },
    })
    export class Server {}
    ```
  </Tab>

  <Tab title="Google">
    ```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    @FrontMcp({
      info: { name: 'MyServer', version: '1.0.0' },
      auth: {
        mode: 'transparent',
        remote: {
          provider: 'https://accounts.google.com',
          jwksUri: 'https://www.googleapis.com/oauth2/v3/certs',
        },
        expectedAudience: '{your-client-id}.apps.googleusercontent.com',
      },
    })
    export class Server {}
    ```
  </Tab>
</Tabs>

### Token Flow

```mermaid theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
sequenceDiagram
    participant Client
    participant FrontMCP
    participant IdP as Identity Provider

    Client->>IdP: Authenticate (OAuth flow)
    IdP-->>Client: Access Token (JWT)

    Client->>FrontMCP: API Request + Bearer token
    FrontMCP->>IdP: Fetch JWKS (cached)
    FrontMCP->>FrontMCP: Verify JWT signature
    FrontMCP->>FrontMCP: Validate claims (aud, exp, iss)
    FrontMCP-->>Client: Authorized response
```

***

## Orchestrated Remote Mode

FrontMCP acts as an OAuth server while proxying user authentication to upstream IdP.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@FrontMcp({
  info: { name: 'MyServer', version: '1.0.0' },
  auth: {
    mode: 'orchestrated',
    type: 'remote',
    remote: {
      provider: 'https://auth.example.com',
      clientId: 'your-client-id',
      clientSecret: 'your-client-secret',
      scopes: ['openid', 'profile', 'email'],
    },
    consent: { enabled: true },
    sessionMode: 'stateful',
  },
})
export class Server {}
```

### Configuration Options

| Option                | Type                        | Default      | Description                                |
| --------------------- | --------------------------- | ------------ | ------------------------------------------ |
| `remote.provider`     | `string`                    | Required     | Upstream IdP base URL                      |
| `remote.clientId`     | `string`                    | Required     | OAuth client ID                            |
| `remote.clientSecret` | `string`                    | -            | OAuth client secret (confidential clients) |
| `remote.scopes`       | `string[]`                  | `['openid']` | Scopes to request from IdP                 |
| `remote.dcrEnabled`   | `boolean`                   | `false`      | Use Dynamic Client Registration            |
| `consent`             | `boolean`                   | `false`      | Show consent UI after IdP login            |
| `sessionMode`         | `'stateful' \| 'stateless'` | `'stateful'` | Session management strategy                |

### When to Use Orchestrated Remote

<Check>**Multiple identity providers** - Federate users from different IdPs under one session</Check>
<Check>**Progressive authorization** - Users authorize apps incrementally</Check>
<Check>**Custom token claims** - Add claims not available from upstream</Check>
<Check>**Consent UI** - Let users select which tools/resources to grant</Check>

### Token Flow

```mermaid theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
sequenceDiagram
    participant User
    participant Client
    participant FrontMCP
    participant IdP as Upstream IdP

    Client->>FrontMCP: GET /oauth/authorize
    FrontMCP-->>User: Redirect to IdP

    User->>IdP: Login
    IdP-->>FrontMCP: Authorization code

    FrontMCP->>IdP: Exchange code for tokens
    IdP-->>FrontMCP: IdP tokens

    FrontMCP->>FrontMCP: Create session
    FrontMCP->>FrontMCP: Sign FrontMCP token
    FrontMCP-->>Client: Redirect with code

    Client->>FrontMCP: Exchange code
    FrontMCP-->>Client: FrontMCP tokens
```

***

## Dynamic Client Registration

When the IdP supports DCR, FrontMCP can register clients automatically:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
auth: {
  mode: 'orchestrated',
  type: 'remote',
  remote: {
    provider: 'https://auth.example.com',
    dcrEnabled: true, // Enable DCR
    // clientId/clientSecret derived from registration
  },
}
```

<Info>
  Not all providers support DCR. Check your IdP documentation.
</Info>

***

## Endpoint Overrides

Override auto-discovered endpoints for non-standard IdPs:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
auth: {
  mode: 'orchestrated',
  type: 'remote',
  remote: {
    provider: 'https://legacy-idp.example.com',
    authEndpoint: 'https://legacy-idp.example.com/auth',
    tokenEndpoint: 'https://legacy-idp.example.com/token',
    userInfoEndpoint: 'https://legacy-idp.example.com/userinfo',
    jwksUri: 'https://legacy-idp.example.com/keys',
  },
}
```

***

## Inline JWKS

For offline verification or non-discoverable providers:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
auth: {
  mode: 'transparent',
  remote: {
    provider: 'https://auth.example.com',
    jwks: {
      keys: [
        {
          kty: 'RSA',
          kid: 'key-id-1',
          alg: 'RS256',
          n: '...',
          e: 'AQAB',
        },
      ],
    },
  },
}
```

***

## Multi-Provider Setup

Combine multiple providers with orchestrated mode:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@App({
  name: 'Slack',
  auth: {
    mode: 'transparent',
    remote: { provider: 'https://slack.com/oauth' },
  },
  standalone: true,
})
export class SlackApp {}

@App({
  name: 'CRM',
  auth: {
    mode: 'transparent',
    remote: { provider: 'https://company.auth0.com' },
  },
})
export class CrmApp {}

@FrontMcp({
  info: { name: 'Suite', version: '1.0.0' },
  apps: [SlackApp, CrmApp],
  auth: {
    mode: 'orchestrated',
    type: 'local',
    consent: { enabled: true },
  },
})
export class Server {}
```

***

## Per-App Remote Auth

Configure different providers per app:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@App({
  name: 'Billing',
  auth: {
    mode: 'transparent',
    remote: {
      provider: 'https://billing.auth0.com',
    },
  },
})
export class BillingApp {}

@App({
  name: 'Analytics',
  auth: {
    mode: 'transparent',
    remote: {
      provider: 'https://analytics.okta.com/oauth2/default',
    },
  },
})
export class AnalyticsApp {}

@FrontMcp({
  info: { name: 'Suite', version: '1.0.0' },
  apps: [BillingApp, AnalyticsApp],
  splitByApp: true,
})
export class Server {}
```

<Tip>
  Use `standalone: true` to expose an app's OAuth endpoints directly, bypassing the parent auth.
</Tip>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Token verification fails">
    * Check `expectedAudience` matches the token's `aud` claim
    * Verify JWKS endpoint is accessible
    * Ensure token hasn't expired
  </Accordion>

  <Accordion title="JWKS fetch fails">
    * Verify IdP URL is correct
    * Check network connectivity
    * Try providing inline JWKS via `remote.jwks`
  </Accordion>

  <Accordion title="Redirect URI mismatch">
    * Register exact redirect URI with IdP
    * Check for trailing slashes
    * Ensure protocol (http/https) matches
  </Accordion>
</AccordionGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Remote Proxy" icon="share" href="/frontmcp/authentication/remote-proxy">
    Handle IdPs without DCR support
  </Card>

  <Card title="Progressive Authorization" icon="forward" href="/frontmcp/authentication/progressive">
    Implement incremental app authorization
  </Card>

  <Card title="Local OAuth" icon="server" href="/frontmcp/authentication/local">
    Built-in OAuth server setup
  </Card>

  <Card title="Production Checklist" icon="clipboard-check" href="/frontmcp/authentication/production">
    Security requirements for deployment
  </Card>
</CardGroup>
