Skip to content

Commit 9348d33

Browse files
oauthex: move internal/oauthex to oauthex (#559)
This PR relocates oauthex and moves DCR logic into dcr.go. Fixes #558
1 parent 547b5c1 commit 9348d33

File tree

11 files changed

+272
-239
lines changed

11 files changed

+272
-239
lines changed

auth/client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"net/http"
1313
"sync"
1414

15-
"github.com/modelcontextprotocol/go-sdk/internal/oauthex"
15+
"github.com/modelcontextprotocol/go-sdk/oauthex"
1616
"golang.org/x/oauth2"
1717
)
1818

oauthex/auth_meta.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// Copyright 2025 The Go MCP SDK Authors. All rights reserved.
2+
// Use of this source code is governed by an MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
// This file implements Authorization Server Metadata.
6+
// See https://www.rfc-editor.org/rfc/rfc8414.html.
7+
8+
//go:build mcp_go_client_oauth
9+
10+
package oauthex
11+
12+
import (
13+
"context"
14+
"errors"
15+
"fmt"
16+
"net/http"
17+
)
18+
19+
// AuthServerMeta represents the metadata for an OAuth 2.0 authorization server,
20+
// as defined in [RFC 8414].
21+
//
22+
// Not supported:
23+
// - signed metadata
24+
//
25+
// [RFC 8414]: https://tools.ietf.org/html/rfc8414)
26+
type AuthServerMeta struct {
27+
// GENERATED BY GEMINI 2.5.
28+
29+
// Issuer is the REQUIRED URL identifying the authorization server.
30+
Issuer string `json:"issuer"`
31+
32+
// AuthorizationEndpoint is the REQUIRED URL of the server's OAuth 2.0 authorization endpoint.
33+
AuthorizationEndpoint string `json:"authorization_endpoint"`
34+
35+
// TokenEndpoint is the REQUIRED URL of the server's OAuth 2.0 token endpoint.
36+
TokenEndpoint string `json:"token_endpoint"`
37+
38+
// JWKSURI is the REQUIRED URL of the server's JSON Web Key Set [JWK] document.
39+
JWKSURI string `json:"jwks_uri"`
40+
41+
// RegistrationEndpoint is the RECOMMENDED URL of the server's OAuth 2.0 Dynamic Client Registration endpoint.
42+
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
43+
44+
// ScopesSupported is a RECOMMENDED JSON array of strings containing a list of the OAuth 2.0
45+
// "scope" values that this server supports.
46+
ScopesSupported []string `json:"scopes_supported,omitempty"`
47+
48+
// ResponseTypesSupported is a REQUIRED JSON array of strings containing a list of the OAuth 2.0
49+
// "response_type" values that this server supports.
50+
ResponseTypesSupported []string `json:"response_types_supported"`
51+
52+
// ResponseModesSupported is a RECOMMENDED JSON array of strings containing a list of the OAuth 2.0
53+
// "response_mode" values that this server supports.
54+
ResponseModesSupported []string `json:"response_modes_supported,omitempty"`
55+
56+
// GrantTypesSupported is a RECOMMENDED JSON array of strings containing a list of the OAuth 2.0
57+
// grant type values that this server supports.
58+
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
59+
60+
// TokenEndpointAuthMethodsSupported is a RECOMMENDED JSON array of strings containing a list of
61+
// client authentication methods supported by this token endpoint.
62+
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
63+
64+
// TokenEndpointAuthSigningAlgValuesSupported is a RECOMMENDED JSON array of strings containing
65+
// a list of the JWS signing algorithms ("alg" values) supported by the token endpoint for
66+
// the signature on the JWT used to authenticate the client.
67+
TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
68+
69+
// ServiceDocumentation is a RECOMMENDED URL of a page containing human-readable documentation
70+
// for the service.
71+
ServiceDocumentation string `json:"service_documentation,omitempty"`
72+
73+
// UILocalesSupported is a RECOMMENDED JSON array of strings representing supported
74+
// BCP47 [RFC5646] language tag values for display in the user interface.
75+
UILocalesSupported []string `json:"ui_locales_supported,omitempty"`
76+
77+
// OpPolicyURI is a RECOMMENDED URL that the server provides to the person registering
78+
// the client to read about the server's operator policies.
79+
OpPolicyURI string `json:"op_policy_uri,omitempty"`
80+
81+
// OpTOSURI is a RECOMMENDED URL that the server provides to the person registering the
82+
// client to read about the server's terms of service.
83+
OpTOSURI string `json:"op_tos_uri,omitempty"`
84+
85+
// RevocationEndpoint is a RECOMMENDED URL of the server's OAuth 2.0 revocation endpoint.
86+
RevocationEndpoint string `json:"revocation_endpoint,omitempty"`
87+
88+
// RevocationEndpointAuthMethodsSupported is a RECOMMENDED JSON array of strings containing
89+
// a list of client authentication methods supported by this revocation endpoint.
90+
RevocationEndpointAuthMethodsSupported []string `json:"revocation_endpoint_auth_methods_supported,omitempty"`
91+
92+
// RevocationEndpointAuthSigningAlgValuesSupported is a RECOMMENDED JSON array of strings
93+
// containing a list of the JWS signing algorithms ("alg" values) supported by the revocation
94+
// endpoint for the signature on the JWT used to authenticate the client.
95+
RevocationEndpointAuthSigningAlgValuesSupported []string `json:"revocation_endpoint_auth_signing_alg_values_supported,omitempty"`
96+
97+
// IntrospectionEndpoint is a RECOMMENDED URL of the server's OAuth 2.0 introspection endpoint.
98+
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"`
99+
100+
// IntrospectionEndpointAuthMethodsSupported is a RECOMMENDED JSON array of strings containing
101+
// a list of client authentication methods supported by this introspection endpoint.
102+
IntrospectionEndpointAuthMethodsSupported []string `json:"introspection_endpoint_auth_methods_supported,omitempty"`
103+
104+
// IntrospectionEndpointAuthSigningAlgValuesSupported is a RECOMMENDED JSON array of strings
105+
// containing a list of the JWS signing algorithms ("alg" values) supported by the introspection
106+
// endpoint for the signature on the JWT used to authenticate the client.
107+
IntrospectionEndpointAuthSigningAlgValuesSupported []string `json:"introspection_endpoint_auth_signing_alg_values_supported,omitempty"`
108+
109+
// CodeChallengeMethodsSupported is a RECOMMENDED JSON array of strings containing a list of
110+
// PKCE code challenge methods supported by this authorization server.
111+
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
112+
}
113+
114+
var wellKnownPaths = []string{
115+
"/.well-known/oauth-authorization-server",
116+
"/.well-known/openid-configuration",
117+
}
118+
119+
// GetAuthServerMeta issues a GET request to retrieve authorization server metadata
120+
// from an OAuth authorization server with the given issuerURL.
121+
//
122+
// It follows [RFC 8414]:
123+
// - The well-known paths specified there are inserted into the URL's path, one at time.
124+
// The first to succeed is used.
125+
// - The Issuer field is checked against issuerURL.
126+
//
127+
// [RFC 8414]: https://tools.ietf.org/html/rfc8414
128+
func GetAuthServerMeta(ctx context.Context, issuerURL string, c *http.Client) (*AuthServerMeta, error) {
129+
var errs []error
130+
for _, p := range wellKnownPaths {
131+
u, err := prependToPath(issuerURL, p)
132+
if err != nil {
133+
// issuerURL is bad; no point in continuing.
134+
return nil, err
135+
}
136+
asm, err := getJSON[AuthServerMeta](ctx, c, u, 1<<20)
137+
if err == nil {
138+
if asm.Issuer != issuerURL { // section 3.3
139+
// Security violation; don't keep trying.
140+
return nil, fmt.Errorf("metadata issuer %q does not match issuer URL %q", asm.Issuer, issuerURL)
141+
}
142+
return asm, nil
143+
}
144+
errs = append(errs, err)
145+
}
146+
return nil, fmt.Errorf("failed to get auth server metadata from %q: %w", issuerURL, errors.Join(errs...))
147+
}

