oauth

package
v0.18.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 14, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package oauth provides OAuth 2.1 server capabilities.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrStateNotFound = errors.New("authorization state not found")
)

Errors returned by the OAuth server.

Functions

func BuildAuthorizationURL

func BuildAuthorizationURL(baseURL, clientID, redirectURI, scope, state string) string

BuildAuthorizationURL builds an authorization URL. Uses paths without /oauth prefix for Claude Desktop compatibility.

func GenerateCodeChallenge

func GenerateCodeChallenge(verifier string, method PKCEMethod) (string, error)

GenerateCodeChallenge generates a code challenge from a verifier.

func ValidateCodeChallenge

func ValidateCodeChallenge(challenge string) error

ValidateCodeChallenge validates a code challenge.

func ValidateCodeVerifier

func ValidateCodeVerifier(verifier string) error

ValidateCodeVerifier validates a code verifier. Per RFC 7636, it must be 43-128 characters of [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~".

func VerifyCodeChallenge

func VerifyCodeChallenge(verifier, challenge string, method PKCEMethod) (bool, error)

VerifyCodeChallenge verifies a code verifier against a challenge.

Types

type AuthorizationCode

type AuthorizationCode struct {
	ID            string         `json:"id"`
	Code          string         `json:"code"`
	ClientID      string         `json:"client_id"`
	UserID        string         `json:"user_id"`
	UserClaims    map[string]any `json:"user_claims"`
	CodeChallenge string         `json:"code_challenge"`
	RedirectURI   string         `json:"redirect_uri"`
	Scope         string         `json:"scope"`
	ExpiresAt     time.Time      `json:"expires_at"`
	Used          bool           `json:"used"`
	CreatedAt     time.Time      `json:"created_at"`
}

AuthorizationCode represents an OAuth authorization code.

func (*AuthorizationCode) IsExpired

func (c *AuthorizationCode) IsExpired() bool

IsExpired checks if the authorization code has expired.

type AuthorizationRequest

type AuthorizationRequest struct {
	ResponseType        string
	ClientID            string
	RedirectURI         string
	Scope               string
	State               string
	CodeChallenge       string
	CodeChallengeMethod string
}

AuthorizationRequest represents an authorization request.

type AuthorizationState added in v0.3.0

type AuthorizationState struct {
	// ClientID is the OAuth client's client_id (e.g., Claude Desktop).
	ClientID string

	// RedirectURI is where to send the client after authentication.
	RedirectURI string

	// State is the client's original state parameter.
	State string

	// CodeChallenge is the PKCE challenge from the client.
	CodeChallenge string

	// CodeChallengeMethod is the PKCE method (S256 or plain).
	CodeChallengeMethod string

	// Scope is the requested scope.
	Scope string

	// UpstreamState is the state for the upstream IdP (e.g., Keycloak).
	UpstreamState string

	// PromptNoneAttempted tracks whether we already tried prompt=none
	// for this flow. Used to prevent infinite redirect loops when the
	// upstream IdP returns login_required.
	PromptNoneAttempted bool

	// CreatedAt is when this state was created.
	CreatedAt time.Time
}

AuthorizationState holds state for linking upstream IdP callbacks to original client authorization requests.

type Client

type Client struct {
	ID           string    `json:"id"`
	ClientID     string    `json:"client_id"`
	ClientSecret string    `json:"client_secret"` // bcrypt hashed
	Name         string    `json:"name"`
	RedirectURIs []string  `json:"redirect_uris"`
	GrantTypes   []string  `json:"grant_types"`
	RequirePKCE  bool      `json:"require_pkce"`
	CreatedAt    time.Time `json:"created_at"`
	Active       bool      `json:"active"`
}

Client represents an OAuth 2.1 client.

func (*Client) SupportsGrantType

func (c *Client) SupportsGrantType(grantType string) bool

SupportsGrantType checks if the client supports a grant type.

func (*Client) ValidRedirectURI

func (c *Client) ValidRedirectURI(uri string) bool

ValidRedirectURI checks if a redirect URI is valid for this client. For loopback redirect URIs (127.0.0.1, [::1], localhost), matching follows RFC 8252 Section 7.3: scheme and host must match, but port and path are ignored.

type DCRConfig

type DCRConfig struct {
	// Enabled enables DCR.
	Enabled bool

	// AllowedRedirectPatterns are regex patterns for allowed redirect URIs.
	AllowedRedirectPatterns []string

	// DefaultGrantTypes are the default grant types for new clients.
	DefaultGrantTypes []string

	// RequirePKCE requires PKCE for all clients.
	RequirePKCE bool
}

DCRConfig configures Dynamic Client Registration.

type DCRRequest

type DCRRequest struct {
	ClientName              string   `json:"client_name"`
	RedirectURIs            []string `json:"redirect_uris"`
	GrantTypes              []string `json:"grant_types,omitempty"`
	TokenEndpointAuthMethod string   `json:"token_endpoint_auth_method,omitempty"`
}

DCRRequest is a Dynamic Client Registration request.

type DCRResponse

type DCRResponse struct {
	ClientID              string   `json:"client_id"`
	ClientSecret          string   `json:"client_secret,omitempty"`
	ClientName            string   `json:"client_name"`
	RedirectURIs          []string `json:"redirect_uris"`
	GrantTypes            []string `json:"grant_types"`
	ClientSecretExpiresAt int      `json:"client_secret_expires_at"` // 0 means never
}

DCRResponse is a Dynamic Client Registration response.

type DCRService

type DCRService struct {
	// contains filtered or unexported fields
}

DCRService handles Dynamic Client Registration.

func NewDCRService

func NewDCRService(storage Storage, config DCRConfig) (*DCRService, error)

NewDCRService creates a new DCR service.

func (*DCRService) Register

func (s *DCRService) Register(ctx context.Context, req DCRRequest) (*DCRResponse, error)

Register registers a new OAuth client.

type ErrorResponse

type ErrorResponse struct {
	Error            string `json:"error"`
	ErrorDescription string `json:"error_description,omitempty"`
}

ErrorResponse represents an OAuth error response.

type MemoryStateStore added in v0.3.0

type MemoryStateStore struct {
	// contains filtered or unexported fields
}

MemoryStateStore is an in-memory implementation of StateStore.

func NewMemoryStateStore added in v0.3.0

func NewMemoryStateStore() *MemoryStateStore

NewMemoryStateStore creates a new in-memory state store.

func (*MemoryStateStore) Cleanup added in v0.3.0

func (s *MemoryStateStore) Cleanup(maxAge time.Duration) error

Cleanup removes states older than maxAge.

func (*MemoryStateStore) Delete added in v0.3.0

func (s *MemoryStateStore) Delete(key string) error

Delete removes an authorization state.

func (*MemoryStateStore) Get added in v0.3.0

Get retrieves an authorization state.

func (*MemoryStateStore) Save added in v0.3.0

func (s *MemoryStateStore) Save(key string, state *AuthorizationState) error

Save stores an authorization state.

type MemoryStorage added in v0.3.0

type MemoryStorage struct {
	// contains filtered or unexported fields
}

MemoryStorage is an in-memory implementation of Storage. It is thread-safe and suitable for development/testing. For production, use PostgresStorage.

func NewMemoryStorage added in v0.3.0

func NewMemoryStorage() *MemoryStorage

NewMemoryStorage creates a new in-memory storage.

func (*MemoryStorage) CleanupExpiredCodes added in v0.3.0

func (m *MemoryStorage) CleanupExpiredCodes(_ context.Context) error

CleanupExpiredCodes removes expired authorization codes.

func (*MemoryStorage) CleanupExpiredTokens added in v0.3.0

func (m *MemoryStorage) CleanupExpiredTokens(_ context.Context) error

CleanupExpiredTokens removes expired refresh tokens.

func (*MemoryStorage) CreateClient added in v0.3.0

func (m *MemoryStorage) CreateClient(_ context.Context, client *Client) error

CreateClient stores a new client.

func (*MemoryStorage) DeleteAuthorizationCode added in v0.3.0

func (m *MemoryStorage) DeleteAuthorizationCode(_ context.Context, code string) error

DeleteAuthorizationCode deletes an authorization code.

func (*MemoryStorage) DeleteClient added in v0.3.0

func (m *MemoryStorage) DeleteClient(_ context.Context, clientID string) error

DeleteClient deletes a client.

func (*MemoryStorage) DeleteRefreshToken added in v0.3.0

func (m *MemoryStorage) DeleteRefreshToken(_ context.Context, token string) error

DeleteRefreshToken deletes a refresh token.

func (*MemoryStorage) DeleteRefreshTokensForClient added in v0.3.0

func (m *MemoryStorage) DeleteRefreshTokensForClient(_ context.Context, clientID string) error

DeleteRefreshTokensForClient deletes all refresh tokens for a client.

func (*MemoryStorage) GetAuthorizationCode added in v0.3.0

func (m *MemoryStorage) GetAuthorizationCode(_ context.Context, code string) (*AuthorizationCode, error)

GetAuthorizationCode retrieves an authorization code.

func (*MemoryStorage) GetClient added in v0.3.0

func (m *MemoryStorage) GetClient(_ context.Context, clientID string) (*Client, error)

GetClient retrieves a client by ID.

func (*MemoryStorage) GetRefreshToken added in v0.3.0

func (m *MemoryStorage) GetRefreshToken(_ context.Context, token string) (*RefreshToken, error)

GetRefreshToken retrieves a refresh token.

func (*MemoryStorage) ListClients added in v0.3.0

func (m *MemoryStorage) ListClients(_ context.Context) ([]*Client, error)

ListClients returns all clients.

func (*MemoryStorage) SaveAuthorizationCode added in v0.3.0

func (m *MemoryStorage) SaveAuthorizationCode(_ context.Context, code *AuthorizationCode) error

SaveAuthorizationCode stores an authorization code.

func (*MemoryStorage) SaveRefreshToken added in v0.3.0

func (m *MemoryStorage) SaveRefreshToken(_ context.Context, token *RefreshToken) error

SaveRefreshToken stores a refresh token.

func (*MemoryStorage) UpdateClient added in v0.3.0

func (m *MemoryStorage) UpdateClient(_ context.Context, client *Client) error

UpdateClient updates an existing client.

type PKCEMethod

type PKCEMethod string

PKCEMethod defines the code challenge method.

const (
	// PKCEMethodPlain uses plain text (not recommended).
	PKCEMethodPlain PKCEMethod = "plain"

	// PKCEMethodS256 uses SHA-256 hashing (recommended).
	PKCEMethodS256 PKCEMethod = "S256"
)

func DefaultPKCEMethod

func DefaultPKCEMethod() PKCEMethod

DefaultPKCEMethod returns the default (and recommended) PKCE method.

type RefreshToken

type RefreshToken struct {
	ID         string         `json:"id"`
	Token      string         `json:"token"`
	ClientID   string         `json:"client_id"`
	UserID     string         `json:"user_id"`
	UserClaims map[string]any `json:"user_claims"`
	Scope      string         `json:"scope"`
	ExpiresAt  time.Time      `json:"expires_at"`
	CreatedAt  time.Time      `json:"created_at"`
}

RefreshToken represents an OAuth refresh token.

func (*RefreshToken) IsExpired

func (t *RefreshToken) IsExpired() bool

IsExpired checks if the refresh token has expired.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is an OAuth 2.1 authorization server.

func NewServer

func NewServer(config ServerConfig, storage Storage) (*Server, error)

NewServer creates a new OAuth server.

func (*Server) Authorize

func (s *Server) Authorize(ctx context.Context, req AuthorizationRequest, userID string, userClaims map[string]any) (string, error)

Authorize handles the authorization endpoint.

func (*Server) Issuer added in v0.4.0

func (s *Server) Issuer() string

Issuer returns the OAuth server's issuer URL.

func (*Server) RegisterClient

func (s *Server) RegisterClient(ctx context.Context, req DCRRequest) (*DCRResponse, error)

RegisterClient handles Dynamic Client Registration.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler for the OAuth server. Handles both standard paths (with /oauth prefix) and Claude Desktop compatible paths (without prefix).

func (*Server) SigningKey added in v0.4.0

func (s *Server) SigningKey() []byte

SigningKey returns the OAuth server's signing key. This is needed by the OAuth JWT authenticator to validate tokens.

func (*Server) StartCleanupRoutine

func (s *Server) StartCleanupRoutine(ctx context.Context, interval time.Duration)

StartCleanupRoutine starts a background routine to clean up expired codes and tokens.

func (*Server) Token

func (s *Server) Token(ctx context.Context, req TokenRequest) (*TokenResponse, error)

Token handles the token endpoint.

type ServerConfig

type ServerConfig struct {
	// Issuer is the OAuth issuer URL.
	Issuer string

	// AccessTokenTTL is the access token lifetime.
	AccessTokenTTL time.Duration

	// RefreshTokenTTL is the refresh token lifetime.
	RefreshTokenTTL time.Duration

	// AuthCodeTTL is the authorization code lifetime.
	AuthCodeTTL time.Duration

	// SigningKey is the HMAC key used to sign JWT access tokens.
	// If not provided, tokens will be opaque (not recommended for production).
	// Generate with: openssl rand -base64 32
	SigningKey []byte

	// DCR configures Dynamic Client Registration.
	DCR DCRConfig

	// Upstream configures the upstream identity provider (e.g., Keycloak).
	Upstream *UpstreamConfig
}

ServerConfig configures the OAuth server.

type StateStore added in v0.3.0

type StateStore interface {
	// Save stores an authorization state.
	Save(key string, state *AuthorizationState) error

	// Get retrieves an authorization state.
	Get(key string) (*AuthorizationState, error)

	// Delete removes an authorization state.
	Delete(key string) error

	// Cleanup removes expired states.
	Cleanup(maxAge time.Duration) error
}

StateStore manages authorization states for the OAuth flow.

type Storage

type Storage interface {
	// Client management
	CreateClient(ctx context.Context, client *Client) error
	GetClient(ctx context.Context, clientID string) (*Client, error)
	UpdateClient(ctx context.Context, client *Client) error
	DeleteClient(ctx context.Context, clientID string) error
	ListClients(ctx context.Context) ([]*Client, error)

	// Authorization code management
	SaveAuthorizationCode(ctx context.Context, code *AuthorizationCode) error
	GetAuthorizationCode(ctx context.Context, code string) (*AuthorizationCode, error)
	DeleteAuthorizationCode(ctx context.Context, code string) error
	CleanupExpiredCodes(ctx context.Context) error

	// Token management
	SaveRefreshToken(ctx context.Context, token *RefreshToken) error
	GetRefreshToken(ctx context.Context, token string) (*RefreshToken, error)
	DeleteRefreshToken(ctx context.Context, token string) error
	DeleteRefreshTokensForClient(ctx context.Context, clientID string) error
	CleanupExpiredTokens(ctx context.Context) error
}

Storage defines the interface for OAuth data persistence.

type TokenRequest

type TokenRequest struct {
	GrantType    string
	Code         string
	RedirectURI  string
	ClientID     string
	ClientSecret string
	CodeVerifier string
	RefreshToken string
	Scope        string
}

TokenRequest represents a token request.

type TokenResponse

type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int    `json:"expires_in"`
	RefreshToken string `json:"refresh_token,omitempty"`
	Scope        string `json:"scope,omitempty"`
}

TokenResponse represents a token response.

type UpstreamConfig added in v0.3.0

type UpstreamConfig struct {
	// Issuer is the upstream IdP issuer URL (e.g., Keycloak realm URL).
	Issuer string

	// ClientID is the MCP server's client ID in the upstream IdP.
	ClientID string

	// ClientSecret is the MCP server's client secret.
	ClientSecret string

	// RedirectURI is the callback URL for the upstream IdP.
	RedirectURI string
}

UpstreamConfig configures the upstream identity provider.

Directories

Path Synopsis
Package postgres provides PostgreSQL storage for OAuth 2.1 data.
Package postgres provides PostgreSQL storage for OAuth 2.1 data.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL