Documentation
¶
Index ¶
- Constants
- Variables
- func BearerTokenCacheKey(token string) string
- func SignToken(tokenValue, secret string) string
- func TryDecodeToken(token string) string
- func VerifyToken(signedToken, secret string) (string, error)
- type BearerTokenCreatedEventPayload
- type BearerVerifyAfterEventPayload
- type BearerVerifyBeforeEventPayload
- type Config
- type CreateTokenParams
- type CreateTokenResult
- type Option
- func WithAuthTokenHeader(header string) Option
- func WithCustomAuthTokenHeader(header string) Option
- func WithCustomTokenHeader(header string) Option
- func WithExposeHeaders(expose bool) Option
- func WithRequireSignature(require bool) Option
- func WithSecret(secret string) Option
- func WithTokenHeader(header string) Option
- type Plugin
- func (p *Plugin) Authenticate() func(next http.Handler) http.Handler
- func (p *Plugin) Config() Config
- func (p *Plugin) CreateToken(ctx context.Context, params CreateTokenParams) (*CreateTokenResult, error)
- func (p *Plugin) ExposedHeaders() string
- func (p *Plugin) ExtractToken(headerValue string) (string, error)
- func (p *Plugin) FormatAuthTokenHeader(token string) (headerName, headerValue string)
- func (p *Plugin) FormatHeader(token string) string
- func (p *Plugin) ID() string
- func (p *Plugin) Init(ctx *plugin.Context) error
- func (p *Plugin) ResolveSession(ctx context.Context, params ResolveSessionParams) (*ResolveSessionResult, error)
- func (p *Plugin) Verify(ctx context.Context, params VerifyParams) (*VerifyResult, error)
- type Repository
- type ResolveSessionParams
- type ResolveSessionResult
- type VerifyParams
- type VerifyResult
Constants ¶
const ( // EventBearerVerifyBefore is emitted right before starting token verification. // Payload: *BearerVerifyBeforeEventPayload EventBearerVerifyBefore = "bearer:verify:before" // EventBearerVerifyAfter is emitted after completing token cryptographic verification. // Payload: *BearerVerifyAfterEventPayload EventBearerVerifyAfter = "bearer:verify:after" // EventBearerTokenCreated is emitted when a new signed bearer token is created. // Payload: *BearerTokenCreatedEventPayload EventBearerTokenCreated = "bearer:token:created" )
const ( // ExtraKeyRawToken stores the raw unsigned token string within dynamic Extra metadata. // Expected type: string. ExtraKeyRawToken = "raw_token" // ExtraKeySignedToken stores the HMAC-signed token string within dynamic Extra metadata. // Expected type: string. ExtraKeySignedToken = "signed_token" // ExtraKeySessionID stores the resolved session ID within dynamic Extra metadata. // Expected type: string. ExtraKeySessionID = "session_id" // ExtraKeyUserID stores the owner user ID within dynamic Extra metadata. // Expected type: string. ExtraKeyUserID = "user_id" // ExtraKeyTokenSource identifies the extraction origin of the token (e.g. "header", "query", "body"). // Expected type: string. ExtraKeyTokenSource = "token_source" )
Standard Extra metadata keys that can be set or consumed in Bearer operations (such as in VerifyParams.Extra, CreateTokenParams.Extra, and Event payloads).
const ( // HeaderAuthorization is the standard RFC 7235 HTTP Authorization header name. HeaderAuthorization = "Authorization" // HeaderSetAuthToken is the default HTTP response header name used to expose the issued bearer token. HeaderSetAuthToken = "set-auth-token" // HeaderAccessControlExposeHeaders is the standard CORS response header used to expose custom headers to client browsers. HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers" // BearerSchemePrefix is the standard case-insensitive scheme prefix preceding bearer tokens in Authorization headers. BearerSchemePrefix = "bearer " )
Standard HTTP header and authentication scheme constants.
const ( SessionContextKey contextKey = "bearer_session" RawTokenContextKey contextKey = "bearer_raw_token" SignedTokenContextKey contextKey = "bearer_signed_token" )
const (
// ContextKeyTokenPrefix is the key prefix used when caching validated tokens in plugin.Context.
ContextKeyTokenPrefix = "bearer:token:"
)
Shared plugin context keys used for internal state and token caching in plugin.Context.
const PluginID = "bearer"
PluginID is the unique string identifier for the Bearer plugin ("bearer").
Variables ¶
var ( // ErrInvalidTokenFormat is returned when a signed token string does not adhere to the "<token>.<signature>" format. ErrInvalidTokenFormat = errors.New("bearer: invalid token format") // ErrInvalidSignature is returned when the cryptographic HMAC-SHA256 signature verification fails. ErrInvalidSignature = errors.New("bearer: signature verification failed") // ErrTokenEmpty is returned when an empty token string or header is provided. ErrTokenEmpty = errors.New("bearer: token is empty") // ErrInvalidHeader is returned when an authorization header does not start with the required "Bearer " prefix. ErrInvalidHeader = errors.New("bearer: invalid authorization header scheme") // ErrSecretRequired is returned when signing or verifying tokens without a configured Secret key. ErrSecretRequired = errors.New("bearer: secret key is required for token signing and verification") // ErrSessionNotFound is returned when a verified token does not match any active session in the database. ErrSessionNotFound = errors.New("bearer: session not found") // ErrSessionExpired is returned when a retrieved session has exceeded its validity timestamp. ErrSessionExpired = errors.New("bearer: session has expired") )
Functions ¶
func BearerTokenCacheKey ¶
BearerTokenCacheKey formats the context store key used to track or cache a validated token in the shared context.
func SignToken ¶
SignToken generates a signed token string in the format "<raw_token>.<base64url_signature>" using HMAC-SHA256.
func TryDecodeToken ¶
TryDecodeToken attempts to unescape percent-encoded characters (%2E, %2B) present in tokens.
func VerifyToken ¶
VerifyToken validates the HMAC-SHA256 signature of a signed token ("<value>.<signature>"). It uses subtle.ConstantTimeCompare to protect against timing attacks.
Types ¶
type BearerTokenCreatedEventPayload ¶
type BearerTokenCreatedEventPayload struct {
// RawToken is the base unsigned token identifier.
RawToken string
// SignedToken is the resulting HMAC-SHA256 signed token in base64url format.
SignedToken string
// UserID identifies the owner user ID (if available).
UserID string
}
BearerTokenCreatedEventPayload contains the details of a newly created and signed token.
type BearerVerifyAfterEventPayload ¶
type BearerVerifyAfterEventPayload struct {
// Token is the processed token string.
Token string
// Valid indicates whether the signature and format were valid.
Valid bool
// Session contains the retrieved session entity if resolved via repository (optional).
Session *entity.Session
}
BearerVerifyAfterEventPayload reports the result of a token validation attempt.
type BearerVerifyBeforeEventPayload ¶
type BearerVerifyBeforeEventPayload struct {
// RawToken is the incoming token string before signature verification.
RawToken string
// Params contains the mutable verification parameters (including Extra metadata).
Params *VerifyParams
}
BearerVerifyBeforeEventPayload contains pre-verification data for lifecycle interception.
type Config ¶
type Config struct {
// Secret defines the cryptographic secret key used for signing and verifying tokens via HMAC-SHA256.
Secret string
// RequireSignature specifies whether incoming tokens must strictly arrive pre-signed.
// When false (default), raw unsigned tokens are signed automatically using the configured Secret.
RequireSignature bool
// TokenHeader specifies the HTTP header name from which to extract the bearer token (default: "Authorization").
TokenHeader string
// AuthTokenHeader specifies the HTTP response header name used to expose the token (default: "set-auth-token").
AuthTokenHeader string
// ExposeHeaders specifies whether to configure CORS Access-Control-Expose-Headers for the response header (default: true).
ExposeHeaders bool
}
Config holds configuration parameters for the Bearer plugin.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns the default production configuration for the Bearer plugin.
type CreateTokenParams ¶
type CreateTokenParams struct {
// Token is the base session token or unique string identifier to sign (required).
Token string `json:"token"`
// Secret optionally overrides the default secret key configured on the plugin.
Secret string `json:"secret,omitempty"`
// UserID optionally associates an owner user ID with the created token.
UserID string `json:"user_id,omitempty"`
plugin.ExtraContainer
}
CreateTokenParams defines parameters to generate and sign a Bearer token.
type CreateTokenResult ¶
type CreateTokenResult struct {
// RawToken is the base unsigned token string.
RawToken string `json:"raw_token"`
// SignedToken is the HMAC-SHA256 signed token.
SignedToken string `json:"signed_token"`
// HeaderValue is the formatted Authorization header string ("Bearer <signed_token>").
HeaderValue string `json:"header_value"`
// AuthTokenHeader is the response header name (default: "set-auth-token").
AuthTokenHeader string `json:"auth_token_header"`
}
CreateTokenResult contains the generated signed token and ready-to-use HTTP header values.
type Option ¶
type Option func(*Config)
Option defines a functional configuration option for the Bearer plugin.
func WithAuthTokenHeader ¶
WithAuthTokenHeader customizes the outgoing HTTP response header name where the token is exposed (default: "set-auth-token").
func WithCustomAuthTokenHeader ¶
WithCustomAuthTokenHeader is an alias for WithAuthTokenHeader.
func WithCustomTokenHeader ¶
WithCustomTokenHeader is an alias for WithTokenHeader.
func WithExposeHeaders ¶
WithExposeHeaders configures whether the output header should be published in CORS Access-Control-Expose-Headers.
func WithRequireSignature ¶
WithRequireSignature configures whether the plugin strictly enforces pre-signed tokens.
func WithSecret ¶
WithSecret sets the cryptographic secret key used for HMAC-SHA256 token signing and verification.
func WithTokenHeader ¶
WithTokenHeader customizes the incoming HTTP request header name used to parse the token (default: "Authorization").
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
Plugin implements Bearer Token Authentication capabilities.
func New ¶
func New(repo Repository, opts ...Option) *Plugin
New creates a new Bearer plugin instance configured with an optional repository and functional options.
Arguments:
- repo: Implementation of bearer.Repository interface (can be nil if only token crypto is required).
- opts: Functional configuration options (WithSecret, WithRequireSignature, WithTokenHeader, etc.).
Returns:
- *Plugin: The configured Bearer plugin instance.
func (*Plugin) Authenticate ¶ added in v0.20.0
Authenticate returns a standard net/http middleware handler to authenticate Bearer tokens from incoming HTTP request headers.
func (*Plugin) CreateToken ¶
func (p *Plugin) CreateToken(ctx context.Context, params CreateTokenParams) (*CreateTokenResult, error)
CreateToken creates an HMAC-SHA256 signed bearer token from a raw session or user identifier.
Brief Explanation:
Appends an HMAC-SHA256 signature encoded with RawURLEncoding to the input token string and publishes EventBearerTokenCreated.
Arguments:
- ctx: Request cancellation context.
- params: CreateTokenParams containing Token string, optional Secret, and UserID.
Returns:
- *CreateTokenResult: Signed token, Authorization header value, and output header name.
- error: ErrTokenEmpty or ErrSecretRequired.
Example:
res, err := bearerPlugin.CreateToken(ctx, bearer.CreateTokenParams{
Token: "session_token_123",
UserID: "user_456",
})
if err != nil {
log.Fatalf("Token creation failed: %v", err)
}
fmt.Println("Header value:", res.HeaderValue)
func (*Plugin) ExposedHeaders ¶
ExposedHeaders returns the comma-separated header names to expose in CORS Access-Control-Expose-Headers.
func (*Plugin) ExtractToken ¶
ExtractToken extracts the bearer token from an HTTP Authorization header string according to RFC 7235.
func (*Plugin) FormatAuthTokenHeader ¶
FormatAuthTokenHeader returns the configured response header name and value for client consumption.
func (*Plugin) FormatHeader ¶
FormatHeader formats a signed token string as a standard HTTP Authorization header ("Bearer <token>").
func (*Plugin) ResolveSession ¶
func (p *Plugin) ResolveSession(ctx context.Context, params ResolveSessionParams) (*ResolveSessionResult, error)
ResolveSession extracts the bearer token from an Authorization header or string, verifies its signature, and retrieves the corresponding non-expired Session entity from storage.
Brief Explanation:
Performs header extraction, signature verification, repository lookup, expiry check, and context caching.
Arguments:
- ctx: Request cancellation context.
- params: ResolveSessionParams containing Header or Token.
Returns:
- *ResolveSessionResult: Session entity, verified raw token, and signed token.
- error: ErrTokenEmpty, ErrInvalidHeader, ErrInvalidSignature, ErrSessionNotFound, or ErrSessionExpired.
Example:
res, err := bearerPlugin.ResolveSession(ctx, bearer.ResolveSessionParams{
Header: "Bearer " + signedToken,
})
if err != nil {
log.Fatalf("Failed to resolve session: %v", err)
}
fmt.Println("Session user ID:", res.Session.UserID)
func (*Plugin) Verify ¶
func (p *Plugin) Verify(ctx context.Context, params VerifyParams) (*VerifyResult, error)
Verify validates the HMAC-SHA256 signature of a token, auto-signs raw tokens if enabled, and caches the resulting token in the shared context.
Brief Explanation:
Validates token format, decodes percent-encoded characters, validates HMAC signature in constant time, and publishes EventBearerVerifyBefore and EventBearerVerifyAfter.
Arguments:
- ctx: Request cancellation context.
- params: VerifyParams containing the token string and optional Secret override.
Returns:
- *VerifyResult: Contains the raw token and signed token.
- error: ErrTokenEmpty, ErrInvalidTokenFormat, ErrInvalidSignature, or ErrSecretRequired.
Example:
res, err := bearerPlugin.Verify(ctx, bearer.VerifyParams{
Token: "my_token.3hA9...sig",
})
if err != nil {
log.Fatalf("Invalid bearer token: %v", err)
}
fmt.Println("Verified raw token:", res.RawToken)
type Repository ¶
type Repository interface {
// GetSessionByToken retrieves an active session by its raw token identifier.
//
// Function:
// Queries storage for the session entity associated with the verified raw token string.
//
// Storage:
// Both (Cache-Aside Strategy) - High-frequency lookup per HTTP request.
//
// Arguments:
// - ctx: Request cancellation context.
// - token: Raw session token string (unstripped of HMAC signature).
//
// Returns:
// - *entity.Session: Active session entity if found.
// - error: ErrSessionNotFound if not found, or infrastructure error.
//
// Example SQL:
// SELECT id, user_id, token, expires_at, created_at, ip_address, user_agent FROM sessions WHERE token = $1 LIMIT 1;
//
// Example Cache (Redis):
// val, err := rdb.Get(ctx, "session:" + token).Bytes()
GetSessionByToken(ctx context.Context, token string) (*entity.Session, error)
}
Repository defines the persistent storage contract required by the Bearer plugin to look up active sessions. Implement this interface on your custom database adapter (e.g. PostgreSQL, MySQL, MongoDB, GORM, Redis).
Implementation Example (GORM / database/sql): ¶
type GormBearerRepository struct {
db *gorm.DB
}
func (r *GormBearerRepository) GetSessionByToken(ctx context.Context, token string) (*entity.Session, error) {
var s entity.Session
if err := r.db.WithContext(ctx).Where("token = ?", token).First(&s).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, bearer.ErrSessionNotFound
}
return nil, err
}
return &s, nil
}
Storage and Caching Recommendation (Redis / Cache-Aside Strategy): ¶
Because `GetSessionByToken` is invoked on **every Bearer-authenticated API request**, querying the relational database on every HTTP call can become a performance bottleneck.
Decorating your database repository with Redis or an in-memory Cache-Aside wrapper is strongly recommended:
type CachedBearerRepository struct {
dbRepo bearer.Repository
redis *redis.Client
ttl time.Duration
}
func (r *CachedBearerRepository) GetSessionByToken(ctx context.Context, token string) (*entity.Session, error) {
cacheKey := "session:" + token
val, err := r.redis.Get(ctx, cacheKey).Bytes()
if err == nil {
var sess entity.Session
if json.Unmarshal(val, &sess) == nil {
return &sess, nil // Fast Cache Hit ($O(1)$ response)
}
}
sess, err := r.dbRepo.GetSessionByToken(ctx, token)
if err != nil {
return nil, err
}
bytes, _ := json.Marshal(sess)
r.redis.Set(ctx, cacheKey, bytes, r.ttl)
return sess, nil
}
type ResolveSessionParams ¶
type ResolveSessionParams struct {
// Header is the full HTTP Authorization header value (e.g. "Bearer <token>.<sig>").
Header string `json:"header,omitempty"`
// Token is the direct token string if already extracted.
Token string `json:"token,omitempty"`
// Secret optionally overrides the secret key.
Secret string `json:"secret,omitempty"`
plugin.ExtraContainer
}
ResolveSessionParams defines parameters to extract, verify, and look up an active session entity.
type ResolveSessionResult ¶
type ResolveSessionResult struct {
// Session is the active, non-expired session entity retrieved from storage.
Session *entity.Session `json:"session"`
// RawToken is the verified raw token string used for querying the session.
RawToken string `json:"raw_token"`
// SignedToken is the verified signed token string.
SignedToken string `json:"signed_token"`
}
ResolveSessionResult contains the active session entity and processed token values.
type VerifyParams ¶
type VerifyParams struct {
// Token is the raw or signed token string or extracted authorization header (required).
Token string `json:"token"`
// Secret optionally overrides the default secret key configured on the plugin.
Secret string `json:"secret,omitempty"`
plugin.ExtraContainer
}
VerifyParams defines parameters required to verify an incoming Bearer token.
type VerifyResult ¶
type VerifyResult struct {
// RawToken is the extracted unsigned token identifier.
RawToken string `json:"raw_token"`
// SignedToken is the complete signed token representation.
SignedToken string `json:"signed_token"`
// Valid indicates whether the cryptographic signature was valid.
Valid bool `json:"valid"`
}
VerifyResult contains the outcome of a successful token validation.