Skip to content

Evaluate enterprise IdP integration (SEP-990) for SSO across MCP servers #507

@teemow

Description

@teemow

Summary

SEP-990 ("Enable enterprise IdP policy controls during MCP OAuth flows") is a finalized MCP specification that enables enterprise Identity Providers to control authorization of MCP clients within corporate environments. It provides:

  • For enterprise admins: Centralized visibility and control over which MCP servers can be used within the organization
  • For end users: Automatic single sign-on across MCP clients and servers -- no manual authentication per server

This issue evaluates what SEP-990 means for muster and identifies the work needed to integrate it.

Background: What SEP-990 Does

SEP-990 implements the Identity Assertion Authorization Grant (ID-JAG) specification, combining RFC 8693 Token Exchange and RFC 7523 JWT Bearer Grant into a three-step flow:

  1. SSO Login: User authenticates to the MCP Client (muster) via enterprise IdP (Okta, Azure AD, etc.)
  2. Token Exchange (RFC 8693): Client exchanges the ID Token for an Identity Assertion JWT (ID-JAG) at the enterprise IdP. The IdP evaluates policy ("Is this user allowed to use this MCP server?") before issuing the ID-JAG.
  3. JWT Bearer Grant (RFC 7523): Client exchanges the ID-JAG for an access token at the MCP Server's authorization server.

The critical difference from standard OAuth is that the enterprise IdP sits in the middle of every MCP server connection, giving it policy control and eliminating per-server user consent.

User -> MCP Client (muster) -> Enterprise IdP (token exchange) -> MCP Server Auth Server (JWT bearer grant) -> Access Token

How Muster Is Affected

Current State

Muster currently supports three auth mechanisms for downstream MCP servers:

  1. Authorization Code Flow (core_auth_login): User manually authenticates via browser-based OAuth redirect per server. Implemented in internal/oauth/client.go and internal/aggregator/auth_tools.go.
  2. Token Forwarding (forwardToken: true): Muster's own ID token is forwarded to downstream servers that trust muster's OAuth client ID. Implemented in EstablishConnectionWithTokenForwarding() in internal/aggregator/connection_helper.go.
  3. Token Exchange (RFC 8693) (tokenExchange config): Muster exchanges its local token for a token valid on a remote cluster's Dex instance. Implemented in EstablishConnectionWithTokenExchange() and internal/oauth/token_exchange.go.

SEP-990 introduces a fourth mechanism that is conceptually similar to the existing token exchange but targets a different use case: instead of exchanging tokens between Dex instances within Giant Swarm's infrastructure, it exchanges tokens through an enterprise IdP (Okta, Azure AD, etc.) for access to third-party MCP servers (SaaS tools, partner services, etc.).

Key Differences from Existing Token Exchange

Aspect Current RFC 8693 Token Exchange SEP-990 Enterprise IdP
IdP Type Internal Dex instances Enterprise IdP (Okta, Azure AD)
Target Remote Giant Swarm clusters Any MCP server (SaaS, internal)
Step 1 Exchange ID token at remote Dex Exchange ID token for ID-JAG at enterprise IdP
Step 2 Use exchanged token directly Exchange ID-JAG at MCP server's auth server (RFC 7523)
Policy Control Trust-based (Dex connector config) Enterprise admin policy at IdP
User Interaction None (SSO) None (SSO)
Token Type Returned Access token from Dex ID-JAG (intermediate), then access token from MCP server

Muster's Role as Gateway/Proxy

Muster is an MCP aggregator/gateway -- the exact architecture pattern the MCP roadmap identifies for enterprise deployments. As a gateway, muster is the ideal place to implement SEP-990 because:

  • All MCP server connections flow through muster
  • Muster already handles SSO token management (ID token storage, refresh, forwarding)
  • Enterprise admins already configure MCP servers through muster's MCPServer CRDs
  • Adding SEP-990 at the gateway level means individual MCP servers don't need to change

Implementation Considerations

1. Go SDK Dependency

The mcp-go SDK has an open PR (#770) implementing SEP-990 as an extauth package under auth/. This PR is under active review (as of March 2026) and implements the OAuthHandler interface pattern. Muster should track this PR and evaluate whether to:

  • Wait for the upstream SDK to stabilize and use it
  • Implement the ID-JAG flow directly using existing libraries (golang.org/x/oauth2, mcp-oauth)

2. Two-Step Token Acquisition

Unlike the current single-step RFC 8693 exchange, SEP-990 requires two sequential token requests:

Step 1: Token Exchange at Enterprise IdP

POST /oauth2/token HTTP/1.1
Host: enterprise.okta.com

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token={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={mcp_server_auth_server_issuer}

Step 2: JWT Bearer Grant at MCP Server Auth Server

POST /oauth2/token HTTP/1.1
Host: auth.mcp-server.example.com

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion={id_jag_token}

This means the TokenExchanger abstraction in internal/oauth/token_exchange.go would need to be extended or a new EnterpriseIdPExchanger created alongside it.

3. MCPServer CRD Configuration

A new auth configuration option would be needed in the MCPServer CRD, e.g.:

apiVersion: mcp.giantswarm.io/v1alpha1
kind: MCPServer
spec:
  auth:
    enterpriseIdP:
      enabled: true
      idpTokenEndpoint: https://enterprise.okta.com/oauth2/token
      mcpAuthServerIssuer: https://auth.mcp-server.example.com
      clientCredentialsSecretRef:
        name: enterprise-idp-credentials
      scopes: "read write"

4. Integration with initSSOForSession

SEP-990 connections should integrate with the existing initSSOForSession() flow in internal/aggregator/auth_resource.go, establishing enterprise IdP connections automatically at login time (just like token forwarding and token exchange do today).

5. ID-JAG Validation

When muster receives an ID-JAG (if it also acts as an MCP authorization server), it needs to:

  • Validate the JWT signature using the enterprise IdP's JWKS
  • Check the iss, aud, sub, and exp claims
  • Verify the client_id claim matches the requesting application

6. Caching Strategy

The existing token exchange cache (oidc.TokenExchangeCache) could be extended to cache both the intermediate ID-JAG and the final access token. The ID-JAG typically has a short lifetime (5 minutes), while the final access token may be longer-lived.

Upstream Dependencies

Acceptance Criteria

  • Evaluate whether the mcp-go SDK's extauth package (when merged) is suitable for muster's use case
  • Design the MCPServer CRD extension for enterprise IdP configuration
  • Prototype the two-step token acquisition flow (ID token -> ID-JAG -> access token)
  • Determine how to integrate with the existing initSSOForSession flow
  • Assess enterprise IdP compatibility (Okta, Azure AD, Google Workspace) with Giant Swarm customer environments
  • Document the relationship between existing RFC 8693 token exchange (internal cross-cluster) and SEP-990 (enterprise IdP mediated)

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    Inbox 📥

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions