authentication

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 7 Imported by: 0

README

authentication

CI CodeQL Coverage Mutation Documentation Go Reference Release Go License

authentication is a production-oriented authentication library for Go services. It turns Basic credentials, opaque bearer tokens, API keys, JWTs, or OIDC ID tokens into an immutable principal. It does not decide whether that principal may perform an action.

The root, Basic, bearer, API-key, HTTP, logging, and test packages use only the Go standard library plus the narrow clock capability contracts. JWT, OIDC, and OpenTelemetry live in separate modules so their larger dependency graphs are opt-in.

Requirements

  • Go 1.26 or newer.
  • clock v1 for deterministic time seams.
  • jwt: lestrrat-go/jwx v3.
  • oidc: coreos/go-oidc v3 and go-jose v4.
  • authotel: OpenTelemetry API v1.44.

Install

go get github.com/faustbrian/go-authentication

Add an optional module only when needed:

go get github.com/faustbrian/go-authentication/jwt
go get github.com/faustbrian/go-authentication/oidc
go get github.com/faustbrian/go-authentication/authotel

Five-minute quickstart

extractor, err := authhttp.NewExtractor(authhttp.BearerAuthorization())
if err != nil {
	return err
}

authenticator, err := bearer.New(bearer.ValidatorFunc(
	func(ctx context.Context, token string) (authentication.Principal, error) {
		if token != configuredToken {
			return authentication.Principal{},
				authentication.NewFailure(authentication.FailureRejected)
		}
		return authentication.NewPrincipal(authentication.PrincipalSpec{
			Subject: "orders-worker",
			Method:  "bearer",
		})
	},
))
if err != nil {
	return err
}

middleware, err := authhttp.NewMiddleware(extractor, authenticator)
if err != nil {
	return err
}

handler := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	principal, ok := authentication.PrincipalFromContext(r.Context())
	if !ok {
		http.Error(w, "authentication invariant failed", http.StatusInternalServerError)
		return
	}
	fmt.Fprintln(w, principal.Subject())
}))

The middleware is fail-closed. It authenticates and stores the principal, but it deliberately performs no role, permission, ownership, or policy checks.

Packages

Package Purpose
root Immutable principals, typed credentials, failures, composition, instrumentation
basic Constant-work static Basic authentication
bearer Callback and interface adapters for opaque tokens
apikey Callback and atomically rotatable static API keys
authhttp Strict extraction, challenges, and authentication-only middleware
authlog Secret-safe standard log/slog instrumentation
authtest Deterministic principals, clocks, authenticators, HTTP fixtures, assertions
jwt Optional strict JWT/JWK validation and owned remote cache
oidc Optional OIDC discovery and ID-token validation without background refresh
authotel Optional OpenTelemetry traces and bounded metrics

Security defaults

  • Credential values always format as redacted.
  • Static secrets are compared through per-authenticator keyed HMAC-SHA-256 digests with constant-time comparison.
  • Multiple credential sources are rejected as ambiguous.
  • A 401 Unauthorized response is emitted only with at least one valid WWW-Authenticate challenge; missing challenge metadata fails as unavailable.
  • Query and cookie credentials are disabled unless explicitly configured.
  • Query credential constructors are deprecated for new designs because URLs can be retained before the extractor sees them.
  • Claims, tokens, keys, HTTP bodies, and cache work have explicit bounds.
  • JWT algorithms, issuer, audience, key ID, key metadata, and time claims are validated explicitly.
  • OIDC uses upstream protocol verification with bounded synchronous JWK refresh and stale known-key availability during issuer outages.
  • Instrumentation receives only credential kind, outcome, failure kind, and duration; it never receives credential or principal contents.

Documentation

Start with the quickstart. Protocol-specific guides are under docs/guides, including HTTP, JSON-RPC, service accounts, credential rotation, and anonymous routes. Operational and compatibility material is in docs/operations.md, docs/troubleshooting.md, and docs/compatibility.md. Observable protocol choices are recorded in the specification decision register.

For a security review or rollout, use the adoption checklist, threat model, findings, and test matrices.

The authentication-versus-authorization boundary is documented in docs/authentication-vs-authorization.md. Security reports follow SECURITY.md, and contributions follow CONTRIBUTING.md.

License

MIT. See LICENSE.

Ecosystem

Use the Golib documentation portal to choose companion packages, supported stacks, recipes, and operations guidance.

Documentation

Overview

Package authentication defines framework-independent authentication contracts.

Index

Examples

Constants

