FrontMCP supports two approaches for integrating external identity providers:
Transparent Mode
Pass-through tokens from the IdP. FrontMCP validates but doesn’t issue tokens.Best for: Single IdP, existing auth infrastructure
Orchestrated Remote
FrontMCP acts as OAuth server, proxying user authentication to upstream IdP.Best for: Multi-provider, progressive auth, federated scenarios
Transparent Mode
Direct token pass-through from external identity provider.
@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
Auth0
Okta
Azure AD
Google
@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 {}
@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 {}
@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 {}
@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 {}
Token Flow
Orchestrated Remote Mode
FrontMCP acts as an OAuth server while proxying user authentication to upstream IdP.
@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
Multiple identity providers - Federate users from different IdPs under one session
Progressive authorization - Users authorize apps incrementally
Custom token claims - Add claims not available from upstream
Consent UI - Let users select which tools/resources to grant
Token Flow
Dynamic Client Registration
When the IdP supports DCR, FrontMCP can register clients automatically:
auth: {
mode: 'orchestrated',
type: 'remote',
remote: {
provider: 'https://auth.example.com',
dcrEnabled: true, // Enable DCR
// clientId/clientSecret derived from registration
},
}
Not all providers support DCR. Check your IdP documentation.
Endpoint Overrides
Override auto-discovered endpoints for non-standard IdPs:
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:
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:
@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:
@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 {}
Use standalone: true to expose an app’s OAuth endpoints directly, bypassing the parent auth.
Troubleshooting
- Check
expectedAudience matches the token’s aud claim
- Verify JWKS endpoint is accessible
- Ensure token hasn’t expired
- Verify IdP URL is correct
- Check network connectivity
- Try providing inline JWKS via
remote.jwks
- Register exact redirect URI with IdP
- Check for trailing slashes
- Ensure protocol (http/https) matches
Next Steps