oauthex/auth_meta_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2025 The Go MCP SDK Authors. All rights reserved.
2+
// Use of this source code is governed by an MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build mcp_go_client_oauth
6+
7+
package oauthex
8+
9+
import (
10+
"encoding/json"
11+
"os"
12+
"path/filepath"
13+
"testing"
14+
)
15+
16+
func TestAuthMetaParse(t *testing.T) {
17+
// Verify that we parse Google's auth server metadata.
18+
data, err := os.ReadFile(filepath.FromSlash("testdata/google-auth-meta.json"))
19+
if err != nil {
20+
t.Fatal(err)
21+
}
22+
var a AuthServerMeta
23+
if err := json.Unmarshal(data, &a); err != nil {
24+
t.Fatal(err)
25+
}
26+
// Spot check.
27+
if g, w := a.Issuer, "https://accounts.google.com"; g != w {
28+
t.Errorf("got %q, want %q", g, w)
29+
}
30+
}

internal/oauthex/auth_meta.go renamed to oauthex/dcr.go

Lines changed: 2 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -5,114 +5,20 @@
55
// This file implements Authorization Server Metadata.
66
// See https://www.rfc-editor.org/rfc/rfc8414.html.
77

8+
//go:build mcp_go_client_oauth
9+
810
package oauthex
911

1012
import (
1113
"bytes"
1214
"context"
1315
"encoding/json"
14-
"errors"
1516
"fmt"
1617
"io"
1718
"net/http"
1819
"time"
1920
)
2021