View Source
const (
	// MaxChallengeParameters bounds authentication challenge metadata.
	MaxChallengeParameters = 16
	// MaxChallengeSchemeBytes bounds an authentication scheme token.
	MaxChallengeSchemeBytes = 64
	// MaxChallengeNameBytes bounds an authentication parameter name.
	MaxChallengeNameBytes = 64
	// MaxChallengeValueBytes bounds an authentication parameter value.
	MaxChallengeValueBytes = 1024
)
View Source
const (
	// MaxClaims is the maximum number of entries in a principal claim map.
	MaxClaims = 128
	// MaxClaimDepth is the maximum nesting depth accepted in principal claims.
	MaxClaimDepth = 8
	// MaxClaimCollection is the maximum number of elements in a nested claim
	// map, slice, or array.
	MaxClaimCollection = 256
)

Variables

View Source
var (
	// ErrCredentialsAbsent means no credential was supplied by an enabled source.
	ErrCredentialsAbsent = errors.New("authentication: credentials absent")
	// ErrCredentialsInvalid means credential syntax or protocol data was invalid.
	ErrCredentialsInvalid = errors.New("authentication: credentials invalid")
	// ErrCredentialsRejected means a validly formed credential was not accepted.
	ErrCredentialsRejected = errors.New("authentication: credentials rejected")
	// ErrAuthenticationUnavailable means validation could not be completed due
	// to a transient dependency or infrastructure failure.
	ErrAuthenticationUnavailable = errors.New("authentication: validation unavailable")
	// ErrAmbiguousCredentials means more than one credential was supplied where
	// exactly one was required.
	ErrAmbiguousCredentials = errors.New("authentication: ambiguous credentials")
	// ErrInvalidChallenge identifies invalid challenge protocol data.
	ErrInvalidChallenge = errors.New("authentication: invalid challenge")
	// ErrInvalidConfiguration identifies unsafe or incomplete authenticator
	// configuration.
	ErrInvalidConfiguration = errors.New("authentication: invalid configuration")
)
View Source
var ErrInvalidPrincipal = errors.New("authentication: invalid principal")

ErrInvalidPrincipal identifies a principal that violates an identity invariant or contains claims that cannot be copied safely.

Functions

func ContextWithPrincipal

func ContextWithPrincipal(ctx context.Context, principal Principal) context.Context

ContextWithPrincipal returns a child context containing principal.

Types

type APIKeyCredential

type APIKeyCredential struct {
	// contains filtered or unexported fields
}

APIKeyCredential is an API key with an optional non-secret key identifier. Its formatted representation is always redacted.

func NewAPIKeyCredential

func NewAPIKeyCredential(keyID, key string) APIKeyCredential

NewAPIKeyCredential creates an API-key credential.

func (APIKeyCredential) GoString

func (APIKeyCredential) GoString() string

func (APIKeyCredential) Key

func (c APIKeyCredential) Key() string

func (APIKeyCredential) KeyID

func (c APIKeyCredential) KeyID() string

func (APIKeyCredential) Kind

func (APIKeyCredential) String

func (APIKeyCredential) String() string

type Authenticator

type Authenticator interface {
	Authenticate(context.Context, Credential) (Result, error)
}

Authenticator validates one typed credential.

Example (BackgroundConsumer)
package main

import (
	"context"
	"fmt"

	authentication "github.com/faustbrian/go-authentication"
	"github.com/faustbrian/go-authentication/apikey"
)

func main() {
	authenticator, _ := apikey.NewStatic([]apikey.Entry{{
		ID: "worker", Key: "secret",
		Principal: authentication.PrincipalSpec{Subject: "invoice-worker"},
	}})
	result, err := authenticator.Authenticate(
		context.Background(),
		authentication.NewAPIKeyCredential("worker", "secret"),
	)
	principal, authenticated := result.Principal()
	fmt.Println(err, authenticated, principal.Subject())
}
Output:
<nil> true invoice-worker

type BasicCredential

type BasicCredential struct {
	// contains filtered or unexported fields
}

BasicCredential is a username and password extracted from Basic authentication. Its formatted representation is always redacted.

func NewBasicCredential

func NewBasicCredential(username, password string) BasicCredential

NewBasicCredential creates a Basic credential.

func (BasicCredential) GoString

func (BasicCredential) GoString() string

func (BasicCredential) Kind

func (BasicCredential) Password

func (c BasicCredential) Password() string

func (BasicCredential) String

func (BasicCredential) String() string

func (BasicCredential) Username

func (c BasicCredential) Username() string

type BearerCredential

