authn

package
v0.7.5 Latest Latest
Warning

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

Go to latest
Published: May 26, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package authn provides an engine-agnostic Kratos middleware dispatcher for authentication. The main package is a pure dispatcher: it knows nothing about credential carriers (Bearer token, mTLS PeerCertificate, API-Key header, signature, etc.). Engine sub-packages (e.g. `security/authn/jwt`) are responsible for credential I/O.

Dispatcher form (P0-4b):

authn.Server(
    authn.Multi(
        authn.Named(jwt.Scheme,    jwt.NewAuthenticator(...)),
        authn.Named(apikey.Scheme, apikey.NewAuthenticator(...)),
    ),
    authn.WithRulesFuncs(examplev1.AuthnRules, iamv1.AuthnRules),
)

`authn.Server` itself is engine-agnostic: it consumes the annotation table (`Rules`) generated by `protoc-gen-servora-authn` to decide for each RPC path whether to skip (PublicMethods), restrict to a subset of schemes (MethodSchemes), or fail-open across all engines (unannotated).

`authn.Multi` is the standard decorator over multiple `NamedAuthenticator` instances. It treats ErrNoCredentials as "try the next allowed engine" and treats any other error as fail-fast.

On success the enriched context returned by the engine is passed directly to the handler. On failure an optional `WithAuditOnFailure` auditor emits a CloudEvents event; the dispatcher itself does not write to the legacy auditpb detail holder.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoCredentials = errors.New("authn: no credentials")

ErrNoCredentials is returned by authentication engines when the request does not carry credentials for that engine. It is not an authentication failure by itself: composite dispatchers such as Multi use it to continue to the next allowed engine. Invalid credentials and backend/config failures must return any other non-nil error.

Functions

func AuthTypeFrom added in v0.5.0

func AuthTypeFrom(ctx context.Context) (string, bool)

AuthTypeFrom retrieves the authentication type string previously set via WithAuthType. Returns ("", false) if not present.

func Server

func Server(a Authenticator, opts ...Option) middleware.Middleware

Server returns a Kratos middleware that dispatches authentication to the supplied `Authenticator` (typically a `Multi` decorator).

Per-request behavior:

  1. Resolve operation: `transport.FromServerContext(ctx).Operation()`.
  2. PublicMethods passthrough: if op ∈ `Rules.PublicMethods`, passthrough — do not call the engine.
  3. Build the allowed-schemes set: if op ∈ `Rules.MethodSchemes`, install `allowed = set(rules.MethodSchemes[op])` into ctx. Otherwise install nil (fail-open / unannotated).
  4. Call `a.Authenticate(ctx)`.
  5. Success → use the returned enriched ctx directly, call the handler.
  6. Failure → optionally emit audit event (if WithAuditOnFailure set), then either invoke `WithErrorHandler` (if set) or return `errors.Unauthorized("AUTHN_FAILED", reason)`.

func SubjectFromAny added in v0.5.0

func SubjectFromAny(fns ...func(context.Context) (string, bool)) func(context.Context) (string, bool)

SubjectFromAny composes multiple subject-extraction functions into a single combinator. The first function that returns (subject, true) wins; nil entries are silently skipped.

This allows business code to combine different identity sources (e.g. actor-from-JWT, actor-from-apikey, actor-from-mTLS) into a unified subject resolver without coupling to any specific engine.

func WithAuthType added in v0.5.0

func WithAuthType(ctx context.Context, authType string) context.Context

WithAuthType attaches an authentication type string to ctx. Engines call this on success to communicate the mechanism used upstream.

Types

type Authenticator

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

Authenticator is the interface for authenticating incoming requests.

CONTRACT: this interface intentionally contains ONLY behavior body (`Authenticate`). Engine metadata belongs to the wrapper layer via `authn.Named(scheme, a)` — NOT on the interface itself.

What MUST NOT live on this interface:

  • Engine metadata (e.g. `Method() string`) — supplied by `authn.Named` when wiring `authn.Multi`; framework main package is agnostic to the scheme string.
  • Hooks / callbacks (e.g. `OnSuccess`) — caller responsibility.
  • Injection (logger / tracer) — container responsibility.
  • Infra probes (e.g. `Health`) — separate sibling interface.

This single-method shape prevents interface bloat as new engines (mTLS, API-Key, AK+SK, Passkey, etc.) are added: each engine is described to the dispatcher by `Named` at wiring time, and orchestration is the `Multi` decorator's responsibility.

func Multi added in v0.4.8

func Multi(named ...NamedAuthenticator) Authenticator

Multi composes multiple `NamedAuthenticator` engines into a single `Authenticator`. First-success-wins: engines are tried in injection order (NOT in `allowedSchemes` order — business decides the precedence at wiring time).

If the `allowedSchemes` set installed by `Server` (from `Rules.MethodSchemes`) is non-nil, engines whose scheme is absent from the set are skipped silently. If nil (unannotated method), every engine participates.

