Skip to main content

Authentication Reference

The public security package surface for authentication: principals, JWT, the auth manager, challenge providers and token stores, signature auth, and login events. For the narrative guide — strategies, the built-in auth resource, and the login flow — see Authentication.

API groupPublic surface
principalsPrincipal, PrincipalType, NewUser, NewExternalApp, PrincipalSystem, PrincipalAnonymous, SetUserDetailsType, SetExternalAppDetailsType
JWTJWT, JWTConfig, JWTClaimsBuilder, JWTClaimsAccessor, NewJWT, GenerateSecret, token type constants, DefaultJWTAudience, DefaultJWTSecret, JWTIssuer
auth managerAuthentication, AuthTokens, Authenticator, AuthManager, TokenGenerator, UserLoader, ExternalAppLoader, ExternalAppConfig, PasswordDecryptor
challenge tokensChallengeProvider, ChallengeState, ChallengeTokenStore, NewMemoryChallengeTokenStore, NewRedisChallengeTokenStore, NewJWTChallengeTokenStore
OTP/challengesOTPEvaluator, OTPCodeSender, OTPCodeVerifier, OTPCodeStore, NewOTPChallengeProvider, NewDeliveredCodeSender, NewDeliveredCodeVerifier, NewDeliveredChallengeProvider, NewSMSChallengeProvider, NewEmailChallengeProvider
TOTP/password/departmentNewTOTPEvaluator, NewTOTPVerifier, NewTOTPChallengeProvider, WithTOTPDestination, NewPasswordChangeChallengeProvider, NewDepartmentSelectionChallengeProvider
signature authSignature, SignatureCredentials, SignatureResult, SignatureAlgorithm, NewSignature, WithAlgorithm, WithTimestampTolerance, WithNonceStore, NonceStore, NewMemoryNonceStore, NewRedisNonceStore
login eventsLoginEvent, LoginEventParams, NewLoginEvent, SubscribeLoginEvent

Bearer constants are AuthSchemeBearer and QueryKeyAccessToken. The token type constants are TokenTypeAccess, TokenTypeRefresh, and TokenTypeChallenge.

JWT and principals

NewJWT expects JWTConfig.Secret to be a hex-encoded key and defaults an empty audience to DefaultJWTAudience. Low-level NewJWT still falls back to the public DefaultJWTSecret when the secret is empty; the framework security module wraps this with a safer boot-time behavior that generates an ephemeral key and warns. Use GenerateSecret() to provision a private production key for vef.security.secret.

The built-in framework token generator issues access tokens with a fixed 30m TTL. vef.security.token_expires configures the refresh-token TTL instead (default 168h), and vef.security.refresh_not_before defaults to 15m. Access and refresh tokens generated together share the same jti.

JWT parsing accepts only HS256, requires issuer JWTIssuer (vef), validates audience, requires iat and exp, and applies a 10-second leeway. The compact claim keys are:

ClaimKey
JWT IDjti
subjectsub
issueriss
audienceaud
issued atiat
not beforenbf
expires atexp
token typetyp
rolesrls
detailsdet

The built-in access and refresh token generator stores the subject as id@name. JWTTokenAuthenticator rebuilds a user principal from that subject without a database lookup. JWTRefreshAuthenticator also expects id@name, but then reloads the user with UserLoader.LoadByID(...) using the id part.

JWTClaimsBuilder writes compact token claims with WithID, WithSubject, WithRoles, WithDetails, WithType, and WithClaim. JWTClaimsAccessor reads the same payload back with ID, Subject, Roles, Details, Type, and Claim. Use NewJWTClaimsBuilder() and NewJWTClaimsAccessor(...) to create those helpers directly.

PrincipalTypeUser, PrincipalTypeExternalApp, and PrincipalTypeSystem describe the supported principal kinds. SetUserDetailsType[T]() and SetExternalAppDetailsType[T]() configure process-global detail unmarshalling targets; call them during startup before serving requests.

Principal serializes as JSON type, id, name, roles, and details. SetUserDetailsType[T]() and SetExternalAppDetailsType[T]() require T to be a struct or struct pointer and panic with ErrUserDetailsNotStruct or ErrExternalAppDetailsNotStruct otherwise. They mutate package-level state and should be treated as startup-only configuration. Unknown principal types keep details as map[string]any; system principals deserialize with details set to nil. The built-in special principals are PrincipalSystem (type: "system", id system, name 系统) and PrincipalAnonymous (type: "user", id anonymous, name 匿名).

Challenge providers

Built-in challenge type constants include:

  • ChallengeTypeTOTP
  • ChallengeTypeSMS
  • ChallengeTypeEmail
  • ChallengeTypePasswordChange
  • ChallengeTypeDepartmentSelection

Their wire values and default orders are:

ConstantWire valueDefault order
ChallengeTypeTOTPtotp100
ChallengeTypeSMSsms_otp200
ChallengeTypeEmailemail_otp300
ChallengeTypePasswordChangepassword_change400
ChallengeTypeDepartmentSelectiondepartment_selection500

