This reference describes the ID-JAG authentication flow. For conceptual understanding of why identity delegation matters, see Why Char Exists and Federated Authentication.
Standards
ID-JAG (Identity Assertion Authorization Grant) uses four OAuth/OIDC specifications:
| Standard | Role in ID-JAG |
|---|
| RFC 8693 | Token Exchange - Hub obtains ID-JAG from IDP |
| RFC 7523 | JWT Bearer Grant - Hub exchanges ID-JAG for access token at MCP server |
| RFC 8707 | Resource Indicators - scopes tokens to specific MCP servers |
| RFC 9728 | Protected Resource Metadata - MCP servers advertise auth requirements |
Authentication Flow
Step 1: Token Exchange Request
The Hub requests an ID-JAG from the IDP:
POST /oauth/token HTTP/1.1
Host: your-idp.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token={user_id_token}
&subject_token_type=urn:ietf:params:oauth:token-type:id_token
&requested_token_type=urn:ietf:params:oauth:token-type:id-jag
&audience=https://mcp-server.internal.com
&resource=https://mcp-server.internal.com
&scope=mcp:tools:read mcp:tools:call
Step 2: ID-JAG Structure
The IDP returns a JWT with type oauth-id-jag+jwt:
// Header
{
"typ": "oauth-id-jag+jwt",
"alg": "RS256",
"kid": "idp-signing-key-id"
}
// Payload
{
"iss": "https://sso.enterprise.com",
"sub": "[email protected]",
"aud": "https://mcp-server.internal.com",
"client_id": "char-tool-hub",
"resource": "https://mcp-server.internal.com",
"scope": "mcp:tools:read mcp:tools:call",
"exp": 1737100000,
"iat": 1737099700,
"jti": "unique-assertion-id"
}
Step 3: JWT Bearer Grant
The Hub exchanges the ID-JAG for an access token at the MCP server:
POST /oauth/token HTTP/1.1
Host: mcp-server.internal.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion={id_jag_jwt}
&client_id=char-tool-hub
&client_secret={tool_hub_secret}
Step 4: Access Token Response
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600
}
IDP Requirements
| Requirement | Notes |
|---|
| Token Exchange (RFC 8693) | Required |
| Configurable resource servers | For audience scoping |
| JWKS endpoint | For signature validation |
IDP Support Matrix
| Provider | Token Exchange | Configuration |
|---|
| Okta | Supported | Via Authorization Servers |
| Azure AD | Supported | Via App Registrations |
| Auth0 | Supported | Via APIs |
| AWS Cognito | Supported | Via Resource Servers |
| Keycloak | Supported | Built-in |
| Google Workspace | Limited | Requires Workload Identity |
MCP Server Requirements
MCP servers must expose /.well-known/oauth-protected-resource:
{
"resource": "https://mcp-server.internal.com",
"authorization_servers": ["https://mcp-server.internal.com"],
"scopes_supported": ["mcp:tools:read", "mcp:tools:call"]
}
Token Endpoint
MCP servers must implement a token endpoint accepting JWT Bearer Grants:
// Token endpoint implementation
if (url.pathname === '/oauth/token' && request.method === 'POST') {
const body = await request.formData();
const grantType = body.get('grant_type');
// Only accept JWT Bearer Grant
if (grantType !== 'urn:ietf:params:oauth:grant-type:jwt-bearer') {
return Response.json({ error: 'unsupported_grant_type' }, { status: 400 });
}
const assertion = body.get('assertion') as string;
// Validate ID-JAG
const validation = await validateIdJag(assertion, {
trustedIssuers: [env.IDP_ISSUER],
expectedAudience: env.MCP_RESOURCE_ID,
idpJwksUrl: env.IDP_JWKS_URL,
});
if (!validation.valid) {
return Response.json({ error: 'invalid_grant' }, { status: 400 });
}
// Issue access token
const accessToken = await issueAccessToken({
sub: validation.claims.sub,
aud: env.MCP_RESOURCE_ID,
scope: validation.claims.scope,
exp: Math.floor(Date.now() / 1000) + 3600,
}, env.SIGNING_KEY);
return Response.json({
access_token: accessToken,
token_type: 'Bearer',
expires_in: 3600,
});
}
ID-JAG Validation
| Check | Requirement |
|---|
| Signature | Validate against IDP’s JWKS |
typ header | Must be oauth-id-jag+jwt |
iss | Must match trusted IDP issuer |
aud | Must match MCP server’s resource ID |
client_id | Must match expected Tool Hub client |
exp | Must be in future (60s clock skew tolerance) |
Access Token Validation
MCP servers validate incoming access tokens on protected endpoints:
| Claim | Validation |
|---|
iss | Must match MCP server’s token endpoint |
aud | Must match MCP server’s resource ID |
sub | User identifier for authorization |
exp | Must be in future (60s clock skew) |
Optional Claims
| Claim | Purpose |
|---|
email | User email address |
groups | Group memberships |
roles | Role assignments |
scope | Granted capabilities |
Token Properties
| Token Type | Issuer | Audience | Typical Lifetime |
|---|
| User ID Token | Enterprise IDP | Frontend app | 1 hour |
| ID-JAG | Enterprise IDP | MCP server | 5 minutes |
| Access Token | MCP server | MCP server | 5-60 minutes |
Hub Token Caching
Cache key format: token:{org_id}:{connector_id}:{user_id}
interface CachedToken {
access_token: string;
expires_at: number;
refresh_token?: string;
scopes: string[];
}
Cache TTL: min(token_expiry - 300, 3600) seconds.
Tokens are stored in encrypted KV. Never stored in queryable databases.
Transaction Tokens
For MCP server internal service calls, use downscoped Transaction Tokens:
| Property | Requirement |
|---|
| Audience | Bound to specific internal service |
| Scope | Limited to specific operation |
| Lifetime | Seconds to minutes |
| User context | Embedded in signed claims |
Fallback Authentication
When ID-JAG is not available:
| Method | Use Case |
|---|
passthrough | Forward user’s IDP token directly (legacy compatibility) |
service | Service credentials without user context (mTLS, API key) |
oauth-pkce | User-consented OAuth for external MCPs |
passthrough bypasses audience scoping. Use only for legacy systems that cannot support ID-JAG.
Specification Status
| Component | Status |
|---|
| RFC 8693 (Token Exchange) | Stable |
| RFC 7523 (JWT Bearer Grant) | Stable |
| RFC 8707 (Resource Indicators) | Stable |
| RFC 9728 (Protected Resource Metadata) | Stable |
| ID-JAG Draft | Draft, implementations emerging |
| MCP Enterprise-Managed Authorization | Draft |
References
OAuth/OIDC:
MCP:
See Also