Skip to content

auth/extauth: only forward an ID-JAG to the MCP authorization server - #1438

Merged
guglielmo-san merged 3 commits into
modelcontextprotocol:mainfrom
akshita317:extauth-check-issued-token-type
Oct 26, 2026
Merged

guglielmo-san merged 3 commits into
modelcontextprotocol:mainfrom
akshita317:extauth-check-issued-token-type

Conversation

@akshita317

Copy link
Copy Markdown
Contributor

EnterpriseHandler.Authorize exchanges the user's ID token at the IdP for an ID-JAG (RFC 8693 token exchange), then sends the token it gets back to the MCP Server's authorization server as a JWT bearer assertion (RFC 7523). It never looked at issued_token_type in the exchange response; oauthex.ExchangeToken only checks that the field is present.

So if the IdP answered with a different type of token, for example an access token from an IdP that does not implement ID-JAG but does implement plain token exchange, that token was forwarded to a party other than the one that issued it.

This refuses the exchange result unless issued_token_type is urn:ietf:params:oauth:token-type:id-jag (oauthex.TokenTypeIDJAG), the value the Identity Assertion Authorization Grant draft defines for this response. The check lives in the handler rather than in ExchangeToken, which is a general RFC 8693 helper where the issued type may legitimately differ from the requested one.

Tests:

  • internal/oauthtest: the fake IdP gets a TokenExchangeConfig.IssuedTokenType option (defaults to the ID-JAG type, so existing tests are unchanged).
  • TestEnterpriseHandler_Authorize_NotIDJAG: the IdP issues an access token, and the MCP authorization server is configured to accept it as an assertion. Without the change Authorize succeeds, i.e. the token is forwarded and accepted; with it, Authorize returns an error and no token source is stored.

AI assistance: prepared with Claude Code.

akshita317 and others added 2 commits October 23, 2026 01:57
EnterpriseHandler.Authorize asks the IdP to exchange the user's ID token
for an ID-JAG, then sends the token it gets back to the MCP Server's
authorization server as a JWT bearer assertion. It did not look at the
issued_token_type of the exchange response, which ExchangeToken only
checks is present. If the IdP issued another type of token, such as an
access token, that token was handed to a different party than the one
that issued it.

Refuse the response unless issued_token_type is
urn:ietf:params:oauth:token-type:id-jag, the value the Identity
Assertion Authorization Grant specification defines for it.

The fake IdP gets an IssuedTokenType option, and
TestEnterpriseHandler_Authorize_NotIDJAG checks that such a token is not
forwarded even to an authorization server that would accept it. It
fails without the change.
@guglielmo-san
guglielmo-san enabled auto-merge (squash) October 26, 2026 14:12
@guglielmo-san
guglielmo-san merged commit 6f47cb7 into modelcontextprotocol:main Oct 26, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants