auth

package
v0.1.0-develop.2026060... Latest Latest
Warning

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

Go to latest
Published: Jun 9, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package auth holds the kernel-level authentication plan model: the sealed AuthPlan / ListenerAuth interfaces, their five typed implementations (None, JWT, JWTFromAssembly, MTLS, ServiceToken), and the narrow dependency interfaces (IntentTokenVerifier, NonceStore, HMACKeyring, AuthProvider, ...) that runtime/auth concrete types satisfy structurally.

Previously these lived in kernel/cell. They were extracted in PR #615 to keep kernel/cell focused on the Cell/Registrar registration model, mirroring the package boundary that Kratos draws between its `registry/` (cell registration) and `middleware/auth/` (authentication) sub-packages.

Dependency direction:

  • kernel/auth depends on kernel/cell only for the Cell type referenced by AssemblyRef.Cell(id) — a one-way edge, no cycle.
  • runtime/auth provides the concrete verifiers / nonce stores / HMAC rings and uses type aliases (auth.Claims, auth.TokenIntent) to share data across the kernel/runtime boundary without conversion.

ref: kratos middleware/auth/ — auth as an independent sub-package alongside

registry/, transport/, log/.

ref: kubernetes/apiserver pkg/authentication/authenticator/interfaces.go —

sealed Token/Request/Password authenticator interfaces.

Index

Constants

View Source
const MinHMACKeyBytes = 32

MinHMACKeyBytes is the minimum byte length required for HMAC secrets used by AuthServiceToken. NIST SP 800-107 §5.3.4 recommends an HMAC key strength of at least the security strength of the underlying hash; for HMAC-SHA-256 that is 256 bits = 32 bytes. NewAuthServiceToken enforces this at construction time; runtime/auth.ServiceTokenMiddleware enforces it again at wiring time (defense in depth) so any auth.HMACKeyring implementation that returns a shorter Current() secret is rejected at both ends.

Variables

This section is empty.

Functions

This section is empty.

Types

type AssemblyRef

type AssemblyRef interface {
	// ID returns the assembly's unique identifier.
	ID() string
	// CellIDs returns the ordered list of registered cell identifiers.
	CellIDs() []string
	// Cell returns the registered Cell with the given ID, or nil if no
	// cell with that ID is registered. Callers are responsible for type-
	// asserting the returned Cell to the role-specific interface they
	// require (e.g. AuthProvider).
	Cell(id string) cell.Cell
}

AssemblyRef is the contract kernel needs from an assembly: identity (ID), the registered cell list (CellIDs), and by-ID cell lookup (Cell). Using a named interface preserves type safety at composition boundaries and lets callers in runtime/bootstrap iterate authProvider discovery without an implicit type assertion to a private sub-interface.

Bootstrap passes the concrete *assembly.CoreAssembly which satisfies this interface structurally; identity checks (same pointer) are done in runtime/bootstrap, not in kernel.

ASSEMBLYREF-METHOD-SET-01 (tools/archtest/assemblyref_method_set_test.go) locks this method set against accidental drift.

type AuthJWT

type AuthJWT struct {
	// Verifier is the IntentTokenVerifier used to validate JWTs. Required; nil
	// (bare or typed) is rejected by NewAuthJWT with an error (B2-K-02 dropped
	// the MustNewAuthJWT panic variant in PR #553 — composition roots
	// propagate the error to bootstrap). Do not set this field directly after
	// construction; use NewAuthJWT(v) which enforces the non-nil invariant.
	Verifier IntentTokenVerifier
}

AuthJWT is the JWT-authenticated listener plan. The verifier is supplied at construction time via NewAuthJWT. Bootstrap extracts it during phase5 and installs the router-aware AuthMiddleware so that Public/PasswordResetExempt routes declared via auth.Mount are honored.

func NewAuthJWT

func NewAuthJWT(v IntentTokenVerifier) (AuthJWT, error)

