bearer

package
v0.27.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
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"
)
View Source
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).

View Source
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.

View Source
const (
	SessionContextKey     contextKey = "bearer_session"
	RawTokenContextKey    contextKey = "bearer_raw_token"
	SignedTokenContextKey contextKey = "bearer_signed_token"
)
View Source
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.

View Source
const PluginID = "bearer"

PluginID is the unique string identifier for the Bearer plugin ("bearer").

Variables

View Source
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

func BearerTokenCacheKey(token string) string

BearerTokenCacheKey formats the context store key used to track or cache a validated token in the shared context.

func SignToken

func SignToken(tokenValue, secret string) string

SignToken generates a signed token string in the format "<raw_token>.<base64url_signature>" using HMAC-SHA256.

func TryDecodeToken

func TryDecodeToken(token string) string

TryDecodeToken attempts to unescape percent-encoded characters (%2E, %2B) present in tokens.

func VerifyToken

func VerifyToken(signedToken, secret string) (string, error)

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

func WithAuthTokenHeader(header string) Option

WithAuthTokenHeader customizes the outgoing HTTP response header name where the token is exposed (default: "set-auth-token").

func WithCustomAuthTokenHeader

func WithCustomAuthTokenHeader(header string) Option

WithCustomAuthTokenHeader is an alias for WithAuthTokenHeader.

func WithCustomTokenHeader

func WithCustomTokenHeader(header string) Option

WithCustomTokenHeader is an alias for WithTokenHeader.

func WithExposeHeaders

func WithExposeHeaders(expose bool) Option

WithExposeHeaders configures whether the output header should be published in CORS Access-Control-Expose-Headers.

func WithRequireSignature

func WithRequireSignature(require bool) Option

WithRequireSignature configures whether the plugin strictly enforces pre-signed tokens.

func WithSecret

func WithSecret(secret string) Option

WithSecret sets the cryptographic secret key used for HMAC-SHA256 token signing and verification.

func WithTokenHeader

func WithTokenHeader(header string) Option

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

func (p *Plugin) Authenticate() func(next http.Handler) http.Handler

Authenticate returns a standard net/http middleware handler to authenticate Bearer tokens from incoming HTTP request headers.

func (*Plugin) Config

func (p *Plugin) Config() Config

Config returns the active configuration settings of the Bearer plugin.

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

func (p *Plugin) ExposedHeaders() string

ExposedHeaders returns the comma-separated header names to expose in CORS Access-Control-Expose-Headers.

func (*Plugin) ExtractToken

func (p *Plugin) ExtractToken(headerValue string) (string, error)

ExtractToken extracts the bearer token from an HTTP Authorization header string according to RFC 7235.

func (*Plugin) FormatAuthTokenHeader

func (p *Plugin) FormatAuthTokenHeader(token string) (headerName, headerValue string)

FormatAuthTokenHeader returns the configured response header name and value for client consumption.

func (*Plugin) FormatHeader

func (p *Plugin) FormatHeader(token string) string

FormatHeader formats a signed token string as a standard HTTP Authorization header ("Bearer <token>").

func (*Plugin) ID

func (p *Plugin) ID() string

ID returns the unique identifier for the Bearer plugin ("bearer").

func (*Plugin) Init

func (p *Plugin) Init(ctx *plugin.Context) error

Init initializes the plugin within the global GoModularAuth context.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL