oauth

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Jan 24, 2026 License: Apache-2.0 Imports: 16 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

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

	// PromptNoneAttempted tracks if we already tried prompt=none.
	// Used to handle Keycloak's login_required error by retrying without prompt=none.
	PromptNoneAttempted bool
}

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.

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.
Package postgres provides PostgreSQL storage for OAuth.

Jump to

Keyboard shortcuts

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