Wrapping a single engine via `Multi(Named(...))` is a supported and recommended pattern: it gives the dispatcher the scheme name without requiring a separate `WithMethod` option, and makes future expansion to more engines a one-line change.

type NamedAuthenticator added in v0.4.8

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

NamedAuthenticator is an opaque scheme + Authenticator pair produced by `Named`. Fields are package-private; consumers can only construct via `Named` and consume via `Multi`.

func Named added in v0.4.8

func Named(scheme string, a Authenticator) NamedAuthenticator

Named pairs a scheme string with an `Authenticator` for `Multi`.

The scheme string is opaque to the framework — any value is accepted. Engine sub-packages typically expose a `Scheme` constant (e.g. `jwt.Scheme = "jwt"`) so business code can write `authn.Named(jwt.Scheme, jwt.NewAuthenticator(...))`.

type Option

type Option func(*serverConfig)

Option configures the Server middleware.

func WithAuditOnFailure added in v0.5.0

func WithAuditOnFailure(a audit.Auditor) Option

WithAuditOnFailure installs an Auditor that receives a CloudEvents event on every authentication failure. The event carries:

  • type = "servora.authn.v1.failure"
  • source = the RPC operation from transport ctx
  • severity extension = "WARN"
  • data = error message as text/plain

When no auditor is configured (default), the failure path does not emit.

func WithErrorHandler

func WithErrorHandler(h func(ctx context.Context, err error) error) Option

WithErrorHandler installs a custom error transformer invoked when authentication fails. If the underlying error implements `SchemeAttemptsErr` (i.e. came from `Multi`), the hook can type-assert to retrieve per-scheme attempts.

func WithRulesFuncs added in v0.4.8

func WithRulesFuncs(fns ...func() Rules) Option

WithRulesFuncs registers one or more rule-table generator functions. `protoc-gen-servora-authn` emits one `AuthnRules() Rules` per .proto package; business code passes them as variadic args to merge across modules. Nil entries are skipped (no panic) so business code can pass optional generators conditionally.

Merge semantics:

  • PublicMethods slices are appended in argument order.
  • MethodSchemes entries from later generators overwrite earlier ones. RPC paths are fully qualified service names; collisions are rare in practice and the last-wins rule lets business code intentionally override a downstream module's annotation if needed.

type Rules added in v0.4.8

type Rules struct {
	PublicMethods []string
	MethodSchemes map[string][]string
}

Rules is the aggregate authentication-rules table consumed by `Server`. It is produced by `protoc-gen-servora-authn` per generated package (e.g. `examplev1.AuthnRules()`) and merged across modules by `WithRulesFuncs`.

Two disjoint subsets:

  • PublicMethods — RPC paths annotated `MODE_PUBLIC`; the dispatcher short-circuits before calling the engine.
  • MethodSchemes — RPC paths annotated `MODE_REQUIRED`, mapped to the accepted scheme list (e.g. `["jwt", "apikey"]`); the dispatcher installs an `allowedSchemes` ctx channel so `Multi` can filter.

An RPC path absent from BOTH maps is unannotated; the dispatcher treats it as fail-open (no allowed-set installed; `Multi` tries every engine in injection order).

type SchemeAttempt added in v0.4.8

type SchemeAttempt struct {
	Scheme string
	Reason string
}

SchemeAttempt records one engine's outcome inside a `Multi` dispatch. Both fields are public so `WithErrorHandler` consumers can render per-scheme diagnostics (logging, metrics labels, custom RPC errors).

type SchemeAttemptsErr added in v0.4.8

type SchemeAttemptsErr interface {
	error
	SchemeAttempts() []SchemeAttempt
}

SchemeAttemptsErr is the public interface satisfied by the package-private error type returned from `Multi.Authenticate` when every allowed engine failed. Business code obtains structured access via type assertion:

authn.WithErrorHandler(func(ctx context.Context, err error) error {
    if as, ok := err.(authn.SchemeAttemptsErr); ok {
        for _, a := range as.SchemeAttempts() {
            log.Errorw("authn attempt failed",
                "scheme", a.Scheme, "reason", a.Reason)
        }
    }
    return err
})

`Server` itself uses this interface to render safe structured failure reasons.

Directories

Path Synopsis
Package apikey provides an API-key authentication skeleton for the engine-agnostic authn dispatcher.
Package apikey provides an API-key authentication skeleton for the engine-agnostic authn dispatcher.
Package jwt provides a generic Bearer JWT authentication skeleton for the engine-agnostic authn dispatcher.
Package jwt provides a generic Bearer JWT authentication skeleton for the engine-agnostic authn dispatcher.
Package noop provides a no-op Authenticator that passes through without enrichment.
Package noop provides a no-op Authenticator that passes through without enrichment.

Jump to

Keyboard shortcuts

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