NewAuthJWT constructs an AuthJWT plan. Returns an error when v is nil so the caller can decide between fail-fast (composition-root error propagation) and graceful refusal.

func (AuthJWT) Describe

func (AuthJWT) Describe() string

type AuthJWTFromAssembly

type AuthJWTFromAssembly struct {
	// Assembly must be the same *assembly.CoreAssembly instance later
	// supplied to bootstrap.WithAssembly. Constructors only reject
	// nil/typed-nil; wrong-instance values pass construction and are
	// caught at bootstrap phase0.
	Assembly AssemblyRef
	// contains filtered or unexported fields
}

AuthJWTFromAssembly is a lazy JWT plan that resolves its verifier from an AuthProvider cell in the assembly during bootstrap phase4. Use it when the verifier is owned by a cell (typical for accesscore-style designs).

The resolved verifier is stored in an atomic.Pointer so that concurrent reads from the router are safe without locking.

AuthJWTFromAssembly implements only ListenerAuth (same rationale as AuthJWT).

Lifecycle constraint: the Assembly value must be the same instance later passed to bootstrap.WithAssembly. Bootstrap phase0 (validateAuthJWTFromAssemblyPlans in runtime/bootstrap/auth_plan_validate.go) rejects direct struct literals, nil assemblies, wrappers, copies, or fakes even when they share the same ID. Construct AuthJWTFromAssembly from the canonical *assembly.CoreAssembly.

func NewAuthJWTFromAssembly

func NewAuthJWTFromAssembly(asm AssemblyRef) (AuthJWTFromAssembly, error)

NewAuthJWTFromAssembly constructs an AuthJWTFromAssembly plan. Returns an error when asm is nil or a typed-nil interface value. The same-instance constraint (see AuthJWTFromAssembly type doc) is checked later, at bootstrap phase0.

func (AuthJWTFromAssembly) Describe

func (AuthJWTFromAssembly) Describe() string

Describe returns "jwt" so that operator dashboards and alert rules that filter on auth=jwt match both AuthJWT and AuthJWTFromAssembly paths consistently. Both ultimately install the same JWT verifier mechanism.

func (AuthJWTFromAssembly) IsConstructed

func (p AuthJWTFromAssembly) IsConstructed() bool

IsConstructed reports whether the plan was built through NewAuthJWTFromAssembly. Direct struct literals do not initialize the shared resolver pointer and are rejected by bootstrap phase0 before phase4 can silently skip SetResolved.

func (AuthJWTFromAssembly) ResolvedVerifier

func (p AuthJWTFromAssembly) ResolvedVerifier() IntentTokenVerifier

ResolvedVerifier returns the verifier once it has been discovered by phase4. Returns nil before SetResolved has been called.

Method is on value receiver so it works when AuthJWTFromAssembly is stored by value in []ListenerAuth. The underlying atomic.Pointer is already a pointer so concurrent safety is preserved.

func (AuthJWTFromAssembly) SetResolved

func (p AuthJWTFromAssembly) SetResolved(v IntentTokenVerifier)

SetResolved stores the verifier discovered by phase4. Called by bootstrap; must not be called by cell code.

This method is exported to allow access from runtime/bootstrap (a different package), but is not part of the public API for cell authors. The archtest in tools/archtest/auth_plan_test.go (AUTH-PLAN-04) enforces that cells/ do not call it.

Method is on value receiver: the internal atomic.Pointer is already a pointer, so the store is visible to all copies of this value.

type AuthKind

type AuthKind uint8

AuthKind is the discriminant for an AuthPlan variant. Declared as uint8 to keep the type small; the iota values are stable.

const (
	AuthKindNone            AuthKind = iota // AuthNone
	AuthKindJWT                             // AuthJWT
	AuthKindJWTFromAssembly                 // AuthJWTFromAssembly
	AuthKindMTLS                            // AuthMTLS
	AuthKindServiceToken                    // AuthServiceToken
	AuthKindOperator                        // AuthOperator (see operator.go)
)

