Add OAuth service implementation with configuration and validation
- Introduced the OAuth service structure, including configuration management and user provider integration. - Implemented default settings and validation for various configuration parameters, ensuring robust service initialization. - Added methods for retrieving service configuration and user information based on access tokens. - Defined error handling for configuration issues, enhancing reliability of the OAuth service.
This commit is contained in:
parent
57d61c1ba3
commit
54607bc3ee
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
|
||||
|
||||
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