Skip to content

mcp: add client-side OAuth flow (preliminary) #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

jba
Copy link
Contributor

@jba jba commented Jul 25, 2025

This is a preliminary implementation of OAuth 2.1 for the client.

When a StreamableClientTransport encounters a 401 Unauthorized response
from the server, it initiates the OAuth flow described in thec
authorization section of the MCP spec
(https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization).
On success, the transport obtains an access token which it passes
to all subsequent requests.

Much remains to be done here:

  • Dynamic client registration is not implemented. Since it is optional,
    we also need another way of supplying the client ID and secret to
    this code.

  • Resource Indicators, as described in section 2.5.1 of the MCP spec.

  • There is no way for the user to provide a redirect URL.

  • All of this is unexported, so it is available only to our own
    StreamingClientTransport. We should add API so people can use it
    with their own transports.

  • And, of course, tests. We should test against fake implementations
    but also, if we can find any, real reference implementations.

@jba
Copy link
Contributor Author

jba commented Jul 25, 2025

Ignore the first two commits. They should be in separate PRs.

@jba
Copy link
Contributor Author

jba commented Jul 25, 2025

/cc @RoyceLeonD

@findleyr findleyr self-requested a review July 30, 2025 19:07
@wagnerjt
Copy link

For testing, Google supports DCR and there is an example of Spotify MCP server to include client id and client secret for the fallback here. This was used to support the vscode's client (currently in insider) at the moment to do exactly this fallback mechanism when DCR does not exist at the IDP.

@RoyceLeonD
Copy link

@jba Sorry It took so long for me to be active on this. Will take a deeper look at the code and revert back in the next day or so.

jba added 4 commits August 6, 2025 13:58
Add a package for the extensions to OAuth 2.0 required by MCP.

This first PR adds Protected Resource Metadata.
Implement the Authorization Server Metadata spec.
This is a preliminary implementation of OAuth 2.1 for the client.

When a StreamableClientTransport encounters a 401 Unauthorized response
from the server, it initiates the OAuth flow described in thec
authorization section of the MCP spec
(https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization).
On success, the transport obtains an access token which it passes
to all subsequent requests.

Much remains to be done here:

- Dynamic client registration is not implemented. Since it is optional,
  we also need another way of supplying the client ID and secret to
  this code.

- Resource Indicators, as described in section 2.5.1 of the MCP spec.

- There is no way for the user to provide a redirect URL.

- All of this is unexported, so it is available only to our own
  StreamingClientTransport. We should add API so people can use it
  with their own transports.

- And, of course, tests. We should test against fake implementations
  but also, if we can find any, real reference implementations.
Endpoint: oauth2.Endpoint{
AuthURL: asm.AuthorizationEndpoint,
TokenURL: asm.TokenEndpoint,
// DeviceAuthURL: "",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding auth style should be necessary depending on the server metadata
https://pkg.go.dev/golang.org/x/oauth2#section-readme:~:text=type-,AuthStyle,-%C2%B6

depending on the AS's token_endpoint_auth_methods_supported.


// Get an access token from the auth server.
config := &oauth2.Config{
ClientID: "TODO: from registration",
Copy link

@ramongalate ramongalate Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should add two options, one for passed in client ids/secrets and one for PKCE for public clients, for a more AUTH2.1 compliant solution.

}
// TODO: try more than one?
authServer := prm.AuthorizationServers[0]
// TODO: which scopes to ask for? All of them?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should ask for all the scopes, I think the best solution would be for the client to specify in its options which scopes it wants and validate against the supported ones, failing if not supported.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and we could default to all, if no scope is passed.

// AuthStyle: "from auth meta?",
},
RedirectURL: "", // ???
Scopes: scopes,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you also request openid, it needs to generate and pass a nonce and validate it in the ID Token.

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.

5 participants