Documentation
¶
Overview ¶
Package oauth provides small, composable OAuth 2.0/2.1 primitives used by AppTheory components (e.g. Remote MCP protected resources) and by Autheory (an OAuth Authorization Server built on AppTheory).
The package intentionally focuses on wire-level helpers: - RFC9728 protected resource discovery (WWW-Authenticate + metadata) - RFC8414 authorization server metadata helpers - RFC7591 Dynamic Client Registration request/response types + validation - PKCE utilities
Index ¶
- Constants
- Variables
- func AuthorizationServerMetadataHandler(md *AuthorizationServerMetadata) apptheory.Handler
- func BearerTokenFromHeaders(headers map[string][]string) (string, error)
- func CanonicalResourceURL(raw string) string
- func CanonicalizeIssuerURL(raw string) (string, bool)
- func NewOpaqueToken() (string, error)
- func NewPKCECodeVerifier() (string, error)
- func PKCEChallengeS256(verifier string) (string, error)
- func PKCEVerifyS256(verifier, expectedChallenge string) (bool, error)
- func ProtectedResourceMetadataHandler(md *ProtectedResourceMetadata) apptheory.Handler
- func ProtectedResourceMetadataURLForRequest(headers map[string][]string) (string, bool)
- func ProtectedResourceWWWAuthenticate(resourceMetadataURL string) string
- func RequireBearerTokenMiddleware(opts RequireBearerTokenOptions) apptheory.Middleware
- func ResourceMetadataURLFromMcpEndpoint(mcpEndpoint string) (string, bool)
- func ValidateDynamicClientRegistrationRequest(req *DynamicClientRegistrationRequest, policy DynamicClientRegistrationPolicy) error
- func ValidatePKCECodeVerifier(verifier string) error
- type AuthorizationCodeRecord
- type AuthorizationCodeStore
- type AuthorizationServerMetadata
- type BearerTokenValidator
- type DynamicClientRegistrationPolicy
- type DynamicClientRegistrationRequest
- type DynamicClientRegistrationResponse
- type MemoryAuthorizationCodeStore
- type MemoryRefreshTokenStore
- func (s *MemoryRefreshTokenStore) Consume(_ context.Context, token string) (*RefreshTokenRecord, error)
- func (s *MemoryRefreshTokenStore) Delete(_ context.Context, token string) error
- func (s *MemoryRefreshTokenStore) Get(_ context.Context, token string) (*RefreshTokenRecord, error)
- func (s *MemoryRefreshTokenStore) Put(_ context.Context, rec *RefreshTokenRecord) error
- type ProtectedResourceMetadata
- type RefreshTokenRecord
- type RefreshTokenStore
- type RequireBearerTokenOptions
Constants ¶
const ContextKeyBearerToken = "oauth.bearer_token" //nolint:gosec // context key, not a credential
ContextKeyBearerToken is set on apptheory.Context by RequireBearerTokenMiddleware.
Variables ¶
var ( // ErrMissingBearerToken is returned when an Authorization header is missing. ErrMissingBearerToken = errors.New("missing bearer token") // ErrInvalidAuthorizationHeader is returned when the Authorization header cannot be parsed as Bearer. ErrInvalidAuthorizationHeader = errors.New("invalid authorization header") // ErrInvalidURL is returned when a required URL is not a valid absolute URL. ErrInvalidURL = errors.New("invalid url") // ErrAuthorizationCodeNotFound indicates an unknown/consumed authorization code. ErrAuthorizationCodeNotFound = errors.New("authorization code not found") // ErrAuthorizationCodeExpired indicates an expired authorization code. ErrAuthorizationCodeExpired = errors.New("authorization code expired") // ErrRefreshTokenNotFound indicates an unknown/revoked refresh token. ErrRefreshTokenNotFound = errors.New("refresh token not found") // ErrRefreshTokenExpired indicates an expired refresh token. ErrRefreshTokenExpired = errors.New("refresh token expired") )
Functions ¶
func AuthorizationServerMetadataHandler ¶
func AuthorizationServerMetadataHandler(md *AuthorizationServerMetadata) apptheory.Handler
AuthorizationServerMetadataHandler returns an AppTheory handler that serves the RFC8414 authorization server metadata document.
func BearerTokenFromHeaders ¶
BearerTokenFromHeaders extracts the bearer token from normalized headers.
func CanonicalResourceURL ¶
CanonicalResourceURL trims whitespace and a trailing slash.
func CanonicalizeIssuerURL ¶
CanonicalizeIssuerURL trims trailing slashes from an issuer/base URL.
func NewOpaqueToken ¶
NewOpaqueToken generates a URL-safe opaque token suitable for authorization codes and refresh tokens.
func NewPKCECodeVerifier ¶
NewPKCECodeVerifier generates a random PKCE code verifier (length ~43).
func PKCEChallengeS256 ¶
PKCEChallengeS256 computes the S256 code challenge for a verifier.
func PKCEVerifyS256 ¶
PKCEVerifyS256 verifies a verifier matches an expected S256 challenge.
func ProtectedResourceMetadataHandler ¶
func ProtectedResourceMetadataHandler(md *ProtectedResourceMetadata) apptheory.Handler
ProtectedResourceMetadataHandler returns an AppTheory handler that serves the RFC9728 protected resource metadata document.
func ProtectedResourceMetadataURLForRequest ¶
ProtectedResourceMetadataURLForRequest attempts to derive an absolute `/.well-known/oauth-protected-resource` URL from common proxy headers.
Prefer using ResourceMetadataURLFromMcpEndpoint with MCP_ENDPOINT for AWS deployments; this helper is primarily for local/test environments.
func ProtectedResourceWWWAuthenticate ¶
ProtectedResourceWWWAuthenticate builds the RFC9728 MCP-style discovery challenge.
Example:
Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource"
func RequireBearerTokenMiddleware ¶
func RequireBearerTokenMiddleware(opts RequireBearerTokenOptions) apptheory.Middleware
RequireBearerTokenMiddleware enforces `Authorization: Bearer <token>` and, when missing/invalid, returns 401 with the MCP 2025-06-18 compatible WWW-Authenticate challenge that points to protected resource metadata.
func ResourceMetadataURLFromMcpEndpoint ¶
ResourceMetadataURLFromMcpEndpoint derives the protected resource metadata URL from an MCP endpoint URL (which must end with `/mcp`).
For example:
https://api.example.com/prod/mcp -> https://api.example.com/prod/.well-known/oauth-protected-resource
func ValidateDynamicClientRegistrationRequest ¶
func ValidateDynamicClientRegistrationRequest(req *DynamicClientRegistrationRequest, policy DynamicClientRegistrationPolicy) error
ValidateDynamicClientRegistrationRequest validates an RFC7591 request against a policy.
func ValidatePKCECodeVerifier ¶
ValidatePKCECodeVerifier validates a verifier against RFC7636 constraints.
Types ¶
type AuthorizationCodeRecord ¶
type AuthorizationCodeRecord struct {
Code string
ClientID string
RedirectURI string
Resource string
CodeChallenge string
CodeChallengeMethod string
ExpiresAt time.Time
}
AuthorizationCodeRecord stores the data needed to redeem an authorization code.
type AuthorizationCodeStore ¶
type AuthorizationCodeStore interface {
Put(ctx context.Context, rec *AuthorizationCodeRecord) error
Consume(ctx context.Context, code string) (*AuthorizationCodeRecord, error)
}
AuthorizationCodeStore stores short-lived authorization codes.
type AuthorizationServerMetadata ¶
type AuthorizationServerMetadata struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint,omitempty"`
TokenEndpoint string `json:"token_endpoint,omitempty"`
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
JWKSURI string `json:"jwks_uri,omitempty"`
ResponseTypesSupported []string `json:"response_types_supported,omitempty"`
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
ScopesSupported []string `json:"scopes_supported,omitempty"`
SubjectTypesSupported []string `json:"subject_types_supported,omitempty"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"`
}
AuthorizationServerMetadata is the RFC8414 Authorization Server metadata document.
func NewAuthorizationServerMetadata ¶
func NewAuthorizationServerMetadata(issuer string) (*AuthorizationServerMetadata, error)
NewAuthorizationServerMetadata builds a Claude-compatible RFC8414 document with conventional root endpoints (/authorize, /token, /register) derived from the issuer/base URL.
func (*AuthorizationServerMetadata) MarshalJSONBytes ¶
func (m *AuthorizationServerMetadata) MarshalJSONBytes() ([]byte, error)
MarshalJSONBytes marshals the metadata document to JSON bytes.
type BearerTokenValidator ¶
BearerTokenValidator validates a Bearer access token.
Implementations can perform JWT verification using a JWKS, introspection, or any other mechanism suitable for the deployment.
type DynamicClientRegistrationPolicy ¶
type DynamicClientRegistrationPolicy struct {
AllowedRedirectURIs []string
RequirePublicClient bool // token_endpoint_auth_method must be "none"
RequireRefreshToken bool // grant_types must include "refresh_token" (if grant_types provided)
}
DynamicClientRegistrationPolicy controls DCR validation.
func ClaudeDynamicClientRegistrationPolicy ¶
func ClaudeDynamicClientRegistrationPolicy() DynamicClientRegistrationPolicy
ClaudeDynamicClientRegistrationPolicy returns a day-1 policy compatible with Claude connectors.
type DynamicClientRegistrationRequest ¶
type DynamicClientRegistrationRequest struct {
ClientName string `json:"client_name,omitempty"`
RedirectURIs []string `json:"redirect_uris,omitempty"`
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty"`
GrantTypes []string `json:"grant_types,omitempty"`
ResponseTypes []string `json:"response_types,omitempty"`
Scope string `json:"scope,omitempty"`
}
DynamicClientRegistrationRequest is an RFC7591 client registration request.
type DynamicClientRegistrationResponse ¶
type DynamicClientRegistrationResponse struct {
ClientID string `json:"client_id"`
// ClientSecret is omitted for public clients.
ClientSecret string `json:"client_secret,omitempty"`
ClientIDIssuedAt int64 `json:"client_id_issued_at,omitempty"`
ClientSecretExpiresAt int64 `json:"client_secret_expires_at,omitempty"`
}
DynamicClientRegistrationResponse is a minimal RFC7591 response.
type MemoryAuthorizationCodeStore ¶
type MemoryAuthorizationCodeStore struct {
// contains filtered or unexported fields
}
MemoryAuthorizationCodeStore is an in-memory AuthorizationCodeStore.
func NewMemoryAuthorizationCodeStore ¶
func NewMemoryAuthorizationCodeStore() *MemoryAuthorizationCodeStore
func (*MemoryAuthorizationCodeStore) Consume ¶
func (s *MemoryAuthorizationCodeStore) Consume(_ context.Context, code string) (*AuthorizationCodeRecord, error)
func (*MemoryAuthorizationCodeStore) Put ¶
func (s *MemoryAuthorizationCodeStore) Put(_ context.Context, rec *AuthorizationCodeRecord) error
type MemoryRefreshTokenStore ¶
type MemoryRefreshTokenStore struct {
// contains filtered or unexported fields
}
MemoryRefreshTokenStore is an in-memory RefreshTokenStore.
func NewMemoryRefreshTokenStore ¶
func NewMemoryRefreshTokenStore() *MemoryRefreshTokenStore
func (*MemoryRefreshTokenStore) Consume ¶
func (s *MemoryRefreshTokenStore) Consume(_ context.Context, token string) (*RefreshTokenRecord, error)
func (*MemoryRefreshTokenStore) Delete ¶
func (s *MemoryRefreshTokenStore) Delete(_ context.Context, token string) error
func (*MemoryRefreshTokenStore) Get ¶
func (s *MemoryRefreshTokenStore) Get(_ context.Context, token string) (*RefreshTokenRecord, error)
func (*MemoryRefreshTokenStore) Put ¶
func (s *MemoryRefreshTokenStore) Put(_ context.Context, rec *RefreshTokenRecord) error
type ProtectedResourceMetadata ¶
type ProtectedResourceMetadata struct {
Resource string `json:"resource"`
AuthorizationServers []string `json:"authorization_servers"`
JWKSURI string `json:"jwks_uri,omitempty"`
ScopesSupported []string `json:"scopes_supported,omitempty"`
BearerMethodsSupported []string `json:"bearer_methods_supported,omitempty"`
}
ProtectedResourceMetadata is the RFC9728 discovery document hosted by a protected resource server.
func NewProtectedResourceMetadata ¶
func NewProtectedResourceMetadata(resource string, authorizationServers []string) (*ProtectedResourceMetadata, error)
NewProtectedResourceMetadata creates a minimal metadata document. It requires: - resource: an absolute URL that identifies the protected resource (for MCP this is typically the `/mcp` endpoint) - authorizationServers: one or more OAuth AS issuer/base URLs
func (*ProtectedResourceMetadata) MarshalJSONBytes ¶
func (m *ProtectedResourceMetadata) MarshalJSONBytes() ([]byte, error)
MarshalJSONBytes marshals the metadata document to JSON bytes.
type RefreshTokenRecord ¶
type RefreshTokenRecord struct {
Token string
ClientID string
Subject string
Resource string
ExpiresAt time.Time
}
RefreshTokenRecord stores long-lived refresh token state.
type RefreshTokenStore ¶
type RefreshTokenStore interface {
Put(ctx context.Context, rec *RefreshTokenRecord) error
Get(ctx context.Context, token string) (*RefreshTokenRecord, error)
Consume(ctx context.Context, token string) (*RefreshTokenRecord, error)
Delete(ctx context.Context, token string) error
}
RefreshTokenStore stores refresh tokens. Implementations should support rotation by Consume+Put.
type RequireBearerTokenOptions ¶
type RequireBearerTokenOptions struct {
// ResourceMetadataURL is used to build the RFC9728 discovery challenge.
//
// If empty, the middleware attempts to derive it from MCP_ENDPOINT, and then
// from request headers (Host + X-Forwarded-Proto) as a last resort.
ResourceMetadataURL string
// Validator, when provided, is called for every request. If it returns an
// error the request is rejected with 401.
Validator BearerTokenValidator
}
RequireBearerTokenOptions configures RequireBearerTokenMiddleware.