Documentation
¶
Overview ¶
Package authcontext provides a unified security-context propagation layer for HTTP services and inter-service calls.
It solves three problems that arise in every multi-layer backend:
- **Extract** — read identity information (user ID, roles, permissions, tenant) from an incoming HTTP request, whether it arrives as a JWT bearer token, a signed cookie, or trusted headers forwarded by a gateway.
- **Store** — place the identity into a request-scoped context.Context so downstream handlers, services, and repositories can access it without passing it through every function signature.
- **Propagate** — when the service makes outbound HTTP calls to other internal services, automatically forward the identity headers so the downstream service can re-extract the same context.
Architecture ¶
Incoming Request
│
▼
┌───────────────────┐
│ Extractor │ ← JWT / headers / custom
│ (AuthExtractor) │
└────────┬──────────┘
│ Identity
▼
┌───────────────────┐
│ Context │ ← context.WithValue
│ (WithIdentity) │
└────────┬──────────┘
│ ctx
▼
┌───────────────────┐
│ Propagator │ ← outbound http.RoundTripper
│ (PropagatingRT) │
└───────────────────┘
│
▼
Downstream Service
Quick start ¶
// 1. Configure an extractor (JWT-based by default).
extractor := authcontext.NewJWTExtractor(auth)
// 2. Gin middleware that extracts and stores identity in ctx.
r.Use(authcontext.GinMiddleware(extractor))
// 3. Read identity anywhere.
id := authcontext.FromContext(c.Request.Context())
fmt.Println(id.UserID, id.Roles)
// 4. Propagate to downstream calls.
client := &http.Client{
Transport: authcontext.NewPropagatingTransport(nil),
}
req, _ := http.NewRequestWithContext(ctx, "GET", "http://downstream/api", nil)
resp, _ := client.Do(req) // identity headers auto-injected
Index ¶
- Variables
- func BearerFromHeader(r *http.Request) string
- func InjectHeaders(req *http.Request, id *Identity, h PropagationHeaders)
- func MarshalIdentity(id *Identity) ([]byte, error)
- func WithIdentity(ctx context.Context, id *Identity) context.Context
- type AuthExtractor
- type ExtractFunc
- type HeaderExtractor
- type Identity
- type JWTClaims
- type JWTExtractor
- type JWTVerifier
- type PropagatingTransport
- type PropagationHeaders
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNoIdentity is returned when no identity is found in the context. ErrNoIdentity = errors.New("authcontext: no identity in context") // ErrInvalidToken is returned when the token cannot be parsed. ErrInvalidToken = errors.New("authcontext: invalid token") )
Functions ¶
func BearerFromHeader ¶
BearerFromHeader extracts a bearer token from the Authorization header ("Bearer <token>"). Returns "" if absent or malformed.
func InjectHeaders ¶
func InjectHeaders(req *http.Request, id *Identity, h PropagationHeaders)
InjectHeaders writes identity headers onto an existing request. This is useful when you build the request manually and don't want to use a custom transport.
func MarshalIdentity ¶
MarshalIdentity serializes id to JSON bytes.
Types ¶
type AuthExtractor ¶
AuthExtractor extracts an Identity from an HTTP request. Different implementations parse JWT tokens, trusted headers, cookies, etc.
type ExtractFunc ¶
The ExtractFunc type is an adapter to allow the use of ordinary functions as [AuthExtractor]s.
func (ExtractFunc) Extract ¶
func (f ExtractFunc) Extract(r *http.Request) (*Identity, error)
Extract implements AuthExtractor.
type HeaderExtractor ¶
type HeaderExtractor struct {
// HeaderUserID is the header containing the user ID.
// Defaults to "X-User-ID".
HeaderUserID string
// HeaderUserName defaults to "X-User-Name".
HeaderUserName string
// HeaderNickName defaults to "X-Nick-Name".
HeaderNickName string
// HeaderTenantID defaults to "X-Tenant-ID".
HeaderTenantID string
// HeaderRoles is a comma-separated list. Defaults to "X-User-Roles".
HeaderRoles string
// HeaderPermissions is a comma-separated list. Defaults to "X-User-Permissions".
HeaderPermissions string
// HeaderToken defaults to "X-Forwarded-Token".
HeaderToken string
}
HeaderExtractor builds an Identity from trusted HTTP headers. This is used when an upstream gateway has already authenticated the request and forwards identity via headers (e.g. X-User-ID, X-User-Roles).
It does NOT verify any token — only use behind a trusted gateway or for internal service-to-service calls.
func NewHeaderExtractor ¶
func NewHeaderExtractor() *HeaderExtractor
NewHeaderExtractor returns a HeaderExtractor with default header names.
func (*HeaderExtractor) Extract ¶
func (h *HeaderExtractor) Extract(r *http.Request) (*Identity, error)
Extract implements AuthExtractor.
type Identity ¶
type Identity struct {
// UserID is the unique identifier of the authenticated user.
UserID string `json:"user_id,omitempty"`
// UserName is the human-readable login name.
UserName string `json:"user_name,omitempty"`
// NickName is an optional display name.
NickName string `json:"nick_name,omitempty"`
// TenantID is an optional multi-tenant scope identifier.
TenantID string `json:"tenant_id,omitempty"`
// Roles is the set of role names assigned to the user.
Roles []string `json:"roles,omitempty"`
// Permissions is the set of permission strings granted to the user.
Permissions []string `json:"permissions,omitempty"`
// Token is the raw token string (JWT, opaque, etc.) used for
// authentication. Populated by extractors so it can be forwarded.
Token string `json:"-"`
// Source indicates how the identity was established: "jwt",
// "header", "custom".
Source string `json:"source,omitempty"`
// Extra holds extractor-specific metadata not covered by the
// fields above.
Extra map[string]any `json:"extra,omitempty"`
}
Identity represents the security principal associated with a request. It is the unified shape that flows through context and is propagated to downstream services.
func FromContext ¶
FromContext retrieves the identity from ctx. Returns nil if no identity is present.
func MustFromContext ¶
MustFromContext retrieves the identity from ctx or panics if absent. Use in handlers where the middleware guarantees an identity exists.
func UnmarshalIdentity ¶
UnmarshalIdentity deserializes id from JSON bytes.
func (*Identity) HasPermission ¶
HasPermission reports whether the identity has the given permission. Supports wildcard matching: "user:*" matches "user:read".
func (*Identity) IsAuthenticated ¶
IsAuthenticated reports whether this identity represents an authenticated user (UserID is non-empty).
type JWTClaims ¶
type JWTClaims struct {
Subject string // sub
Issuer string // iss
Audience []string // aud
ExpiresAt int64 // exp (unix)
Extra map[string]any // custom claims
}
JWTClaims is the claims shape expected by JWTExtractor.
type JWTExtractor ¶
type JWTExtractor struct {
// ClaimsUserID is the extra-claims key for the user ID.
// Defaults to "user_id".
ClaimsUserID string
// ClaimsUserName defaults to "user_name".
ClaimsUserName string
// ClaimsNickName defaults to "nick_name".
ClaimsNickName string
// ClaimsTenantID defaults to "tenant_id".
ClaimsTenantID string
// ClaimsRoles defaults to "roles" (expects []any or []string).
ClaimsRoles string
// ClaimsPermissions defaults to "permissions".
ClaimsPermissions string
// contains filtered or unexported fields
}
JWTExtractor extracts identity from a Bearer JWT token in the Authorization header.
func NewJWTExtractor ¶
func NewJWTExtractor(verifier JWTVerifier) *JWTExtractor
NewJWTExtractor creates a JWT-based extractor. The verifier must implement JWTVerifier (jwtutil.Auth already satisfies this via an adapter, or you can wrap it).
func (*JWTExtractor) Extract ¶
func (j *JWTExtractor) Extract(r *http.Request) (*Identity, error)
Extract implements AuthExtractor.
type JWTVerifier ¶
type JWTVerifier interface {
// Verify parses and validates a token string, returning the
// claims or an error.
Verify(token string) (*JWTClaims, error)
}
JWTVerifier is the minimal subset of jwtutil.Auth needed by JWTExtractor. Defining it here avoids a hard dependency on jwtutil, keeping authcontext usable standalone.
type PropagatingTransport ¶
type PropagatingTransport struct {
// contains filtered or unexported fields
}
PropagatingTransport is an http.RoundTripper that injects identity headers from the request's context into outbound requests.
If the context has no identity, the request passes through unchanged. If the underlying transport is nil, http.DefaultTransport is used.
func NewPropagatingTransport ¶
func NewPropagatingTransport(base http.RoundTripper) *PropagatingTransport
NewPropagatingTransport wraps base (or http.DefaultTransport if nil) with identity-header propagation using the default header names.
func NewPropagatingTransportWithHeaders ¶
func NewPropagatingTransportWithHeaders(base http.RoundTripper, h PropagationHeaders) *PropagatingTransport
NewPropagatingTransportWithHeaders is like NewPropagatingTransport but allows custom header names.
func (*PropagatingTransport) RoundTrip ¶
RoundTrip implements http.RoundTripper.
type PropagationHeaders ¶
type PropagationHeaders struct {
UserID string
UserName string
NickName string
TenantID string
Roles string
Permissions string
Token string
}
PropagationHeaders defines the header names used when forwarding an identity to a downstream service. These match the defaults in HeaderExtractor, so a downstream service using HeaderExtractor will reconstitute the same identity.
func DefaultPropagationHeaders ¶
func DefaultPropagationHeaders() PropagationHeaders
DefaultPropagationHeaders returns the standard header names matching HeaderExtractor defaults.