Skip to main content
Private Beta — Remote MCP authentication is currently in private beta. Contact us to get access.
This reference describes the ID-JAG authentication flow. For conceptual understanding of why identity delegation matters, see Why Char Exists and Federated Authentication.
Prerequisites: ID-JAG requires one-time IDP setup. Your IDP admin must register Char as an OAuth client and grant token exchange permissions before the flows described here will work.

Standards

ID-JAG (Identity Assertion Authorization Grant) uses four OAuth/OIDC specifications:
StandardRole in ID-JAG
RFC 8693Token Exchange - Hub obtains ID-JAG from IDP
RFC 7523JWT Bearer Grant - Hub exchanges ID-JAG for access token at MCP server
RFC 8707Resource Indicators - scopes tokens to specific MCP servers
RFC 9728Protected 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

ID-JAG authentication requires your identity provider to support:
  1. RFC 8693 Token Exchange — The ability to exchange tokens at the /token endpoint
  2. ID-JAG Token Type — Issuing JWTs with typ: "oauth-id-jag+jwt" and accepting requested_token_type=urn:ietf:params:oauth:token-type:id-jag
Many providers support the underlying Token Exchange primitive but not the specific ID-JAG profile yet.
RequirementNotes
Token Exchange (RFC 8693)Required
ID-JAG Token TypeRequired for full compatibility
Configurable resource serversFor audience scoping
JWKS endpointFor signature validation

IDP Support Matrix

ID-JAG requires both RFC 8693 (Token Exchange) and support for the oauth-id-jag+jwt token type. Support varies significantly across providers.
ProviderRFC 8693ID-JAG Token TypeStatusTracking
Okta⚠️ Early AccessXAA Early AccessActive development
PingFederate❓ UnconfirmedFull RFC 8693, ID-JAG unverified
PingOne❓ UnconfirmedFull RFC 8693, ID-JAG unverified
Auth0⚠️ BetaXAA Resource App BetaActive development
Keycloak✅ (v26.2+)❌ Not yetToken Exchange GA, ID-JAG pending#43971
Azure AD / EntraUses proprietary On-Behalf-Of
AWS CognitoNo RFC 8693 support
Google Workspace⚠️ LimitedWorkload Identity Federation only
Legend: ✅ = Supported, ⚠️ = Partial/Early Access, ❌ = Not supported, ❓ = UnconfirmedThis matrix reflects the state as of January 2026. ID-JAG is an emerging IETF draft specification (draft-ietf-oauth-identity-assertion-authz-grant). Provider support is evolving rapidly.

MCP Server Requirements

Protected Resource Metadata (RFC 9728)

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

CheckRequirement
SignatureValidate against IDP’s JWKS
typ headerMust be oauth-id-jag+jwt
issMust match trusted IDP issuer
audMust match MCP server’s resource ID
client_idMust match expected Tool Hub client
expMust be in future (60s clock skew tolerance)

Access Token Validation

MCP servers validate incoming access tokens on protected endpoints:
ClaimValidation
issMust match MCP server’s token endpoint
audMust match MCP server’s resource ID
subUser identifier for authorization
expMust be in future (60s clock skew)

Optional Claims

ClaimPurpose
emailUser email address
groupsGroup memberships
rolesRole assignments
scopeGranted capabilities

Token Properties

Token TypeIssuerAudienceTypical Lifetime
User ID TokenEnterprise IDPFrontend app1 hour
ID-JAGEnterprise IDPMCP server5 minutes
Access TokenMCP serverMCP server5-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:
PropertyRequirement
AudienceBound to specific internal service
ScopeLimited to specific operation
LifetimeSeconds to minutes
User contextEmbedded in signed claims

External MCP Servers

For MCP servers operated by third parties (not your organization), use OAuth 2.1 with PKCE:
  • User explicitly consents via OAuth flow
  • Requires registration with the external MCP’s auth server (not your enterprise IDP)
  • User identity is established through the external provider’s OAuth, not your SSO
This is the standard OAuth pattern—the user sees a consent screen and authorizes the Tool Hub to act on their behalf with that specific external service.
ID-JAG is for internal MCP servers that trust your enterprise IDP. External MCP servers have their own identity systems and require explicit user consent.

Specification Status

ComponentStatus
RFC 8693 (Token Exchange)Stable
RFC 7523 (JWT Bearer Grant)Stable
RFC 8707 (Resource Indicators)Stable
RFC 9728 (Protected Resource Metadata)Stable
ID-JAG DraftDraft, implementations emerging
MCP Enterprise-Managed AuthorizationDraft

References

OAuth/OIDC: MCP:

See Also