Merge pull request #1006 from trheyi/main
Add OAuth service implementation with configuration and validation
This commit is contained in:
commit
93823b87d9
8 changed files with 1001 additions and 0 deletions
1
job/README.md
Normal file
1
job/README.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
# Job
|
||||||
1
job/job.go
Normal file
1
job/job.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package job
|
||||||
12
job/types/interfaces.go
Normal file
12
job/types/interfaces.go
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// Job interface
|
||||||
|
type Job interface {
|
||||||
|
Run(ctx context.Context) error
|
||||||
|
AddTask(ctx context.Context, task Task) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task interface
|
||||||
|
type Task func(ctx context.Context, job Job) error
|
||||||
1
job/types/types.go
Normal file
1
job/types/types.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package types
|
||||||
148
openapi/oauth/interfaces.go
Normal file
148
openapi/oauth/interfaces.go
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
package oauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OAuth interface defines the complete OAuth 2.1 and MCP authorization server functionality
|
||||||
|
type OAuth interface {
|
||||||
|
// AuthorizationServer returns the authorization server endpoint URL
|
||||||
|
// This endpoint is used to initiate the authorization flow
|
||||||
|
AuthorizationServer(ctx context.Context) string
|
||||||
|
|
||||||
|
// ProtectedResource returns the protected resource endpoint URL
|
||||||
|
// This endpoint is used to access protected resources using access tokens
|
||||||
|
ProtectedResource(ctx context.Context) string
|
||||||
|
|
||||||
|
// Authorize processes an authorization request and returns an authorization code
|
||||||
|
// The authorization code can be exchanged for an access token
|
||||||
|
Authorize(ctx context.Context, request *AuthorizationRequest) (*AuthorizationResponse, error)
|
||||||
|
|
||||||
|
// Token exchanges an authorization code for an access token
|
||||||
|
// This is the core token endpoint functionality
|
||||||
|
Token(ctx context.Context, grantType string, code string, clientID string, codeVerifier string) (*Token, error)
|
||||||
|
|
||||||
|
// Revoke revokes an access token or refresh token
|
||||||
|
// Once revoked, the token cannot be used for accessing protected resources
|
||||||
|
Revoke(ctx context.Context, token string, tokenTypeHint string) error
|
||||||
|
|
||||||
|
// Introspect returns information about an access token
|
||||||
|
// This endpoint allows resource servers to validate tokens
|
||||||
|
Introspect(ctx context.Context, token string) (*TokenIntrospectionResponse, error)
|
||||||
|
|
||||||
|
// Register registers a new OAuth client with the authorization server
|
||||||
|
// This is used for static client registration
|
||||||
|
Register(ctx context.Context, clientInfo *ClientInfo) (*ClientInfo, error)
|
||||||
|
|
||||||
|
// JWKS returns the JSON Web Key Set for token verification
|
||||||
|
// This endpoint provides public keys for validating JWT tokens
|
||||||
|
JWKS(ctx context.Context) (*JWKSResponse, error)
|
||||||
|
|
||||||
|
// Endpoints returns a map of all available OAuth endpoints
|
||||||
|
// This provides endpoint discovery for clients
|
||||||
|
Endpoints(ctx context.Context) (map[string]string, error)
|
||||||
|
|
||||||
|
// RefreshToken exchanges a refresh token for a new access token
|
||||||
|
// This allows clients to obtain fresh access tokens without user interaction
|
||||||
|
RefreshToken(ctx context.Context, refreshToken string, scope string) (*RefreshTokenResponse, error)
|
||||||
|
|
||||||
|
// DeviceAuthorization initiates the device authorization flow
|
||||||
|
// This is used for devices with limited input capabilities
|
||||||
|
DeviceAuthorization(ctx context.Context, clientID string, scope string) (*DeviceAuthorizationResponse, error)
|
||||||
|
|
||||||
|
// UserInfo returns user information for a given access token
|
||||||
|
// This endpoint provides user profile information in the format defined by the UserProvider
|
||||||
|
UserInfo(ctx context.Context, accessToken string) (interface{}, error)
|
||||||
|
|
||||||
|
// GenerateCodeChallenge generates a code challenge from a code verifier
|
||||||
|
// This is used for PKCE (Proof Key for Code Exchange) flow
|
||||||
|
GenerateCodeChallenge(ctx context.Context, codeVerifier string, method string) (string, error)
|
||||||
|
|
||||||
|
// ValidateCodeChallenge validates a code verifier against a code challenge
|
||||||
|
// This verifies the PKCE code challenge during token exchange
|
||||||
|
ValidateCodeChallenge(ctx context.Context, codeVerifier string, codeChallenge string, method string) error
|
||||||
|
|
||||||
|
// PushAuthorizationRequest processes a pushed authorization request
|
||||||
|
// This implements RFC 9126 for enhanced security
|
||||||
|
PushAuthorizationRequest(ctx context.Context, request *PushedAuthorizationRequest) (*PushedAuthorizationResponse, error)
|
||||||
|
|
||||||
|
// TokenExchange exchanges one token for another token
|
||||||
|
// This implements RFC 8693 for token exchange scenarios
|
||||||
|
TokenExchange(ctx context.Context, subjectToken string, subjectTokenType string, audience string, scope string) (*TokenExchangeResponse, error)
|
||||||
|
|
||||||
|
// UpdateClient updates an existing OAuth client configuration
|
||||||
|
// This allows modification of client metadata
|
||||||
|
UpdateClient(ctx context.Context, clientID string, clientInfo *ClientInfo) (*ClientInfo, error)
|
||||||
|
|
||||||
|
// DeleteClient removes an OAuth client from the authorization server
|
||||||
|
// This permanently deletes the client and invalidates all associated tokens
|
||||||
|
DeleteClient(ctx context.Context, clientID string) error
|
||||||
|
|
||||||
|
// ValidateScope validates requested scopes against available scopes
|
||||||
|
// This ensures clients only request permitted scopes
|
||||||
|
ValidateScope(ctx context.Context, requestedScopes []string, clientID string) (*ValidationResult, error)
|
||||||
|
|
||||||
|
// GetServerMetadata returns OAuth 2.0 Authorization Server Metadata
|
||||||
|
// This implements RFC 8414 for server discovery
|
||||||
|
GetServerMetadata(ctx context.Context) (*AuthorizationServerMetadata, error)
|
||||||
|
|
||||||
|
// MCP Requirements
|
||||||
|
|
||||||
|
// ValidateResourceParameter validates an OAuth 2.0 resource parameter
|
||||||
|
// This ensures the resource parameter is valid and properly formatted
|
||||||
|
ValidateResourceParameter(ctx context.Context, resource string) (*ValidationResult, error)
|
||||||
|
|
||||||
|
// GetCanonicalResourceURI returns the canonical form of a resource URI
|
||||||
|
// This normalizes resource URIs for consistent processing
|
||||||
|
GetCanonicalResourceURI(ctx context.Context, serverURI string) (string, error)
|
||||||
|
|
||||||
|
// GetProtectedResourceMetadata returns OAuth 2.0 Protected Resource Metadata
|
||||||
|
// This implements RFC 9728 for MCP server discovery
|
||||||
|
GetProtectedResourceMetadata(ctx context.Context) (*ProtectedResourceMetadata, error)
|
||||||
|
|
||||||
|
// HandleWWWAuthenticate processes WWW-Authenticate challenges
|
||||||
|
// This handles authentication challenges from protected resources
|
||||||
|
HandleWWWAuthenticate(ctx context.Context, challenge string) (*WWWAuthenticateChallenge, error)
|
||||||
|
|
||||||
|
// DynamicClientRegistration handles dynamic client registration
|
||||||
|
// This implements RFC 7591 for automatic client registration
|
||||||
|
DynamicClientRegistration(ctx context.Context, request *DynamicClientRegistrationRequest) (*DynamicClientRegistrationResponse, error)
|
||||||
|
|
||||||
|
// ValidateStateParameter validates OAuth state parameters
|
||||||
|
// This prevents CSRF attacks by verifying state parameters
|
||||||
|
ValidateStateParameter(ctx context.Context, state string, clientID string) (*ValidationResult, error)
|
||||||
|
|
||||||
|
// GenerateStateParameter generates a secure state parameter
|
||||||
|
// This creates cryptographically secure state values for CSRF protection
|
||||||
|
GenerateStateParameter(ctx context.Context, clientID string) (*StateParameter, error)
|
||||||
|
|
||||||
|
// ValidateTokenAudience validates token audience claims
|
||||||
|
// This ensures tokens are only used with their intended audiences
|
||||||
|
ValidateTokenAudience(ctx context.Context, token string, expectedAudience string) (*ValidationResult, error)
|
||||||
|
|
||||||
|
// MCP Security Requirements
|
||||||
|
|
||||||
|
// ValidateRedirectURI validates redirect URIs against registered URIs
|
||||||
|
// This prevents open redirect attacks by enforcing exact URI matching
|
||||||
|
ValidateRedirectURI(ctx context.Context, redirectURI string, registeredURIs []string) (*ValidationResult, error)
|
||||||
|
|
||||||
|
// RotateRefreshToken rotates a refresh token and invalidates the old one
|
||||||
|
// This implements refresh token rotation for enhanced security
|
||||||
|
RotateRefreshToken(ctx context.Context, oldToken string) (*RefreshTokenResponse, error)
|
||||||
|
|
||||||
|
// ValidateTokenBinding validates token binding information
|
||||||
|
// This ensures tokens are bound to the correct client or device
|
||||||
|
ValidateTokenBinding(ctx context.Context, token string, binding *TokenBinding) (*ValidationResult, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserProvider interface for user information retrieval
|
||||||
|
type UserProvider interface {
|
||||||
|
// GetUserByAccessToken retrieves user information using an access token
|
||||||
|
GetUserByAccessToken(ctx context.Context, accessToken string) (interface{}, error)
|
||||||
|
|
||||||
|
// GetUserBySubject retrieves user information using a subject identifier
|
||||||
|
GetUserBySubject(ctx context.Context, subject string) (interface{}, error)
|
||||||
|
|
||||||
|
// ValidateUserScope validates if a user has access to requested scopes
|
||||||
|
ValidateUserScope(ctx context.Context, userID string, scopes []string) (bool, error)
|
||||||
|
}
|
||||||
|
|
@ -1 +1,234 @@
|
||||||
package oauth
|
package oauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/yaoapp/gou/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service OAuth service
|
||||||
|
type Service struct {
|
||||||
|
config *Config
|
||||||
|
store store.Store
|
||||||
|
userProvider UserProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config OAuth service configuration
|
||||||
|
type Config struct {
|
||||||
|
// Core storage interface
|
||||||
|
Store store.Store `json:"-"`
|
||||||
|
|
||||||
|
// User provider interface
|
||||||
|
UserProvider UserProvider `json:"-"`
|
||||||
|
|
||||||
|
// Certificate and key management
|
||||||
|
Signing SigningConfig `json:"signing"`
|
||||||
|
|
||||||
|
// Token management settings
|
||||||
|
Token TokenConfig `json:"token"`
|
||||||
|
|
||||||
|
// Security configuration
|
||||||
|
Security SecurityConfig `json:"security"`
|
||||||
|
|
||||||
|
// Default client settings
|
||||||
|
Client ClientConfig `json:"client"`
|
||||||
|
|
||||||
|
// Feature flags
|
||||||
|
Features FeatureFlags `json:"features"`
|
||||||
|
|
||||||
|
// OAuth server metadata
|
||||||
|
IssuerURL string `json:"issuer_url"` // JWT token issuer URL
|
||||||
|
}
|
||||||
|
|
||||||
|
// FeatureFlags represents feature toggle configuration
|
||||||
|
type FeatureFlags struct {
|
||||||
|
// OAuth 2.1 features
|
||||||
|
OAuth21Enabled bool `json:"oauth21_enabled"`
|
||||||
|
PKCEEnforced bool `json:"pkce_enforced"`
|
||||||
|
RefreshTokenRotationEnabled bool `json:"refresh_token_rotation_enabled"`
|
||||||
|
|
||||||
|
// Advanced features
|
||||||
|
DeviceFlowEnabled bool `json:"device_flow_enabled"`
|
||||||
|
TokenExchangeEnabled bool `json:"token_exchange_enabled"`
|
||||||
|
PushedAuthorizationEnabled bool `json:"pushed_authorization_enabled"`
|
||||||
|
DynamicClientRegistrationEnabled bool `json:"dynamic_client_registration_enabled"`
|
||||||
|
|
||||||
|
// MCP features
|
||||||
|
MCPComplianceEnabled bool `json:"mcp_compliance_enabled"`
|
||||||
|
ResourceParameterEnabled bool `json:"resource_parameter_enabled"`
|
||||||
|
|
||||||
|
// Security features
|
||||||
|
TokenBindingEnabled bool `json:"token_binding_enabled"`
|
||||||
|
MTLSEnabled bool `json:"mtls_enabled"`
|
||||||
|
DPoPEnabled bool `json:"dpop_enabled"`
|
||||||
|
|
||||||
|
// Experimental features
|
||||||
|
JWTIntrospectionEnabled bool `json:"jwt_introspection_enabled"`
|
||||||
|
TokenRevocationEnabled bool `json:"token_revocation_enabled"`
|
||||||
|
UserInfoJWTEnabled bool `json:"userinfo_jwt_enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewService creates a new OAuth service with the given configuration
|
||||||
|
func NewService(config *Config) (*Service, error) {
|
||||||
|
if config == nil {
|
||||||
|
return nil, ErrInvalidConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default values if not provided
|
||||||
|
if err := setConfigDefaults(config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate configuration
|
||||||
|
if err := validateConfig(config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use UserProvider from config, or create a default one if not provided
|
||||||
|
userProvider := config.UserProvider
|
||||||
|
if userProvider == nil {
|
||||||
|
userProvider = NewDefaultUserProvider(nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
service := &Service{
|
||||||
|
config: config,
|
||||||
|
store: config.Store,
|
||||||
|
userProvider: userProvider,
|
||||||
|
}
|
||||||
|
|
||||||
|
return service, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfig returns the service configuration
|
||||||
|
func (s *Service) GetConfig() *Config {
|
||||||
|
return s.config
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserProvider returns the user provider for the service
|
||||||
|
func (s *Service) GetUserProvider() UserProvider {
|
||||||
|
return s.userProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// setConfigDefaults sets default values for configuration
|
||||||
|
func setConfigDefaults(config *Config) error {
|
||||||
|
// Certificate defaults
|
||||||
|
if config.Signing.SigningAlgorithm == "" {
|
||||||
|
config.Signing.SigningAlgorithm = "RS256"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token defaults
|
||||||
|
if config.Token.AccessTokenLifetime == 0 {
|
||||||
|
config.Token.AccessTokenLifetime = time.Hour
|
||||||
|
}
|
||||||
|
if config.Token.RefreshTokenLifetime == 0 {
|
||||||
|
config.Token.RefreshTokenLifetime = 24 * time.Hour
|
||||||
|
}
|
||||||
|
if config.Token.AuthorizationCodeLifetime == 0 {
|
||||||
|
config.Token.AuthorizationCodeLifetime = 10 * time.Minute
|
||||||
|
}
|
||||||
|
if config.Token.DeviceCodeLifetime == 0 {
|
||||||
|
config.Token.DeviceCodeLifetime = 15 * time.Minute
|
||||||
|
}
|
||||||
|
if config.Token.AccessTokenFormat == "" {
|
||||||
|
config.Token.AccessTokenFormat = "jwt"
|
||||||
|
}
|
||||||
|
if config.Token.RefreshTokenFormat == "" {
|
||||||
|
config.Token.RefreshTokenFormat = "opaque"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Security defaults
|
||||||
|
if len(config.Security.PKCECodeChallengeMethod) == 0 {
|
||||||
|
config.Security.PKCECodeChallengeMethod = []string{"S256"}
|
||||||
|
}
|
||||||
|
if config.Security.PKCECodeVerifierLength == 0 {
|
||||||
|
config.Security.PKCECodeVerifierLength = 128
|
||||||
|
}
|
||||||
|
if config.Security.StateParameterLifetime == 0 {
|
||||||
|
config.Security.StateParameterLifetime = 10 * time.Minute
|
||||||
|
}
|
||||||
|
if config.Security.StateParameterLength == 0 {
|
||||||
|
config.Security.StateParameterLength = 32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client defaults
|
||||||
|
if config.Client.DefaultClientType == "" {
|
||||||
|
config.Client.DefaultClientType = "confidential"
|
||||||
|
}
|
||||||
|
if config.Client.DefaultTokenEndpointAuthMethod == "" {
|
||||||
|
config.Client.DefaultTokenEndpointAuthMethod = "client_secret_basic"
|
||||||
|
}
|
||||||
|
if len(config.Client.DefaultGrantTypes) == 0 {
|
||||||
|
config.Client.DefaultGrantTypes = []string{"authorization_code", "refresh_token"}
|
||||||
|
}
|
||||||
|
if len(config.Client.DefaultResponseTypes) == 0 {
|
||||||
|
config.Client.DefaultResponseTypes = []string{"code"}
|
||||||
|
}
|
||||||
|
if config.Client.ClientIDLength == 0 {
|
||||||
|
config.Client.ClientIDLength = 32
|
||||||
|
}
|
||||||
|
if config.Client.ClientSecretLength == 0 {
|
||||||
|
config.Client.ClientSecretLength = 64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feature flags defaults - enable OAuth 2.1 features by default
|
||||||
|
config.Features.OAuth21Enabled = true
|
||||||
|
config.Features.PKCEEnforced = true
|
||||||
|
config.Features.RefreshTokenRotationEnabled = true
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateConfig validates the configuration
|
||||||
|
func validateConfig(config *Config) error {
|
||||||
|
if config.Store == nil {
|
||||||
|
return ErrStoreMissing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate issuer URL
|
||||||
|
if config.IssuerURL == "" {
|
||||||
|
return ErrIssuerURLMissing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate certificate configuration
|
||||||
|
if config.Signing.SigningCertPath == "" || config.Signing.SigningKeyPath == "" {
|
||||||
|
return ErrCertificateMissing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate token configuration
|
||||||
|
if config.Token.AccessTokenLifetime <= 0 {
|
||||||
|
return ErrInvalidTokenLifetime
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate security configuration
|
||||||
|
if config.Security.PKCERequired && len(config.Security.PKCECodeChallengeMethod) == 0 {
|
||||||
|
return ErrPKCEConfigurationInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error definitions
|
||||||
|
var (
|
||||||
|
ErrInvalidConfiguration = &ErrorResponse{Code: "invalid_configuration", ErrorDescription: "Invalid OAuth service configuration"}
|
||||||
|
ErrStoreMissing = &ErrorResponse{Code: "store_missing", ErrorDescription: "Store is required for OAuth service"}
|
||||||
|
ErrIssuerURLMissing = &ErrorResponse{Code: "issuer_url_missing", ErrorDescription: "Issuer URL is required for OAuth service"}
|
||||||
|
ErrCertificateMissing = &ErrorResponse{Code: "certificate_missing", ErrorDescription: "JWT signing certificate and key are required"}
|
||||||
|
ErrInvalidTokenLifetime = &ErrorResponse{Code: "invalid_token_lifetime", ErrorDescription: "Token lifetime must be greater than 0"}
|
||||||
|
ErrPKCEConfigurationInvalid = &ErrorResponse{Code: "pkce_configuration_invalid", ErrorDescription: "PKCE configuration is invalid"}
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthorizationServer returns the authorization server endpoint URL
|
||||||
|
func (s *Service) AuthorizationServer(ctx context.Context) string {
|
||||||
|
return s.config.IssuerURL
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProtectedResource returns the protected resource endpoint URL
|
||||||
|
func (s *Service) ProtectedResource(ctx context.Context) string {
|
||||||
|
return s.config.IssuerURL
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserInfo returns user information for a given access token
|
||||||
|
func (s *Service) UserInfo(ctx context.Context, accessToken string) (interface{}, error) {
|
||||||
|
return s.userProvider.GetUserByAccessToken(ctx, accessToken)
|
||||||
|
}
|
||||||
|
|
|
||||||
555
openapi/oauth/types.go
Normal file
555
openapi/oauth/types.go
Normal file
|
|
@ -0,0 +1,555 @@
|
||||||
|
package oauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrorResponse represents an OAuth 2.1 error response
|
||||||
|
type ErrorResponse struct {
|
||||||
|
Code string `json:"error"`
|
||||||
|
ErrorDescription string `json:"error_description,omitempty"`
|
||||||
|
ErrorURI string `json:"error_uri,omitempty"`
|
||||||
|
State string `json:"state,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface
|
||||||
|
func (e *ErrorResponse) Error() string {
|
||||||
|
if e.ErrorDescription != "" {
|
||||||
|
return e.Code + ": " + e.ErrorDescription
|
||||||
|
}
|
||||||
|
return e.Code
|
||||||
|
}
|
||||||
|
|
||||||
|
// OAuth 2.1 Grant Types
|
||||||
|
const (
|
||||||
|
GrantTypeAuthorizationCode = "authorization_code"
|
||||||
|
GrantTypeClientCredentials = "client_credentials"
|
||||||
|
GrantTypeRefreshToken = "refresh_token"
|
||||||
|
GrantTypeDeviceCode = "urn:ietf:params:oauth:grant-type:device_code"
|
||||||
|
GrantTypeTokenExchange = "urn:ietf:params:oauth:grant-type:token-exchange"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OAuth 2.1 Response Types
|
||||||
|
const (
|
||||||
|
ResponseTypeCode = "code"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OAuth 2.1 Token Types
|
||||||
|
const (
|
||||||
|
TokenTypeBearer = "Bearer"
|
||||||
|
TokenTypeMAC = "MAC"
|
||||||
|
TokenTypeDPoP = "DPoP"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OAuth 2.1 Client Types
|
||||||
|
const (
|
||||||
|
ClientTypeConfidential = "confidential"
|
||||||
|
ClientTypePublic = "public"
|
||||||
|
ClientTypeCredentialed = "credentialed"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PKCE Code Challenge Methods
|
||||||
|
const (
|
||||||
|
CodeChallengeMethodS256 = "S256"
|
||||||
|
CodeChallengeMethodPlain = "plain"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OAuth 2.1 Error Codes
|
||||||
|
const (
|
||||||
|
ErrorInvalidRequest = "invalid_request"
|
||||||
|
ErrorInvalidClient = "invalid_client"
|
||||||
|
ErrorInvalidGrant = "invalid_grant"
|
||||||
|
ErrorUnauthorizedClient = "unauthorized_client"
|
||||||
|
ErrorUnsupportedGrantType = "unsupported_grant_type"
|
||||||
|
ErrorInvalidScope = "invalid_scope"
|
||||||
|
ErrorAccessDenied = "access_denied"
|
||||||
|
ErrorUnsupportedResponseType = "unsupported_response_type"
|
||||||
|
ErrorServerError = "server_error"
|
||||||
|
ErrorTemporarilyUnavailable = "temporarily_unavailable"
|
||||||
|
ErrorInvalidToken = "invalid_token"
|
||||||
|
ErrorInsufficientScope = "insufficient_scope"
|
||||||
|
ErrorExpiredToken = "expired_token"
|
||||||
|
ErrorAuthorizationPending = "authorization_pending"
|
||||||
|
ErrorSlowDown = "slow_down"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Token Binding Types
|
||||||
|
const (
|
||||||
|
TokenBindingTypeDPoP = "dpop"
|
||||||
|
TokenBindingTypeMTLS = "mtls"
|
||||||
|
TokenBindingTypeCertificate = "certificate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Application Types
|
||||||
|
const (
|
||||||
|
ApplicationTypeWeb = "web"
|
||||||
|
ApplicationTypeNative = "native"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Token Endpoint Authentication Methods
|
||||||
|
const (
|
||||||
|
TokenEndpointAuthNone = "none"
|
||||||
|
TokenEndpointAuthPost = "client_secret_post"
|
||||||
|
TokenEndpointAuthBasic = "client_secret_basic"
|
||||||
|
TokenEndpointAuthJWT = "client_secret_jwt"
|
||||||
|
TokenEndpointAuthPrivateKeyJWT = "private_key_jwt"
|
||||||
|
TokenEndpointAuthTLSClientAuth = "tls_client_auth"
|
||||||
|
TokenEndpointAuthSelfSignedTLS = "self_signed_tls_client_auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Response Modes
|
||||||
|
const (
|
||||||
|
ResponseModeQuery = "query"
|
||||||
|
ResponseModeFragment = "fragment"
|
||||||
|
ResponseModeFormPost = "form_post"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Standard OAuth Scopes
|
||||||
|
const (
|
||||||
|
ScopeOpenID = "openid"
|
||||||
|
ScopeProfile = "profile"
|
||||||
|
ScopeEmail = "email"
|
||||||
|
ScopeAddress = "address"
|
||||||
|
ScopePhone = "phone"
|
||||||
|
ScopeOffline = "offline_access"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MCP Specific Constants
|
||||||
|
const (
|
||||||
|
MCPResourceParameter = "resource"
|
||||||
|
MCPBearerTokenHeader = "Authorization"
|
||||||
|
MCPBearerTokenPrefix = "Bearer "
|
||||||
|
)
|
||||||
|
|
||||||
|
// WWW-Authenticate Schemes
|
||||||
|
const (
|
||||||
|
WWWAuthenticateSchemeBearer = "Bearer"
|
||||||
|
WWWAuthenticateSchemeBasic = "Basic"
|
||||||
|
WWWAuthenticateSchemeDPoP = "DPoP"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Token represents an OAuth 2.1 access token
|
||||||
|
type Token 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"`
|
||||||
|
IssuedAt time.Time `json:"issued_at"`
|
||||||
|
ExpiresAt time.Time `json:"expires_at"`
|
||||||
|
Audience []string `json:"audience,omitempty"`
|
||||||
|
Subject string `json:"subject,omitempty"`
|
||||||
|
Issuer string `json:"issuer,omitempty"`
|
||||||
|
ClientID string `json:"client_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefreshTokenResponse represents the response from refresh token endpoint
|
||||||
|
type RefreshTokenResponse 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeviceAuthorizationResponse represents device authorization response
|
||||||
|
type DeviceAuthorizationResponse struct {
|
||||||
|
DeviceCode string `json:"device_code"`
|
||||||
|
UserCode string `json:"user_code"`
|
||||||
|
VerificationURI string `json:"verification_uri"`
|
||||||
|
VerificationURIComplete string `json:"verification_uri_complete,omitempty"`
|
||||||
|
ExpiresIn int `json:"expires_in"`
|
||||||
|
Interval int `json:"interval,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserInfo represents user information from userinfo endpoint
|
||||||
|
type UserInfo struct {
|
||||||
|
Subject string `json:"sub"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
GivenName string `json:"given_name,omitempty"`
|
||||||
|
FamilyName string `json:"family_name,omitempty"`
|
||||||
|
MiddleName string `json:"middle_name,omitempty"`
|
||||||
|
Nickname string `json:"nickname,omitempty"`
|
||||||
|
PreferredUsername string `json:"preferred_username,omitempty"`
|
||||||
|
Profile string `json:"profile,omitempty"`
|
||||||
|
Picture string `json:"picture,omitempty"`
|
||||||
|
Website string `json:"website,omitempty"`
|
||||||
|
Email string `json:"email,omitempty"`
|
||||||
|
EmailVerified bool `json:"email_verified,omitempty"`
|
||||||
|
Gender string `json:"gender,omitempty"`
|
||||||
|
Birthdate string `json:"birthdate,omitempty"`
|
||||||
|
Zoneinfo string `json:"zoneinfo,omitempty"`
|
||||||
|
Locale string `json:"locale,omitempty"`
|
||||||
|
PhoneNumber string `json:"phone_number,omitempty"`
|
||||||
|
PhoneVerified bool `json:"phone_number_verified,omitempty"`
|
||||||
|
Address *UserAddress `json:"address,omitempty"`
|
||||||
|
UpdatedAt int64 `json:"updated_at,omitempty"`
|
||||||
|
CustomClaims map[string]interface{} `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserAddress represents user address information
|
||||||
|
type UserAddress struct {
|
||||||
|
Formatted string `json:"formatted,omitempty"`
|
||||||
|
StreetAddress string `json:"street_address,omitempty"`
|
||||||
|
Locality string `json:"locality,omitempty"`
|
||||||
|
Region string `json:"region,omitempty"`
|
||||||
|
PostalCode string `json:"postal_code,omitempty"`
|
||||||
|
Country string `json:"country,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientInfo represents OAuth client information
|
||||||
|
type ClientInfo struct {
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
ClientSecret string `json:"client_secret,omitempty"`
|
||||||
|
ClientName string `json:"client_name,omitempty"`
|
||||||
|
ClientType string `json:"client_type"` // "confidential", "public", "credentialed"
|
||||||
|
RedirectURIs []string `json:"redirect_uris"`
|
||||||
|
ResponseTypes []string `json:"response_types,omitempty"`
|
||||||
|
GrantTypes []string `json:"grant_types,omitempty"`
|
||||||
|
ApplicationType string `json:"application_type,omitempty"`
|
||||||
|
Contacts []string `json:"contacts,omitempty"`
|
||||||
|
ClientURI string `json:"client_uri,omitempty"`
|
||||||
|
LogoURI string `json:"logo_uri,omitempty"`
|
||||||
|
Scope string `json:"scope,omitempty"`
|
||||||
|
TosURI string `json:"tos_uri,omitempty"`
|
||||||
|
PolicyURI string `json:"policy_uri,omitempty"`
|
||||||
|
JwksURI string `json:"jwks_uri,omitempty"`
|
||||||
|
JwksValue string `json:"jwks,omitempty"`
|
||||||
|
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty"`
|
||||||
|
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthorizationServerMetadata represents OAuth 2.0 Authorization Server Metadata (RFC 8414)
|
||||||
|
type AuthorizationServerMetadata struct {
|
||||||
|
Issuer string `json:"issuer"`
|
||||||
|
AuthorizationEndpoint string `json:"authorization_endpoint"`
|
||||||
|
TokenEndpoint string `json:"token_endpoint"`
|
||||||
|
JwksURI string `json:"jwks_uri,omitempty"`
|
||||||
|
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
|
||||||
|
ScopesSupported []string `json:"scopes_supported,omitempty"`
|
||||||
|
ResponseTypesSupported []string `json:"response_types_supported"`
|
||||||
|
ResponseModesSupported []string `json:"response_modes_supported,omitempty"`
|
||||||
|
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
|
||||||
|
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
|
||||||
|
TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
|
||||||
|
ServiceDocumentation string `json:"service_documentation,omitempty"`
|
||||||
|
UILocalesSupported []string `json:"ui_locales_supported,omitempty"`
|
||||||
|
OpPolicyURI string `json:"op_policy_uri,omitempty"`
|
||||||
|
OpTosURI string `json:"op_tos_uri,omitempty"`
|
||||||
|
RevocationEndpoint string `json:"revocation_endpoint,omitempty"`
|
||||||
|
RevocationEndpointAuthMethodsSupported []string `json:"revocation_endpoint_auth_methods_supported,omitempty"`
|
||||||
|
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"`
|
||||||
|
IntrospectionEndpointAuthMethodsSupported []string `json:"introspection_endpoint_auth_methods_supported,omitempty"`
|
||||||
|
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
|
||||||
|
DeviceAuthorizationEndpoint string `json:"device_authorization_endpoint,omitempty"`
|
||||||
|
UserinfoEndpoint string `json:"userinfo_endpoint,omitempty"`
|
||||||
|
PushedAuthorizationRequestEndpoint string `json:"pushed_authorization_request_endpoint,omitempty"`
|
||||||
|
RequirePushedAuthorizationRequests bool `json:"require_pushed_authorization_requests,omitempty"`
|
||||||
|
DPoPSigningAlgValuesSupported []string `json:"dpop_signing_alg_values_supported,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProtectedResourceMetadata represents OAuth 2.0 Protected Resource Metadata (RFC 9728)
|
||||||
|
type ProtectedResourceMetadata struct {
|
||||||
|
Resource string `json:"resource"`
|
||||||
|
AuthorizationServers []string `json:"authorization_servers"`
|
||||||
|
JwksURI string `json:"jwks_uri,omitempty"`
|
||||||
|
BearerMethodsSupported []string `json:"bearer_methods_supported,omitempty"`
|
||||||
|
ResourceDocumentation string `json:"resource_documentation,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenIntrospectionResponse represents token introspection response
|
||||||
|
type TokenIntrospectionResponse struct {
|
||||||
|
Active bool `json:"active"`
|
||||||
|
Scope string `json:"scope,omitempty"`
|
||||||
|
ClientID string `json:"client_id,omitempty"`
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
TokenType string `json:"token_type,omitempty"`
|
||||||
|
ExpiresAt int64 `json:"exp,omitempty"`
|
||||||
|
IssuedAt int64 `json:"iat,omitempty"`
|
||||||
|
NotBefore int64 `json:"nbf,omitempty"`
|
||||||
|
Subject string `json:"sub,omitempty"`
|
||||||
|
Audience []string `json:"aud,omitempty"`
|
||||||
|
Issuer string `json:"iss,omitempty"`
|
||||||
|
JwtID string `json:"jti,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushedAuthorizationRequest represents PAR request
|
||||||
|
type PushedAuthorizationRequest struct {
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
ResponseType string `json:"response_type"`
|
||||||
|
RedirectURI string `json:"redirect_uri"`
|
||||||
|
Scope string `json:"scope,omitempty"`
|
||||||
|
State string `json:"state,omitempty"`
|
||||||
|
CodeChallenge string `json:"code_challenge,omitempty"`
|
||||||
|
CodeChallengeMethod string `json:"code_challenge_method,omitempty"`
|
||||||
|
Resource string `json:"resource,omitempty"`
|
||||||
|
RequestURI string `json:"request_uri,omitempty"`
|
||||||
|
Request string `json:"request,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushedAuthorizationResponse represents PAR response
|
||||||
|
type PushedAuthorizationResponse struct {
|
||||||
|
RequestURI string `json:"request_uri"`
|
||||||
|
ExpiresIn int `json:"expires_in"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenExchangeResponse represents token exchange response
|
||||||
|
type TokenExchangeResponse struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
IssuedTokenType string `json:"issued_token_type"`
|
||||||
|
TokenType string `json:"token_type"`
|
||||||
|
ExpiresIn int `json:"expires_in,omitempty"`
|
||||||
|
Scope string `json:"scope,omitempty"`
|
||||||
|
RefreshToken string `json:"refresh_token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DynamicClientRegistrationRequest represents dynamic client registration request
|
||||||
|
type DynamicClientRegistrationRequest struct {
|
||||||
|
RedirectURIs []string `json:"redirect_uris"`
|
||||||
|
ResponseTypes []string `json:"response_types,omitempty"`
|
||||||
|
GrantTypes []string `json:"grant_types,omitempty"`
|
||||||
|
ApplicationType string `json:"application_type,omitempty"`
|
||||||
|
Contacts []string `json:"contacts,omitempty"`
|
||||||
|
ClientName string `json:"client_name,omitempty"`
|
||||||
|
LogoURI string `json:"logo_uri,omitempty"`
|
||||||
|
ClientURI string `json:"client_uri,omitempty"`
|
||||||
|
PolicyURI string `json:"policy_uri,omitempty"`
|
||||||
|
TosURI string `json:"tos_uri,omitempty"`
|
||||||
|
JwksURI string `json:"jwks_uri,omitempty"`
|
||||||
|
Jwks string `json:"jwks,omitempty"`
|
||||||
|
Scope string `json:"scope,omitempty"`
|
||||||
|
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty"`
|
||||||
|
TokenEndpointAuthSigningAlg string `json:"token_endpoint_auth_signing_alg,omitempty"`
|
||||||
|
DefaultMaxAge int `json:"default_max_age,omitempty"`
|
||||||
|
RequireAuthTime bool `json:"require_auth_time,omitempty"`
|
||||||
|
DefaultACRValues []string `json:"default_acr_values,omitempty"`
|
||||||
|
InitiateLoginURI string `json:"initiate_login_uri,omitempty"`
|
||||||
|
RequestURIs []string `json:"request_uris,omitempty"`
|
||||||
|
SoftwareID string `json:"software_id,omitempty"`
|
||||||
|
SoftwareVersion string `json:"software_version,omitempty"`
|
||||||
|
SoftwareStatement string `json:"software_statement,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DynamicClientRegistrationResponse represents dynamic client registration response
|
||||||
|
type DynamicClientRegistrationResponse struct {
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
ClientSecret string `json:"client_secret,omitempty"`
|
||||||
|
ClientSecretExpiresAt int64 `json:"client_secret_expires_at,omitempty"`
|
||||||
|
RegistrationAccessToken string `json:"registration_access_token,omitempty"`
|
||||||
|
RegistrationClientURI string `json:"registration_client_uri,omitempty"`
|
||||||
|
ClientIDIssuedAt int64 `json:"client_id_issued_at,omitempty"`
|
||||||
|
*DynamicClientRegistrationRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// WWWAuthenticateChallenge represents WWW-Authenticate challenge
|
||||||
|
type WWWAuthenticateChallenge struct {
|
||||||
|
Scheme string `json:"scheme"`
|
||||||
|
Realm string `json:"realm,omitempty"`
|
||||||
|
Scope string `json:"scope,omitempty"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
ErrorDesc string `json:"error_description,omitempty"`
|
||||||
|
ErrorURI string `json:"error_uri,omitempty"`
|
||||||
|
Resource string `json:"resource,omitempty"`
|
||||||
|
Parameters map[string]string `json:"parameters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateParameter represents OAuth state parameter
|
||||||
|
type StateParameter struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
ExpiresAt time.Time `json:"expires_at"`
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
Nonce string `json:"nonce,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenBinding represents token binding information
|
||||||
|
type TokenBinding struct {
|
||||||
|
TokenID string `json:"token_id"`
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
BindingType string `json:"binding_type"` // "dpop", "mtls", "certificate"
|
||||||
|
BindingValue string `json:"binding_value"`
|
||||||
|
BindingData map[string]interface{} `json:"binding_data,omitempty"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
ExpiresAt time.Time `json:"expires_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceParameter represents OAuth 2.0 resource parameter
|
||||||
|
type ResourceParameter struct {
|
||||||
|
Resource string `json:"resource"`
|
||||||
|
Canonical string `json:"canonical"`
|
||||||
|
Audiences []string `json:"audiences,omitempty"`
|
||||||
|
Scopes []string `json:"scopes,omitempty"`
|
||||||
|
ValidatedAt time.Time `json:"validated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidationResult represents validation result
|
||||||
|
type ValidationResult struct {
|
||||||
|
Valid bool `json:"valid"`
|
||||||
|
Errors []string `json:"errors,omitempty"`
|
||||||
|
Details map[string]string `json:"details,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthorizationRequest represents authorization request
|
||||||
|
type AuthorizationRequest struct {
|
||||||
|
ClientID string `json:"client_id"`
|
||||||
|
ResponseType string `json:"response_type"`
|
||||||
|
RedirectURI string `json:"redirect_uri"`
|
||||||
|
Scope string `json:"scope,omitempty"`
|
||||||
|
State string `json:"state,omitempty"`
|
||||||
|
CodeChallenge string `json:"code_challenge,omitempty"`
|
||||||
|
CodeChallengeMethod string `json:"code_challenge_method,omitempty"`
|
||||||
|
Resource string `json:"resource,omitempty"`
|
||||||
|
Nonce string `json:"nonce,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthorizationResponse represents authorization response
|
||||||
|
type AuthorizationResponse struct {
|
||||||
|
Code string `json:"code,omitempty"`
|
||||||
|
State string `json:"state,omitempty"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
ErrorDescription string `json:"error_description,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JWKSResponse represents JWKS response
|
||||||
|
type JWKSResponse struct {
|
||||||
|
Keys []JWK `json:"keys"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JWK represents JSON Web Key
|
||||||
|
type JWK struct {
|
||||||
|
Kty string `json:"kty"`
|
||||||
|
Use string `json:"use,omitempty"`
|
||||||
|
KeyOps []string `json:"key_ops,omitempty"`
|
||||||
|
Alg string `json:"alg,omitempty"`
|
||||||
|
Kid string `json:"kid,omitempty"`
|
||||||
|
X5U string `json:"x5u,omitempty"`
|
||||||
|
X5C []string `json:"x5c,omitempty"`
|
||||||
|
X5T string `json:"x5t,omitempty"`
|
||||||
|
X5TS256 string `json:"x5t#S256,omitempty"`
|
||||||
|
// RSA
|
||||||
|
N string `json:"n,omitempty"`
|
||||||
|
E string `json:"e,omitempty"`
|
||||||
|
D string `json:"d,omitempty"`
|
||||||
|
P string `json:"p,omitempty"`
|
||||||
|
Q string `json:"q,omitempty"`
|
||||||
|
DP string `json:"dp,omitempty"`
|
||||||
|
DQ string `json:"dq,omitempty"`
|
||||||
|
QI string `json:"qi,omitempty"`
|
||||||
|
// EC
|
||||||
|
Crv string `json:"crv,omitempty"`
|
||||||
|
X string `json:"x,omitempty"`
|
||||||
|
Y string `json:"y,omitempty"`
|
||||||
|
// Symmetric
|
||||||
|
K string `json:"k,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// OAuth Service Configuration Types
|
||||||
|
|
||||||
|
// SigningConfig represents signing configuration for OAuth service
|
||||||
|
type SigningConfig struct {
|
||||||
|
// Token signing certificate and key (for JWT tokens)
|
||||||
|
SigningCertPath string `json:"signing_cert_path"`
|
||||||
|
SigningKeyPath string `json:"signing_key_path"`
|
||||||
|
SigningKeyPassword string `json:"signing_key_password,omitempty"`
|
||||||
|
SigningAlgorithm string `json:"signing_algorithm"` // RS256, RS384, RS512, ES256, ES384, ES512
|
||||||
|
|
||||||
|
// Token verification certificates (for token validation)
|
||||||
|
VerificationCerts []string `json:"verification_certs,omitempty"`
|
||||||
|
|
||||||
|
// mTLS client certificate validation
|
||||||
|
MTLSClientCACertPath string `json:"mtls_client_ca_cert_path,omitempty"`
|
||||||
|
MTLSEnabled bool `json:"mtls_enabled"`
|
||||||
|
|
||||||
|
// Certificate rotation settings
|
||||||
|
CertRotationEnabled bool `json:"cert_rotation_enabled"`
|
||||||
|
CertRotationInterval time.Duration `json:"cert_rotation_interval"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenConfig represents token-related configuration
|
||||||
|
type TokenConfig struct {
|
||||||
|
// Access token settings
|
||||||
|
AccessTokenLifetime time.Duration `json:"access_token_lifetime"` // 1h
|
||||||
|
AccessTokenFormat string `json:"access_token_format"` // jwt, opaque
|
||||||
|
AccessTokenSigningAlg string `json:"access_token_signing_alg"` // RS256
|
||||||
|
|
||||||
|
// Refresh token settings
|
||||||
|
RefreshTokenLifetime time.Duration `json:"refresh_token_lifetime"` // 24h
|
||||||
|
RefreshTokenRotation bool `json:"refresh_token_rotation"` // true for OAuth 2.1
|
||||||
|
RefreshTokenFormat string `json:"refresh_token_format"` // opaque, jwt
|
||||||
|
|
||||||
|
// Authorization code settings
|
||||||
|
AuthorizationCodeLifetime time.Duration `json:"authorization_code_lifetime"` // 10m
|
||||||
|
AuthorizationCodeLength int `json:"authorization_code_length"` // 32
|
||||||
|
|
||||||
|
// Device code settings
|
||||||
|
DeviceCodeLifetime time.Duration `json:"device_code_lifetime"` // 15m
|
||||||
|
DeviceCodeLength int `json:"device_code_length"` // 8
|
||||||
|
UserCodeLength int `json:"user_code_length"` // 8
|
||||||
|
DeviceCodeInterval time.Duration `json:"device_code_interval"` // 5s
|
||||||
|
|
||||||
|
// Token binding settings
|
||||||
|
TokenBindingEnabled bool `json:"token_binding_enabled"`
|
||||||
|
SupportedBindingTypes []string `json:"supported_binding_types"` // dpop, mtls
|
||||||
|
|
||||||
|
// Token audience settings
|
||||||
|
DefaultAudience []string `json:"default_audience"`
|
||||||
|
AudienceValidationMode string `json:"audience_validation_mode"` // strict, relaxed
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecurityConfig represents security-related configuration
|
||||||
|
type SecurityConfig struct {
|
||||||
|
// PKCE settings (mandatory for OAuth 2.1)
|
||||||
|
PKCERequired bool `json:"pkce_required"` // true for OAuth 2.1
|
||||||
|
PKCECodeChallengeMethod []string `json:"pkce_code_challenge_method"` // S256
|
||||||
|
PKCECodeVerifierLength int `json:"pkce_code_verifier_length"` // 128
|
||||||
|
|
||||||
|
// State parameter settings
|
||||||
|
StateParameterRequired bool `json:"state_parameter_required"`
|
||||||
|
StateParameterLifetime time.Duration `json:"state_parameter_lifetime"` // 10m
|
||||||
|
StateParameterLength int `json:"state_parameter_length"` // 32
|
||||||
|
|
||||||
|
// Rate limiting
|
||||||
|
RateLimitEnabled bool `json:"rate_limit_enabled"`
|
||||||
|
RateLimitRequests int `json:"rate_limit_requests"` // requests per window
|
||||||
|
RateLimitWindow time.Duration `json:"rate_limit_window"` // 1m
|
||||||
|
RateLimitByClientID bool `json:"rate_limit_by_client_id"`
|
||||||
|
|
||||||
|
// Brute force protection
|
||||||
|
BruteForceProtectionEnabled bool `json:"brute_force_protection_enabled"`
|
||||||
|
MaxFailedAttempts int `json:"max_failed_attempts"` // 5
|
||||||
|
LockoutDuration time.Duration `json:"lockout_duration"` // 15m
|
||||||
|
|
||||||
|
// Encryption settings
|
||||||
|
EncryptionKey string `json:"encryption_key"` // for encrypting sensitive data
|
||||||
|
EncryptionAlgorithm string `json:"encryption_algorithm"` // AES-256-GCM
|
||||||
|
|
||||||
|
// Additional security features
|
||||||
|
IPWhitelist []string `json:"ip_whitelist,omitempty"`
|
||||||
|
IPBlacklist []string `json:"ip_blacklist,omitempty"`
|
||||||
|
RequireHTTPS bool `json:"require_https"`
|
||||||
|
DisableUnsecureEndpoints bool `json:"disable_unsecure_endpoints"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientConfig represents default client configuration
|
||||||
|
type ClientConfig struct {
|
||||||
|
// Default client settings
|
||||||
|
DefaultClientType string `json:"default_client_type"` // confidential, public
|
||||||
|
DefaultTokenEndpointAuthMethod string `json:"default_token_endpoint_auth_method"` // client_secret_basic, client_secret_post, private_key_jwt
|
||||||
|
DefaultGrantTypes []string `json:"default_grant_types"` // authorization_code, refresh_token
|
||||||
|
DefaultResponseTypes []string `json:"default_response_types"` // code
|
||||||
|
DefaultScopes []string `json:"default_scopes"` // openid, profile, email
|
||||||
|
|
||||||
|
// Client validation settings
|
||||||
|
ClientIDLength int `json:"client_id_length"` // 32
|
||||||
|
ClientSecretLength int `json:"client_secret_length"` // 64
|
||||||
|
ClientSecretLifetime time.Duration `json:"client_secret_lifetime"` // 0 (never expires)
|
||||||
|
|
||||||
|
// Dynamic client registration
|
||||||
|
DynamicRegistrationEnabled bool `json:"dynamic_registration_enabled"`
|
||||||
|
AllowedRedirectURISchemes []string `json:"allowed_redirect_uri_schemes"` // https, http (for dev)
|
||||||
|
AllowedRedirectURIHosts []string `json:"allowed_redirect_uri_hosts"` // localhost (for dev)
|
||||||
|
|
||||||
|
// Client certificate settings
|
||||||
|
ClientCertificateRequired bool `json:"client_certificate_required"`
|
||||||
|
ClientCertificateValidation string `json:"client_certificate_validation"` // none, optional, required
|
||||||
|
}
|
||||||
50
openapi/oauth/user.go
Normal file
50
openapi/oauth/user.go
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
package oauth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultUserProvider provides a default implementation of UserProvider
|
||||||
|
type DefaultUserProvider struct {
|
||||||
|
getUserByAccessTokenFunc func(ctx context.Context, accessToken string) (interface{}, error)
|
||||||
|
getUserBySubjectFunc func(ctx context.Context, subject string) (interface{}, error)
|
||||||
|
validateUserScopeFunc func(ctx context.Context, userID string, scopes []string) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultUserProvider creates a new DefaultUserProvider with the given functions
|
||||||
|
func NewDefaultUserProvider(
|
||||||
|
getUserByAccessTokenFunc func(ctx context.Context, accessToken string) (interface{}, error),
|
||||||
|
getUserBySubjectFunc func(ctx context.Context, subject string) (interface{}, error),
|
||||||
|
validateUserScopeFunc func(ctx context.Context, userID string, scopes []string) (bool, error),
|
||||||
|
) *DefaultUserProvider {
|
||||||
|
return &DefaultUserProvider{
|
||||||
|
getUserByAccessTokenFunc: getUserByAccessTokenFunc,
|
||||||
|
getUserBySubjectFunc: getUserBySubjectFunc,
|
||||||
|
validateUserScopeFunc: validateUserScopeFunc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserByAccessToken retrieves user information using an access token
|
||||||
|
func (p *DefaultUserProvider) GetUserByAccessToken(ctx context.Context, accessToken string) (interface{}, error) {
|
||||||
|
if p.getUserByAccessTokenFunc == nil {
|
||||||
|
return nil, &ErrorResponse{Code: "not_implemented", ErrorDescription: "GetUserByAccessToken is not implemented"}
|
||||||
|
}
|
||||||
|
return p.getUserByAccessTokenFunc(ctx, accessToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserBySubject retrieves user information using a subject identifier
|
||||||
|
func (p *DefaultUserProvider) GetUserBySubject(ctx context.Context, subject string) (interface{}, error) {
|
||||||
|
if p.getUserBySubjectFunc == nil {
|
||||||
|
return nil, &ErrorResponse{Code: "not_implemented", ErrorDescription: "GetUserBySubject is not implemented"}
|
||||||
|
}
|
||||||
|
return p.getUserBySubjectFunc(ctx, subject)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateUserScope validates if a user has access to requested scopes
|
||||||
|
func (p *DefaultUserProvider) ValidateUserScope(ctx context.Context, userID string, scopes []string) (bool, error) {
|
||||||
|
if p.validateUserScopeFunc == nil {
|
||||||
|
// Default implementation: allow all scopes
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return p.validateUserScopeFunc(ctx, userID, scopes)
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue