authcontext

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 2026 License: MIT Imports: 6 Imported by: 0

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:

  1. **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.
  2. **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.
  3. **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

Constants

This section is empty.

Variables

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

func BearerFromHeader(r *http.Request) string

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

func MarshalIdentity(id *Identity) ([]byte, error)

MarshalIdentity serializes id to JSON bytes.

func WithIdentity

func WithIdentity(ctx context.Context, id *Identity) context.Context

WithIdentity stores id in ctx. Passing a nil identity clears the value (returns ctx without the key).

Types

type AuthExtractor

type AuthExtractor interface {
	Extract(r *http.Request) (*Identity, error)
}

AuthExtractor extracts an Identity from an HTTP request. Different implementations parse JWT tokens, trusted headers, cookies, etc.

type ExtractFunc

type ExtractFunc func(r *http.Request) (*Identity, error)

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

func FromContext(ctx context.Context) *Identity

FromContext retrieves the identity from ctx. Returns nil if no identity is present.

func MustFromContext

func MustFromContext(ctx context.Context) *Identity

MustFromContext retrieves the identity from ctx or panics if absent. Use in handlers where the middleware guarantees an identity exists.

func UnmarshalIdentity

func UnmarshalIdentity(data []byte) (*Identity, error)

UnmarshalIdentity deserializes id from JSON bytes.

func (*Identity) HasPermission

func (i *Identity) HasPermission(perm string) bool

HasPermission reports whether the identity has the given permission. Supports wildcard matching: "user:*" matches "user:read".

func (*Identity) HasRole

func (i *Identity) HasRole(role string) bool

HasRole reports whether the identity has the given role.

func (*Identity) IsAuthenticated

func (i *Identity) IsAuthenticated() bool

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

func (t *PropagatingTransport) RoundTrip(req *http.Request) (*http.Response, error)

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.

Jump to

Keyboard shortcuts

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