type AuthMTLS

type AuthMTLS struct{}

AuthMTLS is the mutual-TLS listener plan. The middleware asserts that the request arrived over a TLS connection with at least one peer certificate. Chain verification MUST be delegated to tls.Config.ClientAuth; see the runtime/bootstrap phase0 validation (validateAuthPlanMTLSBindings).

func (AuthMTLS) Describe

func (AuthMTLS) Describe() string

type AuthNone

type AuthNone struct{}

AuthNone is the no-op auth plan. Use it for listeners that are network-isolated and require no authentication gate (e.g. the HealthListener behind a Kubernetes probe path).

func (AuthNone) Describe

func (AuthNone) Describe() string

type AuthOperator

type AuthOperator struct {
	// Username and Password are the env operator credentials, compared in
	// constant time against the HTTP Basic Auth header. Required; empty values
	// are rejected by NewAuthOperator. Held as raw bytes (not a struct mirroring
	// runtime/auth.BootstrapCredentials) so the apply-switch maps them into the
	// runtime type at construction with no parallel struct.
	Username []byte
	Password []byte
	// Limiter is the per-IP rate limiter applied before credential parsing.
	// Required; nil (bare or typed) is rejected by NewAuthOperator.
	Limiter OperatorRateLimiter
	// OnAuthFail is an optional observer invoked after a 401/429 is written
	// (reason ∈ {"missing_header","wrong_credentials","rate_limited"}); nil
	// disables it. Routes operator auth failures to an audit log without
	// kernel/auth importing cells/.
	OnAuthFail func(ctx context.Context, reason string)
}

AuthOperator is the operator-credential listener plan for the admin control-plane (cell.AdminListener). Bootstrap installs runtime/auth.NewBootstrapMiddleware with these credentials, rate limiter, and optional auth-fail observer: per-IP rate limit → HTTP Basic Auth → constant-time credential comparison → uniform 401. operator→system actions (e.g. projection rebuild) are authenticated by the env operator credentials, NOT by a caller-cell allowlist.

func NewAuthOperator

func NewAuthOperator(
	username, password []byte,
	limiter OperatorRateLimiter,
	onAuthFail func(ctx context.Context, reason string),
) (AuthOperator, error)

NewAuthOperator constructs an AuthOperator plan. Returns an error when the credentials are too weak or the limiter is nil:

  • empty username/password — an operator gate with empty credentials would authenticate every request;
  • username containing control characters — a malformed credential, almost always an accidentally-injected newline/tab from a secret manager;
  • password shorter than operatorMinPasswordLen — a one-byte password is trivially brute-forceable and cannot protect the admin plane;
  • nil limiter — without per-IP rate limiting, credentials cannot defeat brute-force enumeration.

These mirror the setup/admin credential floor (cellmodules/accesscore loadBootstrapCredentials) so both operator gates share one strength contract. The observer is optional (nil disables it).

func (AuthOperator) Describe

func (AuthOperator) Describe() string

type AuthPlan

type AuthPlan interface {

	// Describe returns a human-readable fingerprint for startup logging.
	// Used by runtime/bootstrap/auth_plan_describe.go (the only allowed location
	// for the "jwt"/"mtls"/"service-token" string literals).
	Describe() string
	// contains filtered or unexported methods
}

AuthPlan is the sealed base interface for all authentication plans. The unexported marker method authPlanKind prevents implementations outside this package, giving us a closed enumeration without code generation.

type AuthProvider

type AuthProvider interface {
	TokenVerifier() IntentTokenVerifier
}

AuthProvider is an optional cell-level interface that exposes an IntentTokenVerifier for runtime authentication. AuthJWTFromAssembly walks the assembly's CellIDs in deterministic order during bootstrap phase4 and promotes the unique implementer's verifier; zero, multiple, or nil verifiers are rejected with a startup error.