ChallengeTokenStore.Generate(ctx, principal, pending, resolved) and Parse(ctx, token) carry the state between login and resolve_challenge. The built-in login resources expose that state field as challengeToken. JWTChallengeTokenStore is stateless; MemoryChallengeTokenStore is suitable for tests or single-instance deployments; RedisChallengeTokenStore is for distributed deployments. Challenge tokens expire after ChallengeTokenExpires. The JWT-backed store uses ClaimChallengePrincipalType, ClaimChallengePrincipalName, ClaimChallengeUsername, ClaimChallengePending, and ClaimChallengeResolved as compact claim keys.

Challenge token stores have different wire/storage shapes:

StoreToken/state contract
JWTChallengeTokenStoreJWT token, typ: "challenge", 5-minute ChallengeTokenExpires, subject is principal ID only
MemoryChallengeTokenStoreUUID token stored in process memory for ChallengeTokenExpires
RedisChallengeTokenStoreUUID token stored under vef:security:challenge:<token> for ChallengeTokenExpires

The JWT challenge claim keys are ptp (ClaimChallengePrincipalType), pnm (ClaimChallengePrincipalName), unm (ClaimChallengeUsername), pnd (ClaimChallengePending), and rsd (ClaimChallengeResolved). Challenge parsing accepts empty principal type as a backwards-compatible user principal, accepts user, external_app, and system, and rejects unknown principal types.

Challenge providers are sorted by Order() in ascending order. The built-in convenience providers use 100 for TOTP, 200 for SMS, 300 for email, 400 for password change, and 500 for department selection. Providers that are not registered, or whose Evaluate(...) returns nil, are skipped. During resolve_challenge, the submitted type must match the first pending challenge type or the framework returns ErrChallengeTypeInvalid.

NewOTPChallengeProvider is the generic constructor. Its OTPChallengeProviderConfig requires ChallengeType, Evaluator, and Verifier; ChallengeOrder controls evaluation order, and Sender is optional and is used by delivered-code flows. OTPChallengeProvider returns OTPChallengeData to the client when a challenge is required. The delivered-code helpers combine OTPCodeStore and OTPCodeDelivery: DeliveredCodeSender, DeliveredCodeVerifier, NewDeliveredCodeSender, NewDeliveredCodeVerifier, NewDeliveredChallengeProvider, NewSMSChallengeProvider, and NewEmailChallengeProvider.

NewTOTPChallengeProvider only needs a TOTPSecretLoader; if LoadSecret(...) returns an empty string, the challenge is skipped. TOTPEvaluator, TOTPVerifier, and TOTPOption are the lower-level pieces behind the convenience provider. TOTP uses TOTPDefaultDestination (Authenticator App) unless WithTOTPDestination(...) overrides it.

NewPasswordChangeChallengeProvider uses PasswordChangeChecker and PasswordChanger; it returns PasswordChangeChallengeData when a password change is required. Common reason constants are PasswordChangeReasonFirstLogin (first_login) and PasswordChangeReasonExpired (expired). The concrete provider type is PasswordChangeChallengeProvider. NewDepartmentSelectionChallengeProvider uses DepartmentLoader and DepartmentSelector; an empty department list skips the challenge, while resolve expects a department ID string. DepartmentSelectionChallengeData serializes as departments plus optional meta; each DepartmentOption serializes as id and name.

The challenge constructors are wiring-time APIs. NewOTPChallengeProvider panics when ChallengeType, Evaluator, or Verifier is missing. NewPasswordChangeChallengeProvider panics when PasswordChangeChecker or PasswordChanger is missing. NewDepartmentSelectionChallengeProvider panics when DepartmentLoader or DepartmentSelector is missing.

Signature helpers

NewSignature(secret, ...) requires a non-empty hex-encoded secret and defaults to SignatureAlgHmacSHA256 with a 5-minute timestamp tolerance. The option type is SignatureOption. Other algorithm constants are SignatureAlgHmacSHA512 and SignatureAlgHmacSM3. WithTimestampTolerance changes the accepted timestamp window and WithNonceStore controls replay protection. Low-level NewSignature(...) creates a MemoryNonceStore by default; pass WithNonceStore(nil) only when you intentionally want to disable nonce storage for that helper. The built-in SignatureAuthenticator injects the application NonceStore when one is provided, otherwise each verification uses the low-level helper's process-local memory store. MemoryNonceStore is local to one process; RedisNonceStore is the distributed option. Stored nonces use twice the timestamp tolerance plus a 1-minute buffer as TTL.

The signed payload is exactly:

app_id=<appID>&method=<method>&nonce=<nonce>&path=<path>&timestamp=<timestamp>

The fields are bound in that order. The request body is not part of the signature payload. The method field is the HTTP method observed by the server.

NewIPWhitelistValidator returns an IPWhitelistValidator from a comma-separated list of IPs and CIDR ranges. An empty whitelist allows all IPs; an invalid whitelist is fail-closed and denies all requests. When an ExternalAppConfig.IPWhitelist is non-empty but the request IP cannot be resolved, SignatureAuthenticator also fails closed with ErrIPNotAllowed.

