mcp: add client-side OAuth flow (#544)
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: * Resource Indicators, as described in section 2.5.1 of the MCP spec. * 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. For #19 Co-authored-by: Jonathan Amsterdam <jba@google.com> --------- Co-authored-by: Jonathan Amsterdam <jba@google.com>
This commit is contained in:
parent
1c3f38f777
commit
069aae16df
1 changed files with 220 additions and 10 deletions
|
|
@ -146,11 +146,11 @@ func GetProtectedResourceMetadataFromHeader(ctx context.Context, header http.Hea
|
|||
if len(headers) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
cs, err := parseWWWAuthenticate(headers)
|
||||
cs, err := ParseWWWAuthenticate(headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
url := resourceMetadataURL(cs)
|
||||
url := ResourceMetadataURL(cs)
|
||||
if url == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
@ -193,9 +193,9 @@ type challenge struct {
|
|||
Params map[string]string
|
||||
}
|
||||
|
||||
// resourceMetadataURL returns a resource metadata URL from the given challenges,
|
||||
// ResourceMetadataURL returns a resource metadata URL from the given challenges,
|
||||
// or the empty string if there is none.
|
||||
func resourceMetadataURL(cs []challenge) string {
|
||||
func ResourceMetadataURL(cs []challenge) string {
|
||||
for _, c := range cs {
|
||||
if u := c.Params["resource_metadata"]; u != "" {
|
||||
return u
|
||||
|
|
@ -204,11 +204,11 @@ func resourceMetadataURL(cs []challenge) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
// parseWWWAuthenticate parses a WWW-Authenticate header string.
|
||||
// ParseWWWAuthenticate parses a WWW-Authenticate header string.
|
||||
// The header format is defined in RFC 9110, Section 11.6.1, and can contain
|
||||
// one or more challenges, separated by commas.
|
||||
// It returns a slice of challenges or an error if one of the headers is malformed.
|
||||
func parseWWWAuthenticate(headers []string) ([]challenge, error) {
|
||||
func ParseWWWAuthenticate(headers []string) ([]challenge, error) {
|
||||
// GENERATED BY GEMINI 2.5 (human-tweaked)
|
||||
var challenges []challenge
|
||||
for _, h := range headers {
|
||||
|
|
|
|||
Loading…
Reference in a new issue