Commit graph go-sdk/auth/shared_test.go
Author SHA1 Message Date
Max Freedom Pollard
5bc078a795
auth: strip a terminating slash from the issuer before building metadata URLs (#1245)
An issuer identifier written with a terminating slash, like
`https://auth.example.com/`, makes authorization server metadata
discovery miss every endpoint. `GetAuthServerMetadata` probes three URLs
that no conformant server serves, finds nothing, and the caller falls
back to the guessed 2025-03-26 endpoints, which are themselves malformed
because they are built by appending to the same slash-terminated issuer.

`authorizationServerMetadataURLs` in `auth/shared.go` decides whether
the issuer has a path component with `baseURL.Path == ""` (line 47), and
a trailing-slash issuer has `Path == "/"`, so it takes the
path-insertion branch. That branch inserts
`strings.TrimLeft(originalPath, "/")` (lines 59 and 62), which strips
the leading slash but keeps the trailing one. For
`https://auth.example.com/` the probes come out as
`/.well-known/oauth-authorization-server/`,
`/.well-known/openid-configuration/` and
`//.well-known/openid-configuration`. For
`https://auth.example.com/tenant1/` the two path-insertion probes come
out with a trailing slash. Only the path-appending form was already
right, because it uses `strings.Trim`.

RFC 8414 section 3.1 settles it: "If the issuer identifier value
contains a path component, any terminating "/" MUST be removed before
inserting "/.well-known/" and the well-known URI suffix between the host
component and the path component." So `https://auth.example.com/` has no
path component and gets the two root forms, which is the list the MCP
authorization spec gives for issuers without a path component.

The change trims slashes off both ends of the issuer path once, uses
that to pick between the root and path-insertion branches, and reuses it
for all three URLs. An issuer without a terminating slash produces
exactly the same list as before.

`TestAuthorizationServerMetadataURLs` pins the URL list for all four
issuer shapes. `TestGetAuthServerMetadataTrailingSlashIssuer` drives the
whole lookup against the existing fake authorization server, serving
metadata at the root well-known path. On unmodified main the first fails
on both trailing-slash cases and the second fails with
`GetAuthServerMetadata() error = Get
"/.well-known/openid-configuration": redirect into loopback address
"127.0.0.1"`, because `//.well-known/openid-configuration` makes
`net/http.ServeMux` issue a canonicalizing redirect that the discovery
client's `CheckRedirect` refuses. Both pass with the change.

Verification on go1.26.4: `gofmt -l .` clean, `go vet ./...` clean,
`staticcheck ./...` clean at v0.6.1 (the version the Test workflow
pins), `go test ./auth/...` ok, `go test ./...` ok.

I did not file an issue first. The fix is self-contained, confined to
one unexported helper, and every issuer shape other than the
slash-terminated ones is byte-identical to before.

Co-authored-by: Guglielmo Colombo <guglielmoc@google.com>
2026-09-07 09:31:45 +00:00
Maciej Kisiel
638d404e0d
all: stabilize client OAuth support (#861)
Also fix lint errors that were hidden because of the build tag.
2026-03-31 12:36:31 +02:00
Pranav RK
2d43865b97
Enterprise managed authorization (#770)
`auth`, `oauthex`: implement Enterprise Managed Authorization (SEP-990)
This PR implements Enterprise Managed Authorization (SEP-990) for the Go
MCP SDK, enabling MCP Clients and Servers to leverage enterprise
Identity Providers for seamless authorization without requiring users to
authenticate separately to each MCP Server.
 Overview
Enterprise Managed Authorization follows the Identity Assertion
Authorization Grant specification
(draft-ietf-oauth-identity-assertion-authz-grant), implementing a
three-step flow:
1. **Single Sign-On (SSO)**: User authenticates to the MCP Client via
enterprise IdP (Okta, Auth0, Azure AD, etc.)
2. **Token Exchange (RFC 8693)**: Client exchanges ID Token for Identity
Assertion JWT Authorization Grant (ID-JAG) at the IdP
3. **JWT Bearer Grant (RFC 7523)**: Client exchanges ID-JAG for Access
Token at the MCP Server
This enables:
- **For end users**: Single sign-on across MCP Clients and Servers—no
manual connection/authorization per server
- **For enterprise admins**: Centralized visibility and control over
which MCP Servers can be used within the organization
- **For MCP clients**: Automatic token acquisition without user
interaction for each server

Closes:
[#628](https://github.com/modelcontextprotocol/go-sdk/issues/628)

---------

Co-authored-by: Maciej Kisiel <mkisiel@google.com>
2026-03-30 16:29:30 +02:00