type BearerCredential struct {
	// contains filtered or unexported fields
}

BearerCredential is an opaque bearer token. Its formatted representation is always redacted.

func NewBearerCredential

func NewBearerCredential(token string) BearerCredential

NewBearerCredential creates a bearer credential.

func (BearerCredential) GoString

func (BearerCredential) GoString() string

func (BearerCredential) Kind

func (BearerCredential) String

func (BearerCredential) String() string

func (BearerCredential) Token

func (c BearerCredential) Token() string

type Binding

type Binding struct {
	Kind          CredentialKind
	Authenticator Authenticator
}

Binding associates a credential kind with one authenticator. Bindings of the same kind are evaluated in declaration order.

type Challenge

type Challenge struct {
	// contains filtered or unexported fields
}

Challenge is an immutable authentication challenge. Transport adapters are responsible for serializing it according to their protocol.

func NewChallenge

func NewChallenge(scheme string, parameters map[string]string) (Challenge, error)

NewChallenge validates and copies challenge protocol data.

func (Challenge) Parameters

func (c Challenge) Parameters() map[string]string

Parameters returns a defensive copy of the authentication parameters.

func (Challenge) Scheme

func (c Challenge) Scheme() string

Scheme returns the authentication scheme.

type Clock deprecated

type Clock interface {
	clockpkg.Clock
}

Clock supplies time to authentication instrumentation.

Deprecated: depend on clock.Clock in new code. This named compatibility contract remains available throughout v1.

type Composite

type Composite struct {
	// contains filtered or unexported fields
}

Composite routes typed credentials to ordered authenticators. Only rejected credentials fall through; every other failure is terminal.

func NewComposite

func NewComposite(bindings []Binding) (*Composite, error)

NewComposite validates and copies ordered authenticator bindings.

func (*Composite) Authenticate

func (c *Composite) Authenticate(ctx context.Context, credential Credential) (Result, error)

Authenticate evaluates authenticators bound to the credential kind in deterministic declaration order.

type Credential

type Credential interface {
	Kind() CredentialKind
	fmt.Stringer
}

Credential is a typed authentication credential. Implementations redact their secret-bearing representation.

type CredentialKind

type CredentialKind string

CredentialKind identifies a credential's protocol family.

const (
	CredentialBasic  CredentialKind = "basic"
	CredentialBearer CredentialKind = "bearer"
	CredentialAPIKey CredentialKind = "api_key"
)

type Event

type Event struct {
	Outcome  Outcome
	Failure  FailureKind
	Duration time.Duration
}

Event contains bounded, secret-free authentication telemetry.

type Failure

type Failure struct {
	// contains filtered or unexported fields
}

Failure is a secret-safe, typed authentication failure.

func NewFailure

func NewFailure(kind FailureKind, options ...FailureOption) *Failure

NewFailure creates a classified, secret-safe failure.

func (*Failure) Challenges

func (f *Failure) Challenges() []Challenge

Challenges returns a defensive copy of the associated challenges.

func (*Failure) Error

func (f *Failure) Error() string

Error returns only the stable classification and never formats the cause.

func (*Failure) Is

func (f *Failure) Is(target error) bool

Is supports stable errors.Is matching by failure classification.

func (*Failure) Kind

func (f *Failure) Kind() FailureKind

Kind returns the stable failure classification.

func (*Failure) Unwrap

func (f *Failure) Unwrap() error

Unwrap returns the underlying operational cause, if any.

type FailureKind

type FailureKind string

FailureKind classifies authentication failures independently of transports.

const (
	FailureAbsent      FailureKind = "absent"
	FailureInvalid     FailureKind = "invalid"
	FailureRejected    FailureKind = "rejected"
	FailureUnavailable FailureKind = "unavailable"
	FailureAmbiguous   FailureKind = "ambiguous"
)

type FailureOption

type FailureOption func(*Failure)

FailureOption configures a Failure.

func WithChallenges

func WithChallenges(challenges ...Challenge) FailureOption

WithChallenges associates transport-independent challenges with a failure.

func WithFailureCause

func WithFailureCause(cause error) FailureOption

WithFailureCause preserves cause for errors.Is and errors.As without including the cause text in Failure.Error.

type Instrumented

type Instrumented struct {
	// contains filtered or unexported fields
}

Instrumented decorates an authenticator with failure-isolated telemetry.

func NewInstrumented

func NewInstrumented(authenticator Authenticator, instrumenter Instrumenter, clock Clock) (*Instrumented, error)

NewInstrumented creates an authentication instrumentation decorator.