type AuthServiceToken

type AuthServiceToken struct {
	// Store is the NonceStore for replay prevention. Required.
	Store NonceStore
	// Ring is the HMACKeyring supplying signing secrets. Required.
	Ring HMACKeyring
}

AuthServiceToken is the HMAC-SHA256 service token plan. Bootstrap installs auth.ServiceTokenMiddleware with the provided ring and nonce store.

func NewAuthServiceToken

func NewAuthServiceToken(store NonceStore, ring HMACKeyring) (AuthServiceToken, error)

NewAuthServiceToken constructs an AuthServiceToken plan. Returns an error if either argument is nil, if store.Kind() is NonceStoreKindNoop, or if ring.Current() returns fewer than MinHMACKeyBytes bytes. A service-token plan is a replay-safe internal-listener guard; NoopNonceStore explicitly disables replay defense and is therefore not a valid AuthServiceToken dependency. A short HMAC secret silently weakens MAC strength and is rejected at construction time (NIST SP 800-107 §5.3.4 — HMAC key length must match underlying hash security strength: 256-bit / 32-byte for HMAC-SHA-256).

func (AuthServiceToken) Describe

func (AuthServiceToken) Describe() string

type Claims

type Claims struct {
	// Subject is the principal identifier (user ID, service name, etc.).
	Subject string
	// Issuer identifies the token issuer.
	Issuer string
	// Audience is the intended recipient(s).
	Audience []string
	// ExpiresAt is the expiration time.
	ExpiresAt time.Time
	// IssuedAt is the token issue time.
	IssuedAt time.Time
	// Roles is the set of roles associated with the subject.
	Roles []string
	// TokenUse records the intent declared by the JWT's token_use claim.
	TokenUse TokenIntent
	// SessionID is the "sid" claim binding the token to a specific session.
	SessionID string
	// TenantID is the "tenant_id" claim identifying the tenant isolation
	// boundary the subject belongs to. Empty in single-tenant deployments (no
	// tenant claim issued). When non-empty it MUST be a valid UUID; the
	// runtime/auth JWTVerifier.VerifyIntent validates and canonicalizes it via
	// pkg/tenant.ParseTenantID before returning Claims (a malformed tenant claim
	// fails closed), so consumers may treat a non-empty value as a canonical
	// lowercase UUID. Typed string (not pkg/tenant.TenantID) to keep this kernel
	// wire type free of the tenant package's UUID dependency; the runtime
	// boundary owns validation.
	TenantID string
	// PasswordResetRequired indicates that the subject must change their password.
	PasswordResetRequired bool
	// JTI is the JWT ID claim ("jti"), a unique identifier for the token.
	// Empty string when the claim is absent.
	JTI string
	// Extra holds additional claims not covered by the standard fields.
	Extra map[string]any
}

Claims represents the decoded token claims. This is the canonical definition; runtime/auth.Claims is a type alias of this type so callers share the same struct without conversion at package boundaries.

type HMACKeyring

type HMACKeyring interface {
	// Current returns a copy of the active signing secret.
	Current() []byte
	// Secrets returns all secrets in try-order: current first, then previous.
	Secrets() [][]byte
}

HMACKeyring supplies HMAC secrets for service token operations. This is the kernel projection of runtime/auth.HMACKeyRing; *HMACKeyRing satisfies it structurally (Current/Secrets methods already exist).

type IntentTokenVerifier

type IntentTokenVerifier interface {
	VerifyIntent(ctx context.Context, token string, expected TokenIntent) (Claims, error)
}

IntentTokenVerifier verifies a JWT token and requires its declared intent to match the expected value. This is the kernel projection of the same interface in runtime/auth; runtime/auth.JWTVerifier satisfies it structurally.

type ListenerAuth

type ListenerAuth interface {
	AuthPlan
	// contains filtered or unexported methods
}

