Documentation
¶
Index ¶
- Constants
- Variables
- func ErrAccountLocked(retryAfter time.Duration) result.Error
- func ErrCredentialsInvalid(message string) result.Error
- func ErrPasswordTooFewCharClasses(minClasses int) result.Error
- func ErrPasswordTooLong(maxLength int) result.Error
- func ErrPasswordTooShort(minLength int) result.Error
- func ErrPrincipalInvalid(message string) result.Error
- func GenerateOpaqueToken() (string, error)
- func GenerateSecret() (string, error)
- func HashOpaqueToken(token string) string
- func PublishRolePermissionsChangedEvent(ctx context.Context, bus event.Bus, roles ...string) error
- func SetExternalAppDetailsType[T any]()
- func SetUserDetailsType[T any]()
- func SubscribeLoginEvent(bus event.Bus, handler func(context.Context, *LoginEvent) error, ...) (event.Unsubscribe, error)
- type AllDataScope
- type AuthManager
- type AuthTokens
- type Authentication
- type Authenticator
- type CachedRolePermissionsLoader
- type ChallengeProvider
- type ChallengeState
- type ChallengeTokenStore
- type DataPermissionApplier
- type DataPermissionResolver
- type DataScope
- type DeliveredCodeSender
- type DeliveredCodeVerifier
- type DepartmentLoader
- type DepartmentOption
- type DepartmentSelectionChallengeData
- type DepartmentSelectionChallengeProvider
- func (p *DepartmentSelectionChallengeProvider) Evaluate(ctx context.Context, principal *Principal) (*LoginChallenge, error)
- func (*DepartmentSelectionChallengeProvider) Order() int
- func (p *DepartmentSelectionChallengeProvider) Resolve(ctx context.Context, principal *Principal, response any) (*Principal, error)
- func (*DepartmentSelectionChallengeProvider) Type() string
- type DepartmentSelector
- type ExpiryPasswordChangeChecker
- type ExternalAppConfig
- type ExternalAppLoader
- type Gender
- type IPWhitelist
- type IPWhitelistLoader
- type IPWhitelistValidator
- type JWT
- type JWTChallengeTokenStore
- type JWTClaimsAccessor
- type JWTClaimsBuilder
- func (b *JWTClaimsBuilder) Claim(key string) (any, bool)
- func (b *JWTClaimsBuilder) Details() (any, bool)
- func (b *JWTClaimsBuilder) ID() (string, bool)
- func (b *JWTClaimsBuilder) Roles() ([]string, bool)
- func (b *JWTClaimsBuilder) Subject() (string, bool)
- func (b *JWTClaimsBuilder) Type() (string, bool)
- func (b *JWTClaimsBuilder) WithClaim(key string, value any) *JWTClaimsBuilder
- func (b *JWTClaimsBuilder) WithDetails(details any) *JWTClaimsBuilder
- func (b *JWTClaimsBuilder) WithID(id string) *JWTClaimsBuilder
- func (b *JWTClaimsBuilder) WithRoles(roles []string) *JWTClaimsBuilder
- func (b *JWTClaimsBuilder) WithSubject(subject string) *JWTClaimsBuilder
- func (b *JWTClaimsBuilder) WithType(typ string) *JWTClaimsBuilder
- type JWTConfig
- type LockoutKey
- type LockoutPolicy
- type LockoutStrategy
- type LoginAttempt
- type LoginChallenge
- type LoginDecision
- type LoginEvent
- type LoginEventParams
- type LoginGuard
- type LoginResult
- type MemoryChallengeTokenStore
- type MemoryLoginGuard
- type MemoryNonceStore
- type MemorySessionStore
- func (s *MemorySessionStore) Create(ctx context.Context, tokenHash string, session Session, ttl time.Duration) error
- func (s *MemorySessionStore) ListAll(ctx context.Context) ([]Session, error)
- func (s *MemorySessionStore) ListByUser(ctx context.Context, userID string) ([]Session, error)
- func (s *MemorySessionStore) Lookup(ctx context.Context, tokenHash string) (*Session, error)
- func (s *MemorySessionStore) Renew(ctx context.Context, tokenHash string, expiresAt time.Time, ttl time.Duration) error
- func (s *MemorySessionStore) Revoke(ctx context.Context, id string) error
- func (s *MemorySessionStore) RevokeUser(ctx context.Context, userID string) error
- type NonceStore
- type OTPChallengeData
- type OTPChallengeProvider
- func NewDeliveredChallengeProvider(challengeType string, order int, evaluator OTPEvaluator, store OTPCodeStore, ...) *OTPChallengeProvider
- func NewEmailChallengeProvider(evaluator OTPEvaluator, store OTPCodeStore, delivery OTPCodeDelivery) *OTPChallengeProvider
- func NewOTPChallengeProvider(config OTPChallengeProviderConfig) *OTPChallengeProvider
- func NewSMSChallengeProvider(evaluator OTPEvaluator, store OTPCodeStore, delivery OTPCodeDelivery) *OTPChallengeProvider
- func NewTOTPChallengeProvider(loader TOTPSecretLoader, opts ...TOTPOption) *OTPChallengeProvider
- func (p *OTPChallengeProvider) Evaluate(ctx context.Context, principal *Principal) (*LoginChallenge, error)
- func (p *OTPChallengeProvider) Order() int
- func (p *OTPChallengeProvider) Resolve(ctx context.Context, principal *Principal, response any) (*Principal, error)
- func (p *OTPChallengeProvider) Type() string
- type OTPChallengeProviderConfig
- type OTPCodeDelivery
- type OTPCodeSender
- type OTPCodeStore
- type OTPCodeVerifier
- type OTPEvaluator
- type PasswordChangeChallengeData
- type PasswordChangeChallengeProvider
- func (p *PasswordChangeChallengeProvider) Evaluate(ctx context.Context, principal *Principal) (*LoginChallenge, error)
- func (*PasswordChangeChallengeProvider) Order() int
- func (p *PasswordChangeChallengeProvider) Resolve(ctx context.Context, principal *Principal, response any) (*Principal, error)
- func (*PasswordChangeChallengeProvider) Type() string
- type PasswordChangeChecker
- type PasswordChanger
- type PasswordDecryptor
- type PasswordHistoryStore
- type PasswordMetadataLoader
- type PasswordRule
- func NewBlocklistRule(entries []string) PasswordRule
- func NewCharacterClassRule(requireUpper, requireLower, requireDigit, requireSymbol bool, minClasses int) PasswordRule
- func NewDisallowIdentityRule() PasswordRule
- func NewMaxLengthRule(maxLength int) PasswordRule
- func NewMinLengthRule(minLength int) PasswordRule
- type PasswordValidator
- type PermissionChecker
- type Principal
- type PrincipalType
- type RedisChallengeTokenStore
- type RedisLoginGuard
- type RedisNonceStore
- type RedisSessionStore
- func (s *RedisSessionStore) Create(ctx context.Context, tokenHash string, session Session, ttl time.Duration) error
- func (s *RedisSessionStore) ListAll(ctx context.Context) ([]Session, error)
- func (s *RedisSessionStore) ListByUser(ctx context.Context, userID string) ([]Session, error)
- func (s *RedisSessionStore) Lookup(ctx context.Context, tokenHash string) (*Session, error)
- func (s *RedisSessionStore) Renew(ctx context.Context, tokenHash string, expiresAt time.Time, ttl time.Duration) error
- func (s *RedisSessionStore) Revoke(ctx context.Context, id string) error
- func (s *RedisSessionStore) RevokeUser(ctx context.Context, userID string) error
- type RequestScopedDataPermApplier
- type RolePermissionsChangedEvent
- type RolePermissionsLoader
- type SelfDataScope
- type Session
- type SessionExceedPolicy
- type SessionInspector
- type SessionMeta
- type SessionPolicy
- type SessionStore
- type Signature
- func (s *Signature) Sign(appID, method, path string) (*SignatureResult, error)
- func (s *Signature) Verify(ctx context.Context, appID, method, path string, timestamp int64, ...) error
- func (s *Signature) VerifyWithSecret(ctx context.Context, secret, appID, method, path string, timestamp int64, ...) error
- type SignatureAlgorithm
- type SignatureCredentials
- type SignatureOption
- type SignatureResult
- type TOTPEvaluator
- type TOTPOption
- type TOTPSecretLoader
- type TOTPVerifier
- type TokenGenerator
- type UserInfo
- type UserInfoLoader
- type UserLoader
- type UserMenu
- type UserMenuType
Constants ¶
const ( ErrMessageUnauthenticated = "security_unauthenticated" ErrMessageExternalAppLoaderNotImplemented = "security_external_app_loader_not_implemented" ErrMessageCredentialsFormatInvalid = "security_credentials_format_invalid" ErrMessageUnsupportedAuthenticationType = "security_unsupported_authentication_type" ErrMessageUserLoaderNotImplemented = "security_user_loader_not_implemented" ErrMessageUserInfoLoaderNotImplemented = "security_user_info_loader_not_implemented" ErrMessageChallengeResolveFailed = "security_challenge_resolve_failed" ErrMessageAccountLocked = "security_account_locked" ErrMessagePasswordTooShort = "security_password_too_short" ErrMessagePasswordTooLong = "security_password_too_long" ErrMessagePasswordTooFewCharClasses = "security_password_too_few_char_classes" )
i18n message-IDs that callers reference directly (template arguments, factory-based result.Err construction, Fiber error mapping, etc.). Pure sentinel-internal message IDs live inline at the sentinel definition and never need a named constant.
const ( ErrCodeUnauthenticated = 1000 ErrCodeUnsupportedAuthenticationType = 1001 ErrCodeTokenExpired = 1002 ErrCodeTokenInvalid = 1003 ErrCodeTokenNotValidYet = 1004 ErrCodeTokenInvalidIssuer = 1005 ErrCodeTokenInvalidAudience = 1006 ErrCodePrincipalInvalid = 1007 ErrCodeCredentialsInvalid = 1008 ErrCodeAppIDRequired = 1009 ErrCodeTimestampRequired = 1010 ErrCodeSignatureRequired = 1011 ErrCodeTimestampInvalid = 1012 ErrCodeSignatureExpired = 1013 ErrCodeExternalAppNotFound = 1014 ErrCodeExternalAppDisabled = 1015 ErrCodeIPNotAllowed = 1016 ErrCodeSignatureInvalid = 1017 ErrCodeNonceRequired = 1018 ErrCodeNonceInvalid = 1019 ErrCodeNonceAlreadyUsed = 1020 ErrCodeAuthHeaderMissing = 1021 ErrCodeAuthHeaderInvalid = 1022 ErrCodeAccountLocked = 1023 ErrCodeTooManyConcurrentSessions = 1024 // Challenge errors (1030-1039). 1030 and 1032 are absent: they were never wired to a sentinel. ErrCodeChallengeTokenInvalid = 1031 ErrCodeChallengeTypeInvalid = 1033 ErrCodeChallengeResolveFailed = 1034 ErrCodeOTPCodeRequired = 1035 ErrCodeOTPCodeInvalid = 1036 ErrCodeNewPasswordRequired = 1037 ErrCodeDepartmentRequired = 1038 // Password policy errors (1050). Every policy violation shares one code; the // i18n message identifies which rule was broken. ErrCodePasswordPolicyViolation = 1050 )
Response codes for security-domain API errors. 1000-1029: authentication; 1030-1039: challenge; 1050: password policy.
const ( AuthSchemeBearer = "Bearer" QueryKeyAccessToken = "__accessToken" )
Authentication constants.
const ( TokenTypeAccess = "access" TokenTypeRefresh = "refresh" TokenTypeChallenge = "challenge" )
JWT token type constants.
const ( // PrioritySelf indicates access only to data created by the user themselves. // This is the most restrictive data scope. PrioritySelf = 10 // PriorityDepartment indicates access to data within the user's department. PriorityDepartment = 20 // PriorityDepartmentAndSub indicates access to data within the user's department and all sub-departments. PriorityDepartmentAndSub = 30 // PriorityOrganization indicates access to data within the user's organization. PriorityOrganization = 40 // PriorityOrganizationAndSub indicates access to data within the user's organization and all sub-organizations. PriorityOrganizationAndSub = 50 // PriorityCustom indicates access to data within the user's custom data scope. PriorityCustom = 60 // PriorityAll indicates unrestricted access to all data. // This is the broadest data scope, typically used for system administrators. PriorityAll = 10000 )
const ( JWTIssuer = "vef" // Issuer DefaultJWTAudience = "vef-app" // Audience DefaultJWTSecret = "af6675678bd81ad7c93c4a51d122ef61e9750fe5d42ceac1c33b293f36bc14c2" // Secret )
const ( ChallengeTokenExpires = 5 * time.Minute ClaimChallengePending = "pnd" ClaimChallengePrincipalType = "ptp" ClaimChallengeResolved = "rsd" // ClaimChallengePrincipalName stores the principal Name as a dedicated claim; // the subject carries only the principal ID. ClaimChallengePrincipalName = "pnm" // ClaimChallengeUsername stores the original login identifier so audit events // emitted after a challenge report the same identifier as the initial login. ClaimChallengeUsername = "unm" )
const ( ChallengeTypeSMS = "sms_otp" ChallengeTypeEmail = "email_otp" )
Challenge type constants for convenience constructors.
const ( PasswordChangeReasonFirstLogin = "first_login" PasswordChangeReasonExpired = "expired" )
Predefined password change reason constants for use in PasswordChangeChecker implementations.
const ( ChallengeTypeTOTP = "totp" TOTPDefaultDestination = "Authenticator App" )
const ChallengeTypeDepartmentSelection = "department_selection"
ChallengeTypeDepartmentSelection is the challenge type identifier for department selection.
const ChallengeTypePasswordChange = "password_change"
ChallengeTypePasswordChange is the challenge type identifier for forced password change.
Variables ¶
var ( ErrUnauthenticated = result.Err( i18n.T(ErrMessageUnauthenticated), result.WithCode(ErrCodeUnauthenticated), result.WithStatus(fiber.StatusUnauthorized), ) ErrTokenExpired = result.Err( i18n.T("security_token_expired"), result.WithCode(ErrCodeTokenExpired), result.WithStatus(fiber.StatusUnauthorized), ) ErrTokenInvalid = result.Err( i18n.T("security_token_invalid"), result.WithCode(ErrCodeTokenInvalid), result.WithStatus(fiber.StatusUnauthorized), ) ErrTokenNotValidYet = result.Err( i18n.T("security_token_not_valid_yet"), result.WithCode(ErrCodeTokenNotValidYet), result.WithStatus(fiber.StatusUnauthorized), ) ErrTokenInvalidIssuer = result.Err( i18n.T("security_token_invalid_issuer"), result.WithCode(ErrCodeTokenInvalidIssuer), result.WithStatus(fiber.StatusUnauthorized), ) ErrTokenInvalidAudience = result.Err( i18n.T("security_token_invalid_audience"), result.WithCode(ErrCodeTokenInvalidAudience), result.WithStatus(fiber.StatusUnauthorized), ) )
Predefined authentication errors (HTTP 401).
var ( ErrAppIDRequired = result.Err( i18n.T("security_app_id_required"), result.WithCode(ErrCodeAppIDRequired), result.WithStatus(fiber.StatusUnauthorized), ) ErrTimestampRequired = result.Err( i18n.T("security_timestamp_required"), result.WithCode(ErrCodeTimestampRequired), result.WithStatus(fiber.StatusUnauthorized), ) ErrSignatureRequired = result.Err( i18n.T("security_signature_required"), result.WithCode(ErrCodeSignatureRequired), result.WithStatus(fiber.StatusUnauthorized), ) ErrTimestampInvalid = result.Err( i18n.T("security_timestamp_invalid"), result.WithCode(ErrCodeTimestampInvalid), result.WithStatus(fiber.StatusUnauthorized), ) ErrSignatureExpired = result.Err( i18n.T("security_signature_expired"), result.WithCode(ErrCodeSignatureExpired), result.WithStatus(fiber.StatusUnauthorized), ) ErrSignatureInvalid = result.Err( i18n.T("security_signature_invalid"), result.WithCode(ErrCodeSignatureInvalid), result.WithStatus(fiber.StatusUnauthorized), ) ErrExternalAppNotFound = result.Err( i18n.T("security_external_app_not_found"), result.WithCode(ErrCodeExternalAppNotFound), result.WithStatus(fiber.StatusUnauthorized), ) ErrExternalAppDisabled = result.Err( i18n.T("security_external_app_disabled"), result.WithCode(ErrCodeExternalAppDisabled), result.WithStatus(fiber.StatusUnauthorized), ) ErrIPNotAllowed = result.Err( i18n.T("security_ip_not_allowed"), result.WithCode(ErrCodeIPNotAllowed), result.WithStatus(fiber.StatusUnauthorized), ) ErrNonceRequired = result.Err( i18n.T("security_nonce_required"), result.WithCode(ErrCodeNonceRequired), result.WithStatus(fiber.StatusUnauthorized), ) ErrNonceInvalid = result.Err( i18n.T("security_nonce_invalid"), result.WithCode(ErrCodeNonceInvalid), result.WithStatus(fiber.StatusUnauthorized), ) ErrNonceAlreadyUsed = result.Err( i18n.T("security_nonce_already_used"), result.WithCode(ErrCodeNonceAlreadyUsed), result.WithStatus(fiber.StatusUnauthorized), ) ErrAuthHeaderMissing = result.Err( i18n.T("security_auth_header_missing"), result.WithCode(ErrCodeAuthHeaderMissing), result.WithStatus(fiber.StatusUnauthorized), ) ErrAuthHeaderInvalid = result.Err( i18n.T("security_auth_header_invalid"), result.WithCode(ErrCodeAuthHeaderInvalid), result.WithStatus(fiber.StatusUnauthorized), ) ErrTooManyConcurrentSessions = result.Err( i18n.T("security_too_many_concurrent_sessions"), result.WithCode(ErrCodeTooManyConcurrentSessions), result.WithStatus(fiber.StatusForbidden), ) )
Predefined external app authentication errors (HTTP 401).
var ( ErrChallengeTokenInvalid = result.Err( i18n.T("security_challenge_token_invalid"), result.WithCode(ErrCodeChallengeTokenInvalid), result.WithStatus(fiber.StatusUnauthorized), ) ErrChallengeTypeInvalid = result.Err( i18n.T("security_challenge_type_invalid"), result.WithCode(ErrCodeChallengeTypeInvalid), result.WithStatus(fiber.StatusBadRequest), ) ErrChallengeResolveFailed = result.Err( i18n.T(ErrMessageChallengeResolveFailed), result.WithCode(ErrCodeChallengeResolveFailed), result.WithStatus(fiber.StatusUnauthorized), ) ErrOTPCodeRequired = result.Err( i18n.T("security_otp_code_required"), result.WithCode(ErrCodeOTPCodeRequired), result.WithStatus(fiber.StatusBadRequest), ) ErrOTPCodeInvalid = result.Err( i18n.T("security_otp_code_invalid"), result.WithCode(ErrCodeOTPCodeInvalid), result.WithStatus(fiber.StatusUnauthorized), ) ErrNewPasswordRequired = result.Err( i18n.T("security_new_password_required"), result.WithCode(ErrCodeNewPasswordRequired), result.WithStatus(fiber.StatusBadRequest), ) ErrDepartmentRequired = result.Err( i18n.T("security_department_required"), result.WithCode(ErrCodeDepartmentRequired), result.WithStatus(fiber.StatusBadRequest), ) )
Predefined challenge errors.
var ( ErrPasswordMissingUppercase = result.Err( i18n.T("security_password_missing_uppercase"), result.WithCode(ErrCodePasswordPolicyViolation), result.WithStatus(fiber.StatusBadRequest), ) ErrPasswordMissingLowercase = result.Err( i18n.T("security_password_missing_lowercase"), result.WithCode(ErrCodePasswordPolicyViolation), result.WithStatus(fiber.StatusBadRequest), ) ErrPasswordMissingDigit = result.Err( i18n.T("security_password_missing_digit"), result.WithCode(ErrCodePasswordPolicyViolation), result.WithStatus(fiber.StatusBadRequest), ) ErrPasswordMissingSymbol = result.Err( i18n.T("security_password_missing_symbol"), result.WithCode(ErrCodePasswordPolicyViolation), result.WithStatus(fiber.StatusBadRequest), ) ErrPasswordContainsIdentity = result.Err( i18n.T("security_password_contains_identity"), result.WithCode(ErrCodePasswordPolicyViolation), result.WithStatus(fiber.StatusBadRequest), ) ErrPasswordBlocked = result.Err( i18n.T("security_password_blocked"), result.WithCode(ErrCodePasswordPolicyViolation), result.WithStatus(fiber.StatusBadRequest), ) ErrPasswordReused = result.Err( i18n.T("security_password_reused"), result.WithCode(ErrCodePasswordPolicyViolation), result.WithStatus(fiber.StatusBadRequest), ) )
Predefined password-policy errors (HTTP 400). All carry ErrCodePasswordPolicyViolation; the message states which rule was broken.
var ( ErrDecodeJWTSecretFailed = errors.New("failed to decode jwt secret") ErrGenerateJWTSecretFailed = errors.New("failed to generate jwt secret") ErrDecodeSignatureSecretFailed = errors.New("failed to decode signature secret") ErrSignatureSecretRequired = errors.New("signature secret is required") ErrUserDetailsNotStruct = errors.New("user details type must be a struct or struct pointer") ErrExternalAppDetailsNotStruct = errors.New("external app details type must be a struct or struct pointer") ErrQueryNotQueryBuilder = errors.New("query does not implement QueryBuilder interface") ErrQueryModelNotSet = errors.New("query must call Model() before applying data permission") )
var ( PrincipalSystem = &Principal{ Type: PrincipalTypeSystem, ID: orm.OperatorSystem, Name: "系统", } PrincipalAnonymous = NewUser(orm.OperatorAnonymous, "匿名") )
Functions ¶
func ErrAccountLocked ¶ added in v0.38.0
ErrAccountLocked reports that brute-force protection has blocked further login attempts for the identity (HTTP 429). retryAfter is surfaced to the caller, rounded up to whole minutes (never below one).
func ErrCredentialsInvalid ¶ added in v0.25.1
ErrCredentialsInvalid creates a credentials invalid error with custom message (HTTP 401).
func ErrPasswordTooFewCharClasses ¶ added in v0.38.0
ErrPasswordTooFewCharClasses reports too few distinct character classes (HTTP 400).
func ErrPasswordTooLong ¶ added in v0.38.0
ErrPasswordTooLong reports a password above the maximum length (HTTP 400).
func ErrPasswordTooShort ¶ added in v0.38.0
ErrPasswordTooShort reports a password below the minimum length (HTTP 400).
func ErrPrincipalInvalid ¶ added in v0.25.1
ErrPrincipalInvalid creates a principal invalid error with custom message (HTTP 401).
func GenerateOpaqueToken ¶ added in v0.38.0
GenerateOpaqueToken returns a new high-entropy, URL-safe opaque token.
func GenerateSecret ¶ added in v0.28.0
GenerateSecret returns a cryptographically random, hex-encoded 256-bit secret suitable for JWTConfig.Secret. Use it to provision a per-deployment signing key.
func HashOpaqueToken ¶ added in v0.38.0
HashOpaqueToken returns the lookup key for a token. Sessions are stored under this hash, never under the raw token, so a store leak cannot yield live credentials (the raw token is unrecoverable from its SHA-256 hash).
func PublishRolePermissionsChangedEvent ¶
PublishRolePermissionsChangedEvent publishes a role permissions changed event. If no roles are specified, subscribers should interpret the event as affecting all roles.
func SetExternalAppDetailsType ¶
func SetExternalAppDetailsType[T any]()
SetExternalAppDetailsType configures the process-global target type used to unmarshal the Details field of external-app Principals (PrincipalTypeExternalApp). T must be a struct or struct pointer; any other kind causes an immediate panic.
This function mutates a package-level variable that is read on every Principal deserialization. Call it exactly once at application startup — before the HTTP server begins accepting requests — and never again. Calling it concurrently with in-flight requests is a data race.
func SetUserDetailsType ¶
func SetUserDetailsType[T any]()
SetUserDetailsType configures the process-global target type used to unmarshal the Details field of user Principals (PrincipalTypeUser). T must be a struct or struct pointer; any other kind causes an immediate panic.
This function mutates a package-level variable that is read on every Principal deserialization. Call it exactly once at application startup — before the HTTP server begins accepting requests — and never again. Calling it concurrently with in-flight requests is a data race.
func SubscribeLoginEvent ¶
func SubscribeLoginEvent( bus event.Bus, handler func(context.Context, *LoginEvent) error, opts ...event.SubscribeOption, ) (event.Unsubscribe, error)
SubscribeLoginEvent registers a typed handler for login events. The returned Unsubscribe detaches the subscription.
Types ¶
type AllDataScope ¶
type AllDataScope struct{}
AllDataScope grants access to all data without any restrictions. This is typically used for system administrators or users with full data access.
func (*AllDataScope) Apply ¶
func (*AllDataScope) Apply(*Principal, orm.SelectQuery) error
func (*AllDataScope) Key ¶
func (*AllDataScope) Key() string
func (*AllDataScope) Priority ¶
func (*AllDataScope) Priority() int
type AuthManager ¶
type AuthManager interface {
// Authenticate finds a suitable authenticator and validates the credentials.
Authenticate(ctx context.Context, authentication Authentication) (*Principal, error)
}
AuthManager orchestrates authentication by delegating to registered Authenticators. It iterates through available authenticators to find one that supports the authentication kind and can successfully validate the credentials.
type AuthTokens ¶
type AuthTokens struct {
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken,omitempty"`
}
AuthTokens holds the tokens issued after successful authentication. The refresh token exists only under the stateless JWT mechanism; an opaque login issues a single self-renewing access token and omits the field.
type Authentication ¶
type Authentication struct {
Type string `json:"type"`
Principal string `json:"principal"`
Credentials any `json:"credentials"`
}
Authentication carries the client-supplied authentication payload.
type Authenticator ¶
type Authenticator interface {
// Supports returns true if this authenticator can handle the given authentication type.
Supports(authType string) bool
// Authenticate validates the credentials and returns the authenticated Principal.
Authenticate(ctx context.Context, authentication Authentication) (*Principal, error)
}
Authenticator validates credentials and returns a Principal on success. Multiple authenticators can be registered to support different authentication methods (e.g., JWT, password, OAuth). Each authenticator declares which authentication kinds it supports via the Supports method.
type CachedRolePermissionsLoader ¶
type CachedRolePermissionsLoader struct {
// contains filtered or unexported fields
}
CachedRolePermissionsLoader is a decorator that adds caching to a RolePermissionsLoader, invalidating entries on RolePermissionsChangedEvent.
func (*CachedRolePermissionsLoader) LoadPermissions ¶
type ChallengeProvider ¶
type ChallengeProvider interface {
// Type returns the unique challenge type identifier (e.g. "totp", "select_department").
Type() string
// Order returns the evaluation priority. Lower values are evaluated first.
Order() int
// Evaluate checks whether this challenge applies to the given principal.
// Return nil to indicate the challenge is not needed.
Evaluate(ctx context.Context, principal *Principal) (*LoginChallenge, error)
// Resolve validates the user's response and returns an optionally updated Principal.
Resolve(ctx context.Context, principal *Principal, response any) (*Principal, error)
}
ChallengeProvider evaluates and resolves a login challenge. Register implementations via vef.ProvideChallengeProvider to inject additional steps into the login flow (e.g., 2FA, department selection).
Providers are evaluated sequentially in Order() ascending order. Each challenge is presented and resolved one at a time before the next provider is evaluated.
type ChallengeState ¶
type ChallengeState struct {
Principal *Principal
// Username is the original login identifier the applicant supplied at the
// first login step. It is carried across challenge steps so audit events
// emitted after an MFA challenge report the same identifier as the initial
// login, independent of the principal's display name.
Username string
Pending []string
Resolved []string
}
ChallengeState holds the state tracked by a challenge token.
type ChallengeTokenStore ¶
type ChallengeTokenStore interface {
// Generate creates a challenge token encoding the principal, the original
// login identifier, and the challenge state. ctx lets I/O-backed
// implementations honor deadlines, cancellation, and trace propagation.
Generate(ctx context.Context, principal *Principal, username string, pending, resolved []string) (string, error)
// Parse retrieves the challenge state from a token.
Parse(ctx context.Context, token string) (*ChallengeState, error)
}
ChallengeTokenStore manages the lifecycle of challenge tokens. Challenge tokens carry the intermediate state between login steps, allowing the login flow to pause for user input (e.g., 2FA code, department selection). The default implementation uses JWT; alternatives (e.g., Redis) can be swapped via DI.
func NewJWTChallengeTokenStore ¶
func NewJWTChallengeTokenStore(jwt *JWT) ChallengeTokenStore
NewJWTChallengeTokenStore creates a new JWT-based challenge token store.
func NewMemoryChallengeTokenStore ¶
func NewMemoryChallengeTokenStore() ChallengeTokenStore
NewMemoryChallengeTokenStore creates a new memory-backed challenge token store.
func NewRedisChallengeTokenStore ¶
func NewRedisChallengeTokenStore(client *redis.Client) ChallengeTokenStore
NewRedisChallengeTokenStore creates a new Redis-backed challenge token store.
type DataPermissionApplier ¶
type DataPermissionApplier interface {
// Apply adds data permission filters to the query based on the current context.
Apply(query orm.SelectQuery) error
}
DataPermissionApplier applies data permission filters to database queries. Wraps the resolution and application of DataScope into a single operation.
func NewRequestScopedDataPermApplier ¶
func NewRequestScopedDataPermApplier( principal *Principal, dataScope DataScope, logger logx.Logger, ) DataPermissionApplier
NewRequestScopedDataPermApplier creates a new request-scoped data permission applier. This function is typically called by the data permission middleware for each request.
type DataPermissionResolver ¶
type DataPermissionResolver interface {
// ResolveDataScope returns the DataScope that should be applied for the permission.
ResolveDataScope(ctx context.Context, principal *Principal, permission string) (DataScope, error)
}
DataPermissionResolver determines the applicable DataScope for a permission. Used to translate permission tokens into concrete data filtering rules.
type DataScope ¶
type DataScope interface {
// Key returns a unique identifier for this data scope type.
Key() string
// Priority determines the order when multiple scopes apply (lower = higher priority).
Priority() int
// Supports returns true if this scope applies to the given Principal and table.
Supports(principal *Principal, table *orm.Table) bool
// Apply modifies the query to enforce the data scope restrictions.
Apply(principal *Principal, query orm.SelectQuery) error
}
DataScope defines row-level data access restrictions. Implementations filter query results based on the Principal's permissions, enabling multi-tenant data isolation or hierarchical data access control.
func NewAllDataScope ¶
func NewAllDataScope() DataScope
NewAllDataScope creates a new AllDataScope instance.
func NewSelfDataScope ¶
NewSelfDataScope creates a new SelfDataScope instance. The createdByColumn parameter specifies the database column name for the creator. If empty, it defaults to "created_by".
type DeliveredCodeSender ¶
type DeliveredCodeSender struct {
// contains filtered or unexported fields
}
DeliveredCodeSender orchestrates OTPCodeStore and OTPCodeDelivery to implement OTPCodeSender. Flow: generate code -> store it -> deliver through the channel.
func NewDeliveredCodeSender ¶
func NewDeliveredCodeSender(store OTPCodeStore, delivery OTPCodeDelivery) *DeliveredCodeSender
NewDeliveredCodeSender creates a DeliveredCodeSender that generates codes via store and sends them via delivery.
type DeliveredCodeVerifier ¶
type DeliveredCodeVerifier struct {
// contains filtered or unexported fields
}
DeliveredCodeVerifier delegates to OTPCodeStore to verify codes, implementing OTPCodeVerifier.
func NewDeliveredCodeVerifier ¶
func NewDeliveredCodeVerifier(store OTPCodeStore) *DeliveredCodeVerifier
NewDeliveredCodeVerifier creates a DeliveredCodeVerifier backed by the given store.
type DepartmentLoader ¶
type DepartmentLoader interface {
// LoadDepartments returns the departments available to the user.
// Return nil or an empty slice to skip the challenge.
LoadDepartments(ctx context.Context, principal *Principal) ([]DepartmentOption, error)
}
DepartmentLoader loads the list of departments available to a user.
type DepartmentOption ¶
DepartmentOption represents a selectable department.
type DepartmentSelectionChallengeData ¶
type DepartmentSelectionChallengeData struct {
Departments []DepartmentOption `json:"departments"`
Meta map[string]any `json:"meta,omitempty"`
}
DepartmentSelectionChallengeData describes the metadata for a department selection challenge.
type DepartmentSelectionChallengeProvider ¶
type DepartmentSelectionChallengeProvider struct {
// contains filtered or unexported fields
}
DepartmentSelectionChallengeProvider orchestrates department selection evaluation and resolution. It implements the ChallengeProvider interface.
func NewDepartmentSelectionChallengeProvider ¶
func NewDepartmentSelectionChallengeProvider(loader DepartmentLoader, selector DepartmentSelector) *DepartmentSelectionChallengeProvider
NewDepartmentSelectionChallengeProvider creates a department selection challenge provider. Default type "department_selection", order 500. Panics if loader or selector is nil.
func (*DepartmentSelectionChallengeProvider) Evaluate ¶
func (p *DepartmentSelectionChallengeProvider) Evaluate(ctx context.Context, principal *Principal) (*LoginChallenge, error)
func (*DepartmentSelectionChallengeProvider) Order ¶
func (*DepartmentSelectionChallengeProvider) Order() int
func (*DepartmentSelectionChallengeProvider) Type ¶
func (*DepartmentSelectionChallengeProvider) Type() string
type DepartmentSelector ¶
type DepartmentSelector interface {
// SelectDepartment validates the department choice and returns an enriched principal.
SelectDepartment(ctx context.Context, principal *Principal, departmentID string) (*Principal, error)
}
DepartmentSelector validates the user's department selection and enriches the principal.
type ExpiryPasswordChangeChecker ¶ added in v0.38.0
type ExpiryPasswordChangeChecker struct {
// contains filtered or unexported fields
}
ExpiryPasswordChangeChecker forces a password change once the password's age exceeds maxAge. It implements PasswordChangeChecker, so it plugs into the forced-change challenge flow (compose it with other checkers via NewCompositePasswordChangeChecker).
func NewExpiryPasswordChangeChecker ¶ added in v0.38.0
func NewExpiryPasswordChangeChecker(loader PasswordMetadataLoader, maxAge time.Duration) *ExpiryPasswordChangeChecker
NewExpiryPasswordChangeChecker creates an expiry checker. A non-positive maxAge disables expiry so Check always returns nil. Panics if loader is nil.
func (*ExpiryPasswordChangeChecker) Check ¶ added in v0.38.0
func (c *ExpiryPasswordChangeChecker) Check(ctx context.Context, principal *Principal) (*PasswordChangeChallengeData, error)
Check returns the expired challenge when the password's age exceeds maxAge.
type ExternalAppConfig ¶
type ExternalAppConfig struct {
Enabled bool `json:"enabled"`
IPWhitelist string `json:"ipWhitelist"`
}
ExternalAppConfig holds configuration for an external application.
type ExternalAppLoader ¶
type ExternalAppLoader interface {
// LoadByID retrieves an external app by its ID, returning the Principal,
// secret key for signature verification, and any error.
LoadByID(ctx context.Context, id string) (*Principal, string, error)
}
ExternalAppLoader retrieves external application credentials for API authentication. Used by OpenAPI authenticator to validate app-based signature authentication.
type IPWhitelist ¶ added in v0.34.0
type IPWhitelist struct {
// Entries lists the allowed IP addresses and CIDR ranges,
// e.g. "10.0.0.1", "192.168.0.0/16".
Entries []string
}
IPWhitelist describes a named source-IP whitelist resolved by an IPWhitelistLoader.
type IPWhitelistLoader ¶ added in v0.34.0
type IPWhitelistLoader interface {
// LoadByName returns the named whitelist, or nil when the name is unknown.
LoadByName(ctx context.Context, name string) (*IPWhitelist, error)
}
IPWhitelistLoader resolves named IP whitelists for the "ip" auth strategy. The framework ships a configuration-backed implementation (vef.security.ip_whitelists); applications may register their own to load whitelists from a database, a config center, or any other source. Matching against the resolved entries always stays in the framework (IPWhitelistValidator), so every implementation shares the same fail-closed semantics.
type IPWhitelistValidator ¶
type IPWhitelistValidator struct {
// contains filtered or unexported fields
}
IPWhitelistValidator validates IP addresses against a whitelist. It supports both individual IP addresses and CIDR notation.
func NewIPWhitelistValidator ¶
func NewIPWhitelistValidator(whitelist string) *IPWhitelistValidator
NewIPWhitelistValidator creates a new IP whitelist validator from a comma-separated string. Supports individual IP addresses (e.g., "192.168.1.1") and CIDR notation (e.g., "192.168.1.0/24"). An empty whitelist means all IPs are allowed.
func NewIPWhitelistValidatorFromEntries ¶ added in v0.34.0
func NewIPWhitelistValidatorFromEntries(entries []string) *IPWhitelistValidator
NewIPWhitelistValidatorFromEntries creates a new IP whitelist validator from individual entries, each a single IP address (e.g., "192.168.1.1") or CIDR range (e.g., "192.168.1.0/24"). Blank entries are skipped; an empty entry list means all IPs are allowed.
func (*IPWhitelistValidator) IsAllowed ¶
func (v *IPWhitelistValidator) IsAllowed(ipStr string) bool
IsAllowed checks if the given IP address is in the whitelist.
func (*IPWhitelistValidator) IsEmpty ¶
func (v *IPWhitelistValidator) IsEmpty() bool
IsEmpty returns true if the whitelist is empty (no restrictions).
type JWT ¶
type JWT struct {
// contains filtered or unexported fields
}
JWT provides low-level JWT token operations. It handles token generation, parsing, and validation without business logic.
func NewJWT ¶
NewJWT creates a new JWT instance with the given configuration. Secret expects a hex-encoded string; invalid hex will cause an error. Audience will be defaulted when empty.
type JWTChallengeTokenStore ¶
type JWTChallengeTokenStore struct {
// contains filtered or unexported fields
}
JWTChallengeTokenStore implements ChallengeTokenStore using stateless JWT tokens. Challenge state (principal, pending/resolved types) is encoded directly in the token, avoiding server-side session storage.
func (*JWTChallengeTokenStore) Parse ¶
func (s *JWTChallengeTokenStore) Parse(_ context.Context, token string) (*ChallengeState, error)
type JWTClaimsAccessor ¶
type JWTClaimsAccessor struct {
// contains filtered or unexported fields
}
func NewJWTClaimsAccessor ¶
func NewJWTClaimsAccessor(claims jwt.MapClaims) *JWTClaimsAccessor
NewJWTClaimsAccessor creates a new JWT claims accessor.
func (*JWTClaimsAccessor) Claim ¶
func (a *JWTClaimsAccessor) Claim(key string) any
Claim returns the claim.
func (*JWTClaimsAccessor) Details ¶
func (a *JWTClaimsAccessor) Details() any
Details returns the details claim.
func (*JWTClaimsAccessor) ID ¶
func (a *JWTClaimsAccessor) ID() string
ID returns the JWT ID claim. Returns empty string if the claim is missing or not a string.
func (*JWTClaimsAccessor) Roles ¶
func (a *JWTClaimsAccessor) Roles() []string
Roles returns the roles claim. Supports both []string and []any payloads; returns empty slice if absent.
func (*JWTClaimsAccessor) Subject ¶
func (a *JWTClaimsAccessor) Subject() string
Subject returns the subject claim. Returns empty string if the claim is missing or not a string.
func (*JWTClaimsAccessor) Type ¶
func (a *JWTClaimsAccessor) Type() string
Type returns the token type claim. Returns empty string if the claim is missing or not a string.
type JWTClaimsBuilder ¶
type JWTClaimsBuilder struct {
// contains filtered or unexported fields
}
JWTClaimsBuilder helps build JWT claims for different token types.
func NewJWTClaimsBuilder ¶
func NewJWTClaimsBuilder() *JWTClaimsBuilder
NewJWTClaimsBuilder creates a new JWT claims builder.
func (*JWTClaimsBuilder) Claim ¶
func (b *JWTClaimsBuilder) Claim(key string) (any, bool)
Claim returns a custom claim.
func (*JWTClaimsBuilder) Details ¶
func (b *JWTClaimsBuilder) Details() (any, bool)
Details returns the details claim.
func (*JWTClaimsBuilder) ID ¶
func (b *JWTClaimsBuilder) ID() (string, bool)
ID returns the JWT ID claim.
func (*JWTClaimsBuilder) Roles ¶
func (b *JWTClaimsBuilder) Roles() ([]string, bool)
Roles returns the roles claim.
func (*JWTClaimsBuilder) Subject ¶
func (b *JWTClaimsBuilder) Subject() (string, bool)
Subject returns the subject claim.
func (*JWTClaimsBuilder) Type ¶
func (b *JWTClaimsBuilder) Type() (string, bool)
Type returns the token type claim.
func (*JWTClaimsBuilder) WithClaim ¶
func (b *JWTClaimsBuilder) WithClaim(key string, value any) *JWTClaimsBuilder
func (*JWTClaimsBuilder) WithDetails ¶
func (b *JWTClaimsBuilder) WithDetails(details any) *JWTClaimsBuilder
func (*JWTClaimsBuilder) WithID ¶
func (b *JWTClaimsBuilder) WithID(id string) *JWTClaimsBuilder
func (*JWTClaimsBuilder) WithRoles ¶
func (b *JWTClaimsBuilder) WithRoles(roles []string) *JWTClaimsBuilder
func (*JWTClaimsBuilder) WithSubject ¶
func (b *JWTClaimsBuilder) WithSubject(subject string) *JWTClaimsBuilder
func (*JWTClaimsBuilder) WithType ¶
func (b *JWTClaimsBuilder) WithType(typ string) *JWTClaimsBuilder
type JWTConfig ¶
type JWTConfig struct {
Secret string // Secret key for JWT signing
Audience string // JWT audience
}
JWTConfig is the configuration for the JWT token.
type LockoutKey ¶ added in v0.38.0
type LockoutKey string
LockoutKey selects the identity dimension a LoginGuard counts failures by.
const ( // LockoutKeyUser counts failures per login identifier. LockoutKeyUser LockoutKey = "user" // LockoutKeyIP counts failures per source address. LockoutKeyIP LockoutKey = "ip" // LockoutKeyUserIP counts failures per identifier-and-source pair. LockoutKeyUserIP LockoutKey = "user_ip" )
type LockoutPolicy ¶ added in v0.38.0
type LockoutPolicy struct {
// MaxFailures is the number of failures tolerated before a penalty engages.
MaxFailures int
// Window is how long failures are remembered before the counter resets.
Window time.Duration
// LockDuration is the block length under the lock strategy.
LockDuration time.Duration
// Strategy selects lock vs. backoff.
Strategy LockoutStrategy
// BackoffBase is the first backoff delay past the threshold; it doubles per
// further failure.
BackoffBase time.Duration
// BackoffMax caps the per-attempt backoff delay.
BackoffMax time.Duration
// Key selects the dimension failures are counted by.
Key LockoutKey
}
LockoutPolicy is the fully-resolved brute-force policy a LoginGuard enforces. The framework builds it from config; an application constructing a guard directly must populate every field, as a zero policy imposes no lockout.
type LockoutStrategy ¶ added in v0.38.0
type LockoutStrategy string
LockoutStrategy selects how a LoginGuard penalizes repeated failures. It mirrors config.LockoutStrategy as the resolved domain value the guard acts on.
const ( // LockoutStrategyLock blocks all attempts for a fixed duration once the // failure threshold is reached. LockoutStrategyLock LockoutStrategy = "lock" // LockoutStrategyBackoff imposes an exponentially growing delay past the // threshold instead of a hard lock. LockoutStrategyBackoff LockoutStrategy = "backoff" )
type LoginAttempt ¶ added in v0.38.0
type LoginAttempt struct {
// Identity is the login identifier supplied by the client (the username).
Identity string
// ClientIP is the resolved source address of the request.
ClientIP string
}
LoginAttempt identifies a single login attempt for brute-force accounting.
type LoginChallenge ¶
type LoginChallenge struct {
Type string `json:"type"`
Data any `json:"data,omitempty"`
Required bool `json:"required"`
}
LoginChallenge describes a challenge the user must complete during login.
type LoginDecision ¶ added in v0.38.0
type LoginDecision struct {
// Allowed reports whether the attempt may proceed.
Allowed bool
// RetryAfter is how long the caller should wait before retrying when the
// attempt is blocked; it is zero when Allowed is true.
RetryAfter time.Duration
}
LoginDecision is the verdict a LoginGuard returns for an attempt.
type LoginEvent ¶
type LoginEvent struct {
AuthType string `json:"authType"`
UserID *string `json:"userId"` // Populated on success
Username string `json:"username"`
LoginIP string `json:"loginIp"`
UserAgent string `json:"userAgent"`
TraceID string `json:"traceId"`
IsOk bool `json:"isOk"`
FailReason string `json:"failReason"` // Populated on failure
ErrorCode int `json:"errorCode"`
}
LoginEvent represents a user login attempt — successful or otherwise.
func NewLoginEvent ¶
func NewLoginEvent(params LoginEventParams) *LoginEvent
NewLoginEvent creates a new login event with the given parameters.
func (*LoginEvent) EventType ¶ added in v0.24.0
func (*LoginEvent) EventType() string
EventType implements event.Event.
type LoginEventParams ¶
type LoginEventParams struct {
AuthType string
UserID *string
Username string
LoginIP string
UserAgent string
TraceID string
IsOk bool
FailReason string
ErrorCode int
}
LoginEventParams contains parameters for creating a LoginEvent.
type LoginGuard ¶ added in v0.38.0
type LoginGuard interface {
// Check reports whether an attempt for the identity may proceed now, without
// recording anything.
Check(ctx context.Context, attempt LoginAttempt) (LoginDecision, error)
// RecordFailure registers a failed attempt and returns the resulting
// decision (whether the identity is now blocked, and for how long).
RecordFailure(ctx context.Context, attempt LoginAttempt) (LoginDecision, error)
// RecordSuccess clears any accumulated failure state for the identity.
RecordSuccess(ctx context.Context, attempt LoginAttempt) error
}
LoginGuard tracks failed login attempts and decides whether an identity may currently attempt authentication, providing brute-force protection through a fixed-window lock or an exponential backoff.
func NewMemoryLoginGuard ¶ added in v0.38.0
func NewMemoryLoginGuard(policy LockoutPolicy) LoginGuard
NewMemoryLoginGuard creates an in-memory login guard governed by policy.
func NewRedisLoginGuard ¶ added in v0.38.0
func NewRedisLoginGuard(client *redis.Client, policy LockoutPolicy) LoginGuard
NewRedisLoginGuard creates a Redis-backed login guard governed by policy.
type LoginResult ¶
type LoginResult struct {
Tokens *AuthTokens `json:"tokens,omitempty"`
ChallengeToken string `json:"challengeToken,omitempty"`
Challenge *LoginChallenge `json:"challenge,omitempty"`
}
LoginResult represents the response of a login attempt. When a challenge is pending, Tokens is nil and ChallengeToken + Challenge are set. When all challenges are resolved (or none were needed), Tokens is set.
type MemoryChallengeTokenStore ¶
type MemoryChallengeTokenStore struct {
// contains filtered or unexported fields
}
MemoryChallengeTokenStore implements ChallengeTokenStore using an in-memory cache. Suitable for single-instance deployments or testing; for distributed setups use Redis-backed stores.
func (*MemoryChallengeTokenStore) Parse ¶
func (s *MemoryChallengeTokenStore) Parse(ctx context.Context, token string) (*ChallengeState, error)
type MemoryLoginGuard ¶ added in v0.38.0
type MemoryLoginGuard struct {
// contains filtered or unexported fields
}
MemoryLoginGuard implements LoginGuard with in-memory counters. It is suitable for single-instance deployments; multi-node deployments should use RedisLoginGuard so the failure counters are shared across nodes.
func (*MemoryLoginGuard) Check ¶ added in v0.38.0
func (g *MemoryLoginGuard) Check(ctx context.Context, attempt LoginAttempt) (LoginDecision, error)
Check reports whether the identity is currently within a cooldown window.
func (*MemoryLoginGuard) RecordFailure ¶ added in v0.38.0
func (g *MemoryLoginGuard) RecordFailure(ctx context.Context, attempt LoginAttempt) (LoginDecision, error)
RecordFailure increments the failure counter and, once the threshold is exceeded, opens a cooldown window per the policy.
func (*MemoryLoginGuard) RecordSuccess ¶ added in v0.38.0
func (g *MemoryLoginGuard) RecordSuccess(ctx context.Context, attempt LoginAttempt) error
RecordSuccess clears the failure counter and any open cooldown.
type MemoryNonceStore ¶
type MemoryNonceStore struct {
// contains filtered or unexported fields
}
MemoryNonceStore implements NonceStore using an in-memory cache. This implementation is suitable for development and single-instance deployments. For distributed systems, use RedisNonceStore instead.
func (*MemoryNonceStore) StoreIfAbsent ¶
func (m *MemoryNonceStore) StoreIfAbsent(ctx context.Context, appID, nonce string, ttl time.Duration) (bool, error)
StoreIfAbsent atomically stores the nonce only when it does not exist.
type MemorySessionStore ¶ added in v0.38.0
type MemorySessionStore struct {
// contains filtered or unexported fields
}
MemorySessionStore implements SessionStore on the framework's in-memory TTL cache, so expired sessions are reclaimed by the cache's lazy checks and background GC instead of accumulating for the process lifetime. It suits single-instance deployments; multi-node deployments must use RedisSessionStore so sessions are shared across nodes.
There is no per-user index: ListByUser and ListAll scan all live sessions, which is fine at the single-node scale this store targets (mirroring the Redis store's keyspace-scan trade-off for ListAll).
func (*MemorySessionStore) ListAll ¶ added in v0.38.0
func (s *MemorySessionStore) ListAll(ctx context.Context) ([]Session, error)
ListAll returns every live session across all users, newest activity first.
func (*MemorySessionStore) ListByUser ¶ added in v0.38.0
func (*MemorySessionStore) Revoke ¶ added in v0.38.0
func (s *MemorySessionStore) Revoke(ctx context.Context, id string) error
func (*MemorySessionStore) RevokeUser ¶ added in v0.38.0
func (s *MemorySessionStore) RevokeUser(ctx context.Context, userID string) error
type NonceStore ¶
type NonceStore interface {
// StoreIfAbsent atomically stores a nonce only when it does not already exist.
// It returns true when the nonce was newly stored, false when the nonce already existed.
// The TTL should be slightly longer than timestamp tolerance to ensure
// nonces remain valid while their corresponding timestamps are accepted.
StoreIfAbsent(ctx context.Context, appID, nonce string, ttl time.Duration) (bool, error)
}
NonceStore manages nonce lifecycle for replay attack prevention. Stores used nonces with TTL to detect and reject duplicate requests. Implementations must be thread-safe for concurrent access.
func NewMemoryNonceStore ¶
func NewMemoryNonceStore() NonceStore
NewMemoryNonceStore creates a new in-memory nonce store.
func NewRedisNonceStore ¶
func NewRedisNonceStore(client *redis.Client) NonceStore
NewRedisNonceStore creates a new Redis-backed nonce store.
type OTPChallengeData ¶
type OTPChallengeData struct {
Destination string `json:"destination"`
Meta map[string]any `json:"meta,omitempty"`
}
OTPChallengeData describes metadata presented to the user for an OTP challenge.
type OTPChallengeProvider ¶
type OTPChallengeProvider struct {
// contains filtered or unexported fields
}
OTPChallengeProvider orchestrates OTP evaluation, sending, and verification. It implements the ChallengeProvider interface.
func NewDeliveredChallengeProvider ¶
func NewDeliveredChallengeProvider(challengeType string, order int, evaluator OTPEvaluator, store OTPCodeStore, delivery OTPCodeDelivery) *OTPChallengeProvider
NewDeliveredChallengeProvider creates an OTP challenge provider backed by OTPCodeStore and OTPCodeDelivery.
func NewEmailChallengeProvider ¶
func NewEmailChallengeProvider(evaluator OTPEvaluator, store OTPCodeStore, delivery OTPCodeDelivery) *OTPChallengeProvider
NewEmailChallengeProvider creates an Email OTP challenge provider. Default type "email_otp", order 300.
func NewOTPChallengeProvider ¶
func NewOTPChallengeProvider(config OTPChallengeProviderConfig) *OTPChallengeProvider
NewOTPChallengeProvider creates a generic OTP challenge provider. ChallengeType, Evaluator, and Verifier are required; panics if any is missing.
func NewSMSChallengeProvider ¶
func NewSMSChallengeProvider(evaluator OTPEvaluator, store OTPCodeStore, delivery OTPCodeDelivery) *OTPChallengeProvider
NewSMSChallengeProvider creates an SMS OTP challenge provider. Default type "sms_otp", order 200.
func NewTOTPChallengeProvider ¶
func NewTOTPChallengeProvider(loader TOTPSecretLoader, opts ...TOTPOption) *OTPChallengeProvider
NewTOTPChallengeProvider creates a TOTP challenge provider. Only TOTPSecretLoader needs to be implemented by the application. Default type "totp", order 100, destination "Authenticator App".
func (*OTPChallengeProvider) Evaluate ¶
func (p *OTPChallengeProvider) Evaluate(ctx context.Context, principal *Principal) (*LoginChallenge, error)
func (*OTPChallengeProvider) Order ¶
func (p *OTPChallengeProvider) Order() int
func (*OTPChallengeProvider) Type ¶
func (p *OTPChallengeProvider) Type() string
type OTPChallengeProviderConfig ¶
type OTPChallengeProviderConfig struct {
ChallengeType string // Required, unique identifier (e.g. "totp", "sms_otp").
ChallengeOrder int // Evaluation priority; lower values are evaluated first.
Evaluator OTPEvaluator // Required.
Sender OTPCodeSender // Optional; nil skips the send step.
Verifier OTPCodeVerifier // Required.
}
OTPChallengeProviderConfig configures an OTPChallengeProvider.
type OTPCodeDelivery ¶
type OTPCodeDelivery interface {
// Deliver sends the given OTP code to the principal via the configured channel.
Deliver(ctx context.Context, principal *Principal, code string) error
}
OTPCodeDelivery sends a generated OTP code to the user through a specific channel (SMS, email, etc.).
type OTPCodeSender ¶
type OTPCodeSender interface {
// Send triggers the delivery of an OTP code to the given principal.
Send(ctx context.Context, principal *Principal) error
}
OTPCodeSender triggers OTP code delivery. For TOTP this is nil (codes are generated by an authenticator app); for SMS/Email this sends the code through the chosen channel.
type OTPCodeStore ¶
type OTPCodeStore interface {
// Generate creates a new OTP code, stores it, and returns the generated code.
Generate(ctx context.Context, principal *Principal) (string, error)
// Verify checks whether the submitted code matches the stored code.
Verify(ctx context.Context, principal *Principal, code string) (bool, error)
}
OTPCodeStore manages the lifecycle of server-generated OTP codes. Used for SMS/Email flows where the server generates, stores, and verifies codes.
type OTPCodeVerifier ¶
type OTPCodeVerifier interface {
// Verify checks whether the submitted code is valid for the given principal.
Verify(ctx context.Context, principal *Principal, code string) (bool, error)
}
OTPCodeVerifier validates a user-submitted OTP code.
type OTPEvaluator ¶
type OTPEvaluator interface {
// Evaluate checks the principal and returns challenge data if OTP is required.
// Return nil to skip the challenge; non-nil triggers a challenge.
Evaluate(ctx context.Context, principal *Principal) (*OTPChallengeData, error)
}
OTPEvaluator determines whether a user needs OTP verification.
type PasswordChangeChallengeData ¶
type PasswordChangeChallengeData struct {
Reason string `json:"reason"`
Meta map[string]any `json:"meta,omitempty"`
}
PasswordChangeChallengeData describes the metadata for a forced password change challenge.
type PasswordChangeChallengeProvider ¶
type PasswordChangeChallengeProvider struct {
// contains filtered or unexported fields
}
PasswordChangeChallengeProvider orchestrates forced password change evaluation and resolution. It implements the ChallengeProvider interface.
func NewPasswordChangeChallengeProvider ¶
func NewPasswordChangeChallengeProvider(checker PasswordChangeChecker, changer PasswordChanger, validator PasswordValidator) *PasswordChangeChallengeProvider
NewPasswordChangeChallengeProvider creates a forced password change challenge provider. Default type "password_change", order 400. The validator enforces password strength before the new password is persisted; pass nil to skip strength validation. Panics if checker or changer is nil.
func (*PasswordChangeChallengeProvider) Evaluate ¶
func (p *PasswordChangeChallengeProvider) Evaluate(ctx context.Context, principal *Principal) (*LoginChallenge, error)
func (*PasswordChangeChallengeProvider) Order ¶
func (*PasswordChangeChallengeProvider) Order() int
func (*PasswordChangeChallengeProvider) Type ¶
func (*PasswordChangeChallengeProvider) Type() string
type PasswordChangeChecker ¶
type PasswordChangeChecker interface {
// Check returns challenge data (including reason) if a password change is required,
// or nil if no change is needed.
Check(ctx context.Context, principal *Principal) (*PasswordChangeChallengeData, error)
}
PasswordChangeChecker determines whether a user must change their password.
func NewCompositePasswordChangeChecker ¶ added in v0.38.0
func NewCompositePasswordChangeChecker(checkers ...PasswordChangeChecker) PasswordChangeChecker
NewCompositePasswordChangeChecker runs checkers in order and returns the first one that requires a change, letting several reasons (first login, expiry, …) share one forced-change challenge. Nil checkers are skipped.
type PasswordChanger ¶
type PasswordChanger interface {
// ChangePassword validates password strength and persists the new password.
ChangePassword(ctx context.Context, principal *Principal, newPassword string) error
}
PasswordChanger validates and persists a new password.
type PasswordDecryptor ¶
type PasswordDecryptor interface {
// Decrypt transforms an encrypted password back to plaintext for verification.
Decrypt(encryptedPassword string) (string, error)
}
PasswordDecryptor decrypts client-side encrypted passwords before verification. Used when passwords are encrypted during transmission for additional security.
type PasswordHistoryStore ¶ added in v0.38.0
type PasswordHistoryStore interface {
// Recent returns the subject's most recent encoded passwords, newest first,
// capped at limit.
Recent(ctx context.Context, principalID string, limit int) ([]string, error)
// Add records encodedPassword as the subject's newest history entry. Call it
// from PasswordChanger.ChangePassword when a new password is persisted.
Add(ctx context.Context, principalID, encodedPassword string) error
}
PasswordHistoryStore persists a subject's previously used password hashes so a new password can be rejected if it repeats a recent one. The application owns the store (the user database belongs to it); the framework only reads history to check reuse and performs the hash comparison itself, so implementations never touch the password.Encoder.
type PasswordMetadataLoader ¶ added in v0.38.0
type PasswordMetadataLoader interface {
// PasswordChangedAt returns when the principal's password was last set. A
// zero time means the timestamp is unknown, which the expiry checker treats
// as not-yet-expired rather than forcing a change on incomplete data.
PasswordChangedAt(ctx context.Context, principal *Principal) (time.Time, error)
}
PasswordMetadataLoader exposes password metadata the framework needs but does not own, since the user store belongs to the application. It is the extension point behind password-expiry enforcement.
type PasswordRule ¶ added in v0.38.0
type PasswordRule interface {
// Check returns a non-nil error when plaintext violates the rule, or nil
// when it satisfies the rule.
Check(principal *Principal, plaintext string) error
}
PasswordRule is a single composable password-policy constraint.
func NewBlocklistRule ¶ added in v0.38.0
func NewBlocklistRule(entries []string) PasswordRule
NewBlocklistRule rejects passwords that match any blocked entry (case-insensitive). Entries are compared verbatim after trimming; supply a deny list of well-known weak passwords for the deployment.
func NewCharacterClassRule ¶ added in v0.38.0
func NewCharacterClassRule(requireUpper, requireLower, requireDigit, requireSymbol bool, minClasses int) PasswordRule
NewCharacterClassRule enforces required character classes and, when minClasses > 0, a minimum count of distinct classes present. The four classes are uppercase, lowercase, digit, and symbol (any non-space, non-letter, non-digit rune); caseless letters such as CJK count toward no class.
func NewDisallowIdentityRule ¶ added in v0.38.0
func NewDisallowIdentityRule() PasswordRule
NewDisallowIdentityRule rejects a password that contains the principal's login id or display name (case-insensitive), the most common weak-password pattern.
func NewMaxLengthRule ¶ added in v0.38.0
func NewMaxLengthRule(maxLength int) PasswordRule
NewMaxLengthRule requires at most maxLength characters (counted as runes). A bound guards against slow-KDF denial of service and silent bcrypt truncation.
func NewMinLengthRule ¶ added in v0.38.0
func NewMinLengthRule(minLength int) PasswordRule
NewMinLengthRule requires at least minLength characters (counted as runes).
type PasswordValidator ¶ added in v0.38.0
type PasswordValidator interface {
// Validate returns a non-nil error (a result.Error carrying an i18n message
// and a 400 status) describing the first policy violation, or nil when the
// password is acceptable. The principal enables context-aware rules such as
// rejecting a password that echoes the account identity.
Validate(ctx context.Context, principal *Principal, plaintext string) error
}
PasswordValidator checks a candidate plaintext password against a policy. The framework builds one from configuration and injects it; applications can also call it directly from their own registration or reset flows.
func NewChainValidator ¶ added in v0.38.0
func NewChainValidator(validators ...PasswordValidator) PasswordValidator
NewChainValidator composes validators into one that returns the first violation, letting strength rules and history checks share a single PasswordValidator. Nil validators are skipped.
func NewHistoryValidator ¶ added in v0.38.0
func NewHistoryValidator(store PasswordHistoryStore, encoder password.Encoder, depth int) PasswordValidator
NewHistoryValidator rejects a password that matches any of the subject's last depth entries. depth ≤ 0 disables the check. Comparison uses encoder because each stored hash carries its own salt.
func NewRuleBasedValidator ¶ added in v0.38.0
func NewRuleBasedValidator(rules ...PasswordRule) PasswordValidator
NewRuleBasedValidator composes rules into a PasswordValidator that returns the first violation. With no rules it accepts every password, so an unconfigured policy imposes no constraint.
type PermissionChecker ¶
type PermissionChecker interface {
// HasPermission returns true if the Principal has the specified permission token.
HasPermission(ctx context.Context, principal *Principal, permission string) (bool, error)
}
PermissionChecker verifies if a Principal has a specific permission. Used by authorization middleware to enforce access control on API endpoints.
type Principal ¶
type Principal struct {
// Type is the type of the principal.
Type PrincipalType `json:"type"`
// ID is the id of the user.
ID string `json:"id"`
// Name is the name of the user.
Name string `json:"name"`
// Roles is the roles of the user.
Roles []string `json:"roles"`
// Details is the details of the user.
Details any `json:"details"`
}
Principal is the principal of the user.
func NewExternalApp ¶
NewExternalApp is the function to create a new external app principal.
func (*Principal) AttemptUnmarshalDetails ¶
AttemptUnmarshalDetails attempts to unmarshal the details into the principal.
func (*Principal) UnmarshalJSON ¶
UnmarshalJSON implements custom JSON unmarshaling for Principal. This allows the Details field to be properly deserialized based on the Type field.
type PrincipalType ¶
type PrincipalType string
PrincipalType is the type of the principal.
const ( // PrincipalTypeUser is the type of the user. PrincipalTypeUser PrincipalType = "user" // PrincipalTypeExternalApp is the type of the external app. PrincipalTypeExternalApp PrincipalType = "external_app" // PrincipalTypeSystem is the type of the system. PrincipalTypeSystem PrincipalType = orm.OperatorSystem )
type RedisChallengeTokenStore ¶
type RedisChallengeTokenStore struct {
// contains filtered or unexported fields
}
RedisChallengeTokenStore implements ChallengeTokenStore using Redis for distributed deployments.
func (*RedisChallengeTokenStore) Parse ¶
func (s *RedisChallengeTokenStore) Parse(ctx context.Context, token string) (*ChallengeState, error)
type RedisLoginGuard ¶ added in v0.38.0
type RedisLoginGuard struct {
// contains filtered or unexported fields
}
RedisLoginGuard implements LoginGuard with Redis-backed counters shared across all nodes, the correct choice for multi-node deployments.
func (*RedisLoginGuard) Check ¶ added in v0.38.0
func (g *RedisLoginGuard) Check(ctx context.Context, attempt LoginAttempt) (LoginDecision, error)
Check reports whether an unexpired cooldown key exists for the identity.
func (*RedisLoginGuard) RecordFailure ¶ added in v0.38.0
func (g *RedisLoginGuard) RecordFailure(ctx context.Context, attempt LoginAttempt) (LoginDecision, error)
RecordFailure increments the shared failure counter and, once the threshold is exceeded, sets a cooldown key whose TTL is the block duration.
func (*RedisLoginGuard) RecordSuccess ¶ added in v0.38.0
func (g *RedisLoginGuard) RecordSuccess(ctx context.Context, attempt LoginAttempt) error
RecordSuccess clears the failure counter and any open cooldown.
type RedisNonceStore ¶
type RedisNonceStore struct {
// contains filtered or unexported fields
}
RedisNonceStore implements NonceStore using Redis for distributed deployments.
func (*RedisNonceStore) StoreIfAbsent ¶
func (s *RedisNonceStore) StoreIfAbsent(ctx context.Context, appID, nonce string, ttl time.Duration) (bool, error)
StoreIfAbsent atomically stores the nonce only when it does not exist.
type RedisSessionStore ¶ added in v0.38.0
type RedisSessionStore struct {
// contains filtered or unexported fields
}
RedisSessionStore implements SessionStore on Redis so sessions are shared across nodes. Session and token keys carry a TTL that Redis expires automatically; the per-user id set is pruned lazily on read and on revoke. Every multi-key mutation runs in a MULTI/EXEC transaction so a reader never observes a half-written or half-deleted session.
func (*RedisSessionStore) ListAll ¶ added in v0.38.0
func (s *RedisSessionStore) ListAll(ctx context.Context) ([]Session, error)
ListAll enumerates every live session by scanning the id keyspace. It keeps no global index set — which would accumulate tombstones for one-time users — at the cost of a keyspace SCAN, acceptable for an infrequent admin view.
func (*RedisSessionStore) ListByUser ¶ added in v0.38.0
func (*RedisSessionStore) Revoke ¶ added in v0.38.0
func (s *RedisSessionStore) Revoke(ctx context.Context, id string) error
func (*RedisSessionStore) RevokeUser ¶ added in v0.38.0
func (s *RedisSessionStore) RevokeUser(ctx context.Context, userID string) error
type RequestScopedDataPermApplier ¶
type RequestScopedDataPermApplier struct {
// contains filtered or unexported fields
}
RequestScopedDataPermApplier is the default implementation of DataPermissionApplier. It applies data permission filtering using a single DataScope instance.
IMPORTANT: This struct is request-scoped and should NOT be stored beyond request lifecycle.
func (*RequestScopedDataPermApplier) Apply ¶
func (a *RequestScopedDataPermApplier) Apply(query orm.SelectQuery) error
Apply implements security.DataPermissionApplier.Apply.
type RolePermissionsChangedEvent ¶
type RolePermissionsChangedEvent struct {
Roles []string `json:"roles"` // Affected role names (empty means all roles)
}
RolePermissionsChangedEvent is published when role permissions are modified.
func (*RolePermissionsChangedEvent) EventType ¶ added in v0.24.0
func (*RolePermissionsChangedEvent) EventType() string
EventType implements event.Event.
type RolePermissionsLoader ¶
type RolePermissionsLoader interface {
// LoadPermissions returns a map of permission tokens to their DataScope for a role.
LoadPermissions(ctx context.Context, role string) (map[string]DataScope, error)
}
RolePermissionsLoader retrieves permissions associated with a role. Used by RBAC implementations to build the permission set for authorization checks.
func NewCachedRolePermissionsLoader ¶
func NewCachedRolePermissionsLoader( loader RolePermissionsLoader, bus event.Bus, ) RolePermissionsLoader
NewCachedRolePermissionsLoader creates a new cached role permissions loader. It automatically subscribes to role permissions change events to invalidate cache.
type SelfDataScope ¶
type SelfDataScope struct {
// contains filtered or unexported fields
}
SelfDataScope restricts access to data created by the user themselves. This is commonly used for personal data access where users can only see their own records.
func (*SelfDataScope) Apply ¶
func (s *SelfDataScope) Apply(principal *Principal, query orm.SelectQuery) error
func (*SelfDataScope) Key ¶
func (*SelfDataScope) Key() string
func (*SelfDataScope) Priority ¶
func (*SelfDataScope) Priority() int
type Session ¶ added in v0.38.0
type Session struct {
// ID is a random public identifier, safe to surface in "active devices" UIs.
ID string
// UserID is the owning principal's id.
UserID string
// Principal is the snapshot returned to callers on authentication.
Principal *Principal
// ClientIP and UserAgent describe where the session was opened.
ClientIP string
UserAgent string
// CreatedAt, LastSeenAt and ExpiresAt track the session's lifecycle.
CreatedAt time.Time
LastSeenAt time.Time
ExpiresAt time.Time
}
Session is a server-side login session backing an opaque token. It never carries the token or its hash; the store keys sessions by the token hash internally and exposes only the public ID for administration.
type SessionExceedPolicy ¶ added in v0.38.0
type SessionExceedPolicy string
SessionExceedPolicy selects what happens when a login would exceed the per-account concurrent-session limit.
const ( // SessionExceedReject denies the new login once the limit is reached. SessionExceedReject SessionExceedPolicy = "reject" // SessionExceedEvictOldest revokes the oldest session(s) to admit the new // login (the "kick the earliest device offline" behavior). SessionExceedEvictOldest SessionExceedPolicy = "evict_oldest" )
type SessionInspector ¶ added in v0.38.0
type SessionInspector interface {
// ListAll returns every live session across all users, newest activity first.
ListAll(ctx context.Context) ([]Session, error)
}
SessionInspector is an optional capability a SessionStore may implement to support cross-user administration and monitoring — for example an "all online sessions" dashboard. It is kept out of SessionStore because the authentication mechanism never needs it, so custom stores are not forced to implement it; callers type-assert for it (mirroring event.StreamInspector).
ListAll enumerates every live session and is O(all sessions); it is intended for infrequent administrative views, not a request-path call. Deployments large enough to need pagination should build it on their own store.
type SessionMeta ¶ added in v0.38.0
SessionMeta carries the client context captured when a token is issued. A stateless generator (JWT) ignores it; the opaque generator records it on the session so active devices can be listed and audited.
type SessionPolicy ¶ added in v0.38.0
type SessionPolicy struct {
// MaxConcurrent bounds simultaneous sessions per account; 0 is unlimited.
MaxConcurrent int
// OnExceed selects reject vs. evict-oldest when the limit is hit.
OnExceed SessionExceedPolicy
// IdleTTL is how long a session survives without activity and the sliding
// renewal window applied on each authenticated request.
IdleTTL time.Duration
// MaxLifetime caps a session's total age regardless of renewal; 0 is uncapped.
MaxLifetime time.Duration
// Sliding enables idle-timeout renewal on each authenticated request.
Sliding bool
}
SessionPolicy is the resolved session behavior a store and the opaque generator/authenticator enforce, built from configuration.
type SessionStore ¶ added in v0.38.0
type SessionStore interface {
// Create stores a new session for tokenHash with the given time-to-live.
Create(ctx context.Context, tokenHash string, session Session, ttl time.Duration) error
// Lookup returns the session for a presented token's hash, or nil when it is
// absent or expired.
Lookup(ctx context.Context, tokenHash string) (*Session, error)
// Renew extends the session for tokenHash to expiresAt with a fresh ttl.
Renew(ctx context.Context, tokenHash string, expiresAt time.Time, ttl time.Duration) error
// Revoke removes the session identified by its public ID.
Revoke(ctx context.Context, id string) error
// ListByUser returns a user's live sessions, newest activity first.
ListByUser(ctx context.Context, userID string) ([]Session, error)
// RevokeUser removes every session belonging to userID (force-logout).
RevokeUser(ctx context.Context, userID string) error
}
SessionStore persists opaque-token sessions. Implementations must be safe for concurrent use. Lookup and Renew address a session by the presented token's hash (the per-request path); Revoke and administration address it by public ID. A single-node deployment can use MemorySessionStore; a multi-node one must use RedisSessionStore so sessions are shared across nodes.
func NewMemorySessionStore ¶ added in v0.38.0
func NewMemorySessionStore() SessionStore
NewMemorySessionStore creates an empty in-memory session store.
func NewRedisSessionStore ¶ added in v0.38.0
func NewRedisSessionStore(client *redis.Client) SessionStore
NewRedisSessionStore creates a Redis-backed session store.
type Signature ¶
type Signature struct {
// contains filtered or unexported fields
}
Signature provides HMAC-based signature generation and verification. It handles timestamp validation and supports optional data hash for integrity.
func NewSignature ¶
func NewSignature(secret string, opts ...SignatureOption) (*Signature, error)
NewSignature creates a new Signature instance. The secret parameter is required and expects a hex-encoded string.
func (*Signature) Sign ¶
func (s *Signature) Sign(appID, method, path string) (*SignatureResult, error)
Sign generates a signature for the given appID bound to the request's HTTP method and path. Callers pass the same method/path the server will see (e.g. "POST", "/api"). Returns a SignatureResult containing all components.
func (*Signature) Verify ¶
func (s *Signature) Verify(ctx context.Context, appID, method, path string, timestamp int64, nonce, signature string) error
Verify validates the signature against the provided parameters, including the request's HTTP method and path (which must match what was signed). Returns nil if valid, or an error describing the validation failure.
func (*Signature) VerifyWithSecret ¶
func (s *Signature) VerifyWithSecret(ctx context.Context, secret, appID, method, path string, timestamp int64, nonce, signature string) error
VerifyWithSecret validates the signature using an externally provided secret. This is useful when the secret is loaded dynamically per-request (e.g., from ExternalAppLoader). The secret parameter expects a hex-encoded string.
type SignatureAlgorithm ¶
type SignatureAlgorithm string
SignatureAlgorithm represents the HMAC algorithm used for signing.
const ( SignatureAlgHmacSHA256 SignatureAlgorithm = "HMAC-SHA256" SignatureAlgHmacSHA512 SignatureAlgorithm = "HMAC-SHA512" SignatureAlgHmacSM3 SignatureAlgorithm = "HMAC-SM3" )
type SignatureCredentials ¶
type SignatureCredentials struct {
// Timestamp is the Unix timestamp (seconds) when the request was created.
Timestamp int64
// Nonce is a random string to prevent replay attacks.
Nonce string
// Signature is the HMAC signature in hex encoding.
Signature string
}
SignatureCredentials represents the credentials extracted from HTTP headers for signature-based authentication.
type SignatureOption ¶
type SignatureOption func(*Signature)
SignatureOption configures a Signature instance.
func WithAlgorithm ¶
func WithAlgorithm(algorithm SignatureAlgorithm) SignatureOption
WithAlgorithm sets the HMAC algorithm. Defaults to HMAC-SHA256.
func WithNonceStore ¶
func WithNonceStore(store NonceStore) SignatureOption
WithNonceStore sets the nonce store for replay attack prevention. Defaults to an in-memory store; pass WithNonceStore(nil) to disable nonce validation.
func WithTimestampTolerance ¶
func WithTimestampTolerance(tolerance time.Duration) SignatureOption
WithTimestampTolerance sets the maximum allowed time difference. Defaults to 5 minutes.
type SignatureResult ¶
SignatureResult contains the result of a signature operation.
type TOTPEvaluator ¶
type TOTPEvaluator struct {
// contains filtered or unexported fields
}
TOTPEvaluator checks whether a user needs TOTP verification, implementing OTPEvaluator.
func NewTOTPEvaluator ¶
func NewTOTPEvaluator(loader TOTPSecretLoader, opts ...TOTPOption) *TOTPEvaluator
NewTOTPEvaluator creates a TOTPEvaluator with the given loader and optional configuration.
func (*TOTPEvaluator) Evaluate ¶
func (e *TOTPEvaluator) Evaluate(ctx context.Context, principal *Principal) (*OTPChallengeData, error)
type TOTPOption ¶
type TOTPOption func(*TOTPEvaluator)
TOTPOption configures optional parameters for TOTPEvaluator.
func WithTOTPDestination ¶
func WithTOTPDestination(destination string) TOTPOption
WithTOTPDestination sets the destination description shown to the user for the TOTP challenge. Defaults to TOTPDefaultDestination ("Authenticator App").
type TOTPSecretLoader ¶
type TOTPSecretLoader interface {
// LoadSecret returns the base32-encoded TOTP secret for the given principal.
// An empty string means the user has not configured TOTP.
LoadSecret(ctx context.Context, principal *Principal) (string, error)
}
TOTPSecretLoader loads a user's TOTP secret.
type TOTPVerifier ¶
type TOTPVerifier struct {
// contains filtered or unexported fields
}
TOTPVerifier validates TOTP codes using standard parameters (SHA1, 6 digits, 30s period, skew=1). It implements OTPCodeVerifier.
func NewTOTPVerifier ¶
func NewTOTPVerifier(loader TOTPSecretLoader) *TOTPVerifier
NewTOTPVerifier creates a TOTPVerifier with the given secret loader.
type TokenGenerator ¶
type TokenGenerator interface {
// Generate creates the tokens for the given Principal.
Generate(ctx context.Context, principal *Principal, meta SessionMeta) (*AuthTokens, error)
}
TokenGenerator issues tokens for an authenticated Principal after login. meta carries the client context at issuance: a stateless generator (JWT) ignores it, while a stateful one (opaque) records it on the session it creates.
type UserInfoLoader ¶
type UserInfoLoader interface {
// LoadUserInfo retrieves detailed user information based on the Principal and parameters.
LoadUserInfo(ctx context.Context, principal *Principal, params map[string]any) (*UserInfo, error)
}
UserInfoLoader retrieves extended user information for the current session. Used to populate user profile data, preferences, or other session-specific details.
type UserLoader ¶
type UserLoader interface {
// LoadByUsername retrieves a user by username, returning the Principal,
// hashed password, and any error. Used for password-based authentication.
LoadByUsername(ctx context.Context, username string) (*Principal, string, error)
// LoadByID retrieves a user by their unique identifier.
// Used for token refresh and session validation.
LoadByID(ctx context.Context, id string) (*Principal, error)
}
UserLoader retrieves user information for authentication and authorization. Implementations typically query a database or external identity provider.
type UserMenuType ¶
type UserMenuType string
const ( UserMenuTypeDirectory UserMenuType = "directory" UserMenuTypeMenu UserMenuType = "menu" UserMenuTypeView UserMenuType = "view" UserMenuTypeDashboard UserMenuType = "dashboard" UserMenuTypeReport UserMenuType = "report" )
Source Files
¶
- api_errors.go
- cached_role_permission_loader.go
- challenge.go
- constants.go
- data_scopes.go
- department_selection.go
- errors.go
- ip_whitelist.go
- jwt.go
- jwt_challenge_token_store.go
- jwt_config.go
- login_event.go
- login_guard.go
- memory_challenge_token_store.go
- memory_login_guard.go
- memory_nonce_store.go
- memory_session_store.go
- otp.go
- password_change.go
- password_expiry.go
- password_history.go
- password_policy.go
- permission.go
- principal.go
- redis_challenge_token_store.go
- redis_login_guard.go
- redis_nonce_store.go
- redis_session_store.go
- request_scoped_data_perm_applier.go
- security.go
- session.go
- signature.go
- totp.go
- user_info.go