func (*Instrumented) Authenticate

func (i *Instrumented) Authenticate(ctx context.Context, credential Credential) (Result, error)

Authenticate reports bounded outcome metadata without changing the wrapped authenticator's result or error.

type Instrumenter

type Instrumenter interface {
	Start(context.Context, CredentialKind) (context.Context, func(Event))
}

Instrumenter starts instrumentation for one authentication attempt. Implementations must not derive attributes from credential contents.

type Outcome

type Outcome string

Outcome is the bounded authentication outcome reported to instrumentation.

const (
	OutcomeAuthenticated Outcome = "authenticated"
	OutcomeAnonymous     Outcome = "anonymous"
	OutcomeFailed        Outcome = "failed"
)

type Principal

type Principal struct {
	// contains filtered or unexported fields
}

Principal is an immutable authenticated identity or the explicit anonymous identity. Its zero value is anonymous.

func AnonymousPrincipal

func AnonymousPrincipal() Principal

AnonymousPrincipal returns the explicit anonymous identity.

func NewPrincipal

func NewPrincipal(spec PrincipalSpec) (Principal, error)

NewPrincipal validates and copies authenticated identity data.

func PrincipalFromContext

func PrincipalFromContext(ctx context.Context) (Principal, bool)

PrincipalFromContext retrieves a principal stored by ContextWithPrincipal.

func (Principal) Audiences

func (p Principal) Audiences() []string

Audiences returns a copy of the intended audiences.

func (Principal) AuthenticatedAt

func (p Principal) AuthenticatedAt() time.Time

AuthenticatedAt returns the time at which the identity was authenticated.

func (Principal) Claims

func (p Principal) Claims() map[string]any

Claims returns a deep copy of the bounded claim set.

func (Principal) IsAnonymous

func (p Principal) IsAnonymous() bool

IsAnonymous reports whether p represents absence of an authenticated identity.

func (Principal) Issuer

func (p Principal) Issuer() string

Issuer returns the authority that asserted the identity, when applicable.

func (Principal) Method

func (p Principal) Method() string

Method returns the authentication method that established the identity.

func (Principal) Scopes

func (p Principal) Scopes() []string

Scopes returns a copy of the scopes asserted by the credential. Scopes are authentication data and are not an authorization decision.

func (Principal) Subject

func (p Principal) Subject() string

Subject returns the stable subject identifier.

func (Principal) TenantHints

func (p Principal) TenantHints() []string

TenantHints returns a copy of non-authoritative tenant hints.

type PrincipalSpec

type PrincipalSpec struct {
	Subject         string
	Method          string
	Issuer          string
	Audiences       []string
	TenantHints     []string
	Scopes          []string
	Claims          map[string]any
	AuthenticatedAt time.Time
}

PrincipalSpec contains the identity data used to construct a Principal. Callers may reuse or mutate its slices and maps after NewPrincipal returns.

type Result

type Result struct {
	// contains filtered or unexported fields
}

Result is the outcome of successful authentication policy evaluation.

func AnonymousResult

func AnonymousResult() Result

AnonymousResult creates an explicit anonymous result for optional routes.

func NewAuthenticatedResult

func NewAuthenticatedResult(principal Principal) (Result, error)

NewAuthenticatedResult creates a result for a concrete authenticated identity.

func (Result) Principal

func (r Result) Principal() (Principal, bool)

Principal returns the identity and whether it is authenticated.

func (Result) State

func (r Result) State() ResultState

State returns the result state.

type ResultState

type ResultState string

ResultState identifies whether authentication established an identity or an explicitly permitted anonymous state.

const (
	ResultAuthenticated ResultState = "authenticated"
	ResultAnonymous     ResultState = "anonymous"
)

Directories

Path Synopsis
Package apikey provides static and callback API-key authenticators.
Package apikey provides static and callback API-key authenticators.
Package authhttp provides strict HTTP credential extraction, challenges, and authentication-only middleware for net/http.
Package authhttp provides strict HTTP credential extraction, challenges, and authentication-only middleware for net/http.
Package authlog adapts authentication instrumentation to log/slog.
Package authlog adapts authentication instrumentation to log/slog.
authotel module
Package authtest provides deterministic authentication fixtures and assertions.
Package authtest provides deterministic authentication fixtures and assertions.
Package basic provides Basic credential authenticators.
Package basic provides Basic credential authenticators.
Package bearer provides validation adapters for opaque bearer tokens.
Package bearer provides validation adapters for opaque bearer tokens.
jwt module
oidc module

Jump to

Keyboard shortcuts

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