ListenerAuth is the (only) typed authentication scheme accepted by bootstrap.WithListener. RouteGroups inherit their listener's auth chain uniformly — there is no group-level override (PR269 round-3: cells that need a different scheme should declare their routes on a different listener).

type NonceStore

type NonceStore interface {
	// CheckAndMark checks whether nonce has been seen within its TTL window.
	// If not, it marks the nonce and returns nil. Returns ErrNonceReused on replay.
	CheckAndMark(ctx context.Context, nonce string) error
	// Kind reports the implementation classification.
	Kind() NonceStoreKind
}

NonceStore tracks nonces for replay prevention. This is the kernel projection of runtime/auth.NonceStore; runtime/auth.InMemoryNonceStore and runtime/auth.NoopNonceStore satisfy it structurally. Note: the kernel interface uses (ctx, key, ttl) to accommodate future distributed implementations; runtime/auth.NonceStore uses (ctx, nonce) without ttl. We match the existing runtime/auth.NonceStore signature so no adapter is needed.

type NonceStoreKind

type NonceStoreKind string

NonceStoreKind classifies a NonceStore implementation for startup validation. Mirrors runtime/auth.NonceStoreKind; kept as a string for extensibility.

const (
	// NonceStoreKindNoop is the explicit disable-replay-check sentinel.
	// Production deployments must reject this kind for service-token guards.
	NonceStoreKindNoop NonceStoreKind = "noop"
	// NonceStoreKindInMemory is the single-process map-backed implementation.
	NonceStoreKindInMemory NonceStoreKind = "in_memory"
	// NonceStoreKindDistributed is reserved for shared backends (Redis, etc.).
	NonceStoreKindDistributed NonceStoreKind = "distributed"
)

func (NonceStoreKind) ReplaySafe

func (k NonceStoreKind) ReplaySafe(requireDistributed bool) bool

ReplaySafe reports whether a nonce store of this kind provides adequate service-token replay defense for the given topology requirement. requireDistributed is true for real multi-pod deployments, where a single-process (in-memory) store cannot coordinate replay defense across pods.

This is the single source of truth for "which NonceStoreKind is replay-safe". Both composition.SharedDeps.validateProductionNonceStore (config-time, on the declared SharedDeps.NonceStore, with rich diagnostics) and runtime/bootstrap's phase0 auth-plan check (on the store that ACTUALLY guards the listener) gate on this one predicate so the two enforcement points cannot drift. The noop sentinel and any unrecognized kind are never replay-safe — fail-closed (#1410 review F2/F1).

type OperatorRateLimiter

type OperatorRateLimiter interface {
	Allow(key string) bool
}

OperatorRateLimiter decides whether a request identified by key (typically the client IP) should be allowed. It is the kernel projection of runtime/auth.BootstrapRateLimiter so that the AuthOperator plan can hold its limiter as a kernel-level interface, keeping kernel/ free of runtime/ imports (same idiom as NonceStore / HMACKeyring in auth_types.go). The composition root injects a concrete per-IP limiter (e.g. adapters/ratelimit.TokenBucket); there is deliberately no built-in allow-all implementation — operator credentials must always be rate-limited to defeat brute-force enumeration.

type TokenIntent

type TokenIntent string

TokenIntent distinguishes how a JWT is meant to be used. The values here are the canonical definition; runtime/auth.TokenIntent is a type alias of this type.

const (
	// TokenIntentAccess marks a short-lived credential for calling business
	// endpoints. Verifier rejects any access token replayed at /auth/refresh.
	TokenIntentAccess TokenIntent = "access"
)

func (TokenIntent) IsValid

func (t TokenIntent) IsValid() bool

IsValid reports whether the intent is one of the known enum values.

Directories

Path Synopsis
Package authtest provides composition-root convenience helpers for AuthPlan constructors.
Package authtest provides composition-root convenience helpers for AuthPlan constructors.

Jump to

Keyboard shortcuts

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