`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>
59 lines
2 KiB
Go
59 lines
2 KiB
Go
// Copyright 2026 The Go MCP SDK Authors. All rights reserved.
|
|
// Use of this source code is governed by an MIT-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
//go:build mcp_go_client_oauth
|
|
|
|
package oauthex
|
|
|
|
import "errors"
|
|
|
|
// ClientCredentials holds client authentication credentials for OAuth token requests.
|
|
// It supports multiple authentication methods, but only one method should be set at a time.
|
|
// Use the Validate method to ensure proper configuration.
|
|
type ClientCredentials struct {
|
|
// ClientID is the OAuth2 client identifier.
|
|
// REQUIRED for all authentication methods.
|
|
ClientID string
|
|
|
|
// ClientSecretAuth configures client authentication using a client secret.
|
|
// This is the most common authentication method for confidential clients.
|
|
// OPTIONAL. If not provided, the client is treated as a public client.
|
|
ClientSecretAuth *ClientSecretAuth
|
|
}
|
|
|
|
// ClientSecretAuth holds client secret authentication credentials.
|
|
// This authentication method supports both "client_secret_basic" and "client_secret_post"
|
|
// methods as defined in RFC 6749 Section 2.3.1.
|
|
type ClientSecretAuth struct {
|
|
// ClientSecret is the OAuth2 client secret for confidential clients.
|
|
// REQUIRED when using ClientSecretAuth.
|
|
ClientSecret string
|
|
}
|
|
|
|
// Validate checks that the ClientCredentials are properly configured.
|
|
// It ensures that:
|
|
// - ClientID is not empty.
|
|
// - At most one authentication method is configured.
|
|
// - If ClientSecretAuth is set, ClientSecret is not empty.
|
|
func (c *ClientCredentials) Validate() error {
|
|
if c.ClientID == "" {
|
|
return errors.New("ClientID is required")
|
|
}
|
|
|
|
// Count how many auth methods are configured.
|
|
authMethodCount := 0
|
|
if c.ClientSecretAuth != nil {
|
|
authMethodCount++
|
|
if c.ClientSecretAuth.ClientSecret == "" {
|
|
return errors.New("ClientSecret is required when using ClientSecretAuth")
|
|
}
|
|
}
|
|
|
|
// Allow zero auth methods (public client) or exactly one auth method.
|
|
if authMethodCount > 1 {
|
|
return errors.New("only one client authentication method can be configured")
|
|
}
|
|
|
|
return nil
|
|
}
|