security.NewIPWhitelistValidatorFromEntries(entries) is the slice-based counterpart used by the built-in api.IPAuth(...) strategy. The strategy resolves a named security.IPWhitelist through security.IPWhitelistLoader; the default loader reads vef.security.ip_whitelists, while applications may provide their own loader for database or config-center backed lists.

Signature storage keys and defaults:

ContractValue
request headersX-App-ID, X-Timestamp, X-Nonce, X-Signature
algorithmsHMAC-SHA256, HMAC-SHA512, HMAC-SM3
default algorithmHMAC-SHA256
default tolerance5m
nonce TTL2*tolerance + 1m
Redis nonce prefixvef:security:nonce:
disable replay checkingWithNonceStore(nil)

Security-domain API errors expose ErrCode* constants in the 1000-1039 range:

CodeConstantErrorHTTP status
1000ErrCodeUnauthenticatedErrUnauthenticated401
1001ErrCodeUnsupportedAuthenticationTypeunsupported authentication type400
1002ErrCodeTokenExpiredErrTokenExpired401
1003ErrCodeTokenInvalidErrTokenInvalid401
1004ErrCodeTokenNotValidYetErrTokenNotValidYet401
1005ErrCodeTokenInvalidIssuerErrTokenInvalidIssuer401
1006ErrCodeTokenInvalidAudienceErrTokenInvalidAudience401
1007ErrCodePrincipalInvalidErrPrincipalInvalid(message)401
1008ErrCodeCredentialsInvalidErrCredentialsInvalid(message)401
1009ErrCodeAppIDRequiredErrAppIDRequired401
1010ErrCodeTimestampRequiredErrTimestampRequired401
1011ErrCodeSignatureRequiredErrSignatureRequired401
1012ErrCodeTimestampInvalidErrTimestampInvalid401
1013ErrCodeSignatureExpiredErrSignatureExpired401
1014ErrCodeExternalAppNotFoundErrExternalAppNotFound401
1015ErrCodeExternalAppDisabledErrExternalAppDisabled401
1016ErrCodeIPNotAllowedErrIPNotAllowed401
1017ErrCodeSignatureInvalidErrSignatureInvalid401
1018ErrCodeNonceRequiredErrNonceRequired401
1019ErrCodeNonceInvalidErrNonceInvalid401
1020ErrCodeNonceAlreadyUsedErrNonceAlreadyUsed401
1021ErrCodeAuthHeaderMissingErrAuthHeaderMissing401
1022ErrCodeAuthHeaderInvalidErrAuthHeaderInvalid401
1031ErrCodeChallengeTokenInvalidErrChallengeTokenInvalid401
1033ErrCodeChallengeTypeInvalidErrChallengeTypeInvalid400
1034ErrCodeChallengeResolveFailedchallenge resolve failure message IDreserved
1035ErrCodeOTPCodeRequiredErrOTPCodeRequired400
1036ErrCodeOTPCodeInvalidErrOTPCodeInvalid401
1037ErrCodeNewPasswordRequiredErrNewPasswordRequired400
1038ErrCodeDepartmentRequiredErrDepartmentRequired400

Authentication-related sentinels include ErrUnauthenticated, ErrTokenExpired, ErrTokenInvalid, ErrTokenNotValidYet, ErrTokenInvalidIssuer, ErrTokenInvalidAudience, ErrAppIDRequired, ErrTimestampRequired, ErrSignatureRequired, ErrTimestampInvalid, ErrSignatureExpired, ErrSignatureInvalid, ErrExternalAppNotFound, ErrExternalAppDisabled, ErrIPNotAllowed, ErrNonceRequired, ErrNonceInvalid, ErrNonceAlreadyUsed, ErrAuthHeaderMissing, ErrAuthHeaderInvalid, ErrChallengeTokenInvalid, ErrChallengeTypeInvalid, ErrOTPCodeRequired, ErrOTPCodeInvalid, ErrNewPasswordRequired, ErrDepartmentRequired, plus the factory helpers ErrCredentialsInvalid(message) and ErrPrincipalInvalid(message). ErrCodeChallengeResolveFailed and ErrChallengeResolveFailed are reserved for challenge resolution failures.

Low-level secret parsing errors use ErrDecodeJWTSecretFailed, ErrGenerateJWTSecretFailed, ErrDecodeSignatureSecretFailed, and ErrSignatureSecretRequired. ErrUserDetailsNotStruct and ErrExternalAppDetailsNotStruct are raised when detail-type registration is not given a struct or struct pointer. Public i18n message ID constants include ErrMessageChallengeResolveFailed, ErrMessageCredentialsFormatInvalid, ErrMessageExternalAppLoaderNotImplemented, ErrMessageUnauthenticated, ErrMessageUnsupportedAuthenticationType, ErrMessageUserInfoLoaderNotImplemented, and ErrMessageUserLoaderNotImplemented.

Next Step