21-
// AuthServerMeta represents the metadata for an OAuth 2.0 authorization server,
22-
// as defined in [RFC 8414].
23-
//
24-
// Not supported:
25-
// - signed metadata
26-
//
27-
// [RFC 8414]: https://tools.ietf.org/html/rfc8414)
28-
type AuthServerMeta struct {
29-
// GENERATED BY GEMINI 2.5.
30-
31-
// Issuer is the REQUIRED URL identifying the authorization server.
32-
Issuer string `json:"issuer"`
33-
34-
// AuthorizationEndpoint is the REQUIRED URL of the server's OAuth 2.0 authorization endpoint.
35-
AuthorizationEndpoint string `json:"authorization_endpoint"`
36-
37-
// TokenEndpoint is the REQUIRED URL of the server's OAuth 2.0 token endpoint.
38-
TokenEndpoint string `json:"token_endpoint"`
39-
40-
// JWKSURI is the REQUIRED URL of the server's JSON Web Key Set [JWK] document.
41-
JWKSURI string `json:"jwks_uri"`
42-
43-
// RegistrationEndpoint is the RECOMMENDED URL of the server's OAuth 2.0 Dynamic Client Registration endpoint.
44-
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
45-
46-
// ScopesSupported is a RECOMMENDED JSON array of strings containing a list of the OAuth 2.0
47-
// "scope" values that this server supports.
48-
ScopesSupported []string `json:"scopes_supported,omitempty"`
49-
50-
// ResponseTypesSupported is a REQUIRED JSON array of strings containing a list of the OAuth 2.0
51-
// "response_type" values that this server supports.
52-
ResponseTypesSupported []string `json:"response_types_supported"`
53-
54-
// ResponseModesSupported is a RECOMMENDED JSON array of strings containing a list of the OAuth 2.0
55-
// "response_mode" values that this server supports.
56-
ResponseModesSupported []string `json:"response_modes_supported,omitempty"`
57-
58-
// GrantTypesSupported is a RECOMMENDED JSON array of strings containing a list of the OAuth 2.0
59-
// grant type values that this server supports.
60-
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
61-
62-
// TokenEndpointAuthMethodsSupported is a RECOMMENDED JSON array of strings containing a list of
63-
// client authentication methods supported by this token endpoint.
64-
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
65-
66-
// TokenEndpointAuthSigningAlgValuesSupported is a RECOMMENDED JSON array of strings containing
67-
// a list of the JWS signing algorithms ("alg" values) supported by the token endpoint for
68-
// the signature on the JWT used to authenticate the client.
69-
TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
70-
71-
// ServiceDocumentation is a RECOMMENDED URL of a page containing human-readable documentation
72-
// for the service.
73-
ServiceDocumentation string `json:"service_documentation,omitempty"`
74-
75-
// UILocalesSupported is a RECOMMENDED JSON array of strings representing supported
76-
// BCP47 [RFC5646] language tag values for display in the user interface.
77-
UILocalesSupported []string `json:"ui_locales_supported,omitempty"`
78-
79-
// OpPolicyURI is a RECOMMENDED URL that the server provides to the person registering
80-
// the client to read about the server's operator policies.
81-
OpPolicyURI string `json:"op_policy_uri,omitempty"`
82-
83-
// OpTOSURI is a RECOMMENDED URL that the server provides to the person registering the
84-
// client to read about the server's terms of service.
85-
OpTOSURI string `json:"op_tos_uri,omitempty"`
86-
87-
// RevocationEndpoint is a RECOMMENDED URL of the server's OAuth 2.0 revocation endpoint.
88-
RevocationEndpoint string `json:"revocation_endpoint,omitempty"`
89-
90-
// RevocationEndpointAuthMethodsSupported is a RECOMMENDED JSON array of strings containing
91-
// a list of client authentication methods supported by this revocation endpoint.
92-
RevocationEndpointAuthMethodsSupported []string `json:"revocation_endpoint_auth_methods_supported,omitempty"`
93-
94-
// RevocationEndpointAuthSigningAlgValuesSupported is a RECOMMENDED JSON array of strings
95-
// containing a list of the JWS signing algorithms ("alg" values) supported by the revocation
96-
// endpoint for the signature on the JWT used to authenticate the client.
97-
RevocationEndpointAuthSigningAlgValuesSupported []string `json:"revocation_endpoint_auth_signing_alg_values_supported,omitempty"`
98-
99-
// IntrospectionEndpoint is a RECOMMENDED URL of the server's OAuth 2.0 introspection endpoint.
100-
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"`
101-
102-
// IntrospectionEndpointAuthMethodsSupported is a RECOMMENDED JSON array of strings containing
103-
// a list of client authentication methods supported by this introspection endpoint.
104-
IntrospectionEndpointAuthMethodsSupported []string `json:"introspection_endpoint_auth_methods_supported,omitempty"`
105-
106-
// IntrospectionEndpointAuthSigningAlgValuesSupported is a RECOMMENDED JSON array of strings
107-
// containing a list of the JWS signing algorithms ("alg" values) supported by the introspection
108-
// endpoint for the signature on the JWT used to authenticate the client.
109-
IntrospectionEndpointAuthSigningAlgValuesSupported []string `json:"introspection_endpoint_auth_signing_alg_values_supported,omitempty"`
110-
111-
// CodeChallengeMethodsSupported is a RECOMMENDED JSON array of strings containing a list of
112-
// PKCE code challenge methods supported by this authorization server.
113-
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
114-
}
115-
11622
// ClientRegistrationMetadata represents the client metadata fields for the DCR POST request (RFC 7591).
11723
type ClientRegistrationMetadata struct {
11824
// RedirectURIs is a REQUIRED JSON array of redirection URI strings for use in
@@ -260,41 +166,6 @@ func (e *ClientRegistrationError) Error() string {
260166
return fmt.Sprintf("registration failed: %s (%s)", e.ErrorCode, e.ErrorDescription)
261167
}
262168

263-
var wellKnownPaths = []string{
264-
"/.well-known/oauth-authorization-server",
265-
"/.well-known/openid-configuration",
266-
}
267-
268-
// GetAuthServerMeta issues a GET request to retrieve authorization server metadata
269-
// from an OAuth authorization server with the given issuerURL.
270-
//
271-
// It follows [RFC 8414]:
272-
// - The well-known paths specified there are inserted into the URL's path, one at time.
273-
// The first to succeed is used.
274-
// - The Issuer field is checked against issuerURL.
275-
//
276-
// [RFC 8414]: https://tools.ietf.org/html/rfc8414
277-
func GetAuthServerMeta(ctx context.Context, issuerURL string, c *http.Client) (*AuthServerMeta, error) {
278-
var errs []error
279-
for _, p := range wellKnownPaths {
280-
u, err := prependToPath(issuerURL, p)
281-
if err != nil {
282-
// issuerURL is bad; no point in continuing.
283-
return nil, err
284-
}
285-
asm, err := getJSON[AuthServerMeta](ctx, c, u, 1<<20)
286-
if err == nil {
287-
if asm.Issuer != issuerURL { // section 3.3
288-
// Security violation; don't keep trying.
289-
return nil, fmt.Errorf("metadata issuer %q does not match issuer URL %q", asm.Issuer, issuerURL)
290-
}
291-
return asm, nil
292-
}
293-
errs = append(errs, err)
294-
}
295-
return nil, fmt.Errorf("failed to get auth server metadata from %q: %w", issuerURL, errors.Join(errs...))
296-
}
297-
298169
// RegisterClient performs Dynamic Client Registration according to RFC 7591.
299170
func RegisterClient(ctx context.Context, registrationEndpoint string, clientMeta *ClientRegistrationMetadata, c *http.Client) (*ClientRegistrationResponse, error) {
300171
if registrationEndpoint == "" {

internal/oauthex/auth_meta_test.go renamed to oauthex/dcr_test.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by an MIT-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build mcp_go_client_oauth
6+
57
package oauthex
68

79
import (
@@ -19,22 +21,6 @@ import (
1921
"github.com/google/go-cmp/cmp"
2022
)
2123

22-
func TestAuthMetaParse(t *testing.T) {
23-
// Verify that we parse Google's auth server metadata.
24-
data, err := os.ReadFile(filepath.FromSlash("testdata/google-auth-meta.json"))
25-
if err != nil {
26-
t.Fatal(err)
27-
}
28-
var a AuthServerMeta
29-
if err := json.Unmarshal(data, &a); err != nil {
30-
t.Fatal(err)
31-
}
32-
// Spot check.
33-
if g, w := a.Issuer, "https://accounts.google.com"; g != w {
34-
t.Errorf("got %q, want %q", g, w)
35-
}
36-
}
37-
3824
func TestClientRegistrationMetadataParse(t *testing.T) {
3925
// Verify that we can parse a typical client metadata JSON.
4026
data, err := os.ReadFile(filepath.FromSlash("testdata/client-auth-meta.json"))

internal/oauthex/oauth2.go renamed to oauthex/oauth2.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
// license that can be found in the LICENSE file.
44

55
// Package oauthex implements extensions to OAuth2.
6+
7+
//go:build mcp_go_client_oauth
8+
69
package oauthex
710

811
import (

internal/oauthex/oauth2_test.go renamed to oauthex/oauth2_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by an MIT-style
33
// license that can be found in the LICENSE file.
44

5+
//go:build mcp_go_client_oauth
6+
57
package oauthex
68

79
import (

0 commit comments

Comments
 (0)