auth

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2026 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package auth defines the contracts for authenticating a caller from a bearer credential.

The Authenticator interface abstracts token verification against an identity provider (e.g. Zitadel via OIDC). This package is dependency-free: it declares the port only, and imports nothing beyond the standard library's context and errors packages. Concrete adapters (e.g. the Zitadel-backed implementation in auth/zitadel) live in subpackages so that a consumer importing only this port does not pull in an SDK it does not need.

Deliberately excluded: org_id-based multi-tenancy. The systems this package was extracted from carried a Principal.OrgID mirrored from a Zitadel claim, intended for Cerbos derived-role checks — but the owner's Zitadel instance has exactly one organization, so no such comparison could ever discriminate between users, and org_id never scoped a single query or migration in either source system. The real separation between systems is OIDC audience validation, which an Authenticator implementation already performs.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnauthenticated indicates the request carries no valid credentials:
	// missing, malformed, or expired token. Maps to HTTP 401.
	ErrUnauthenticated = errors.New("auth: unauthenticated")

	// ErrForbidden indicates the request carries valid credentials that still
	// fail a requirement the Authenticator itself enforces (e.g. a role
	// required at token-verification time, distinct from the resource-level
	// authorization performed by authz.Checker). Maps to HTTP 403.
	ErrForbidden = errors.New("auth: forbidden")

	// ErrServiceUnavailable indicates the identity provider could not be
	// reached or is failing (5xx), as opposed to the credentials being
	// invalid. Maps to HTTP 503, never 403 or 500: a provider outage reported
	// as 403 tells the client "you lack permission" and tells monitoring
	// "permissions bug" instead of "infrastructure incident", and unlike 403,
	// 503 is retryable. See httpx/middleware.Authenticate for the mapping.
	ErrServiceUnavailable = errors.New("auth: identity provider unavailable")
)

Functions

func WithPrincipal

func WithPrincipal(ctx context.Context, p *Principal) context.Context

WithPrincipal returns a copy of ctx carrying p as the authenticated principal.

Types

type Authenticator

type Authenticator interface {
	Authenticate(ctx context.Context, token string) (*Principal, error)
}

Authenticator verifies a bearer token and extracts its Principal.

It takes the raw token string, not an *http.Request. auth is the only port package in this module that would otherwise carry a dependency: authz imports only context, and storage and notification import nothing beyond the standard library either. A *http.Request parameter here existed solely so Authenticator could mention the type, but Go dependency graphs are per-package, not per-declaration — splitting Authenticator into its own file in this same package would not have helped. Every consumer that imports auth just to read a Principal, such as audit, inherited net/http transitively for no reason connected to what it actually does.

A prior version of this doc defended *http.Request by arguing that a future adapter might need to read a cookie or a different header instead of "Authorization", and that a request parameter kept that choice open. That argument inverts once the port takes a token string: extracting the credential from wherever the deployment puts it is a transport concern, and it now lives entirely in httpx/middleware — the only place that has a live *http.Request in the first place. Moving to a cookie, or trying two header names, changes httpx/middleware only; this port's signature never moves for that reason. What a *http.Request parameter actually cost: every caller of Authenticate that is not inside an HTTP handler — a job running under a service identity, a CLI, a queue consumer in the project's worker binary — had to fabricate a fake *http.Request just to ask "who is this token for". A token string has no such caller.

Implementations MUST return one of the sentinel errors below (optionally wrapped) on failure, so httpx/middleware can map it to the correct HTTP status without importing the concrete provider SDK.

type Principal

type Principal struct {
	UserID   string
	Username string
	Roles    []string
}

Principal is the authenticated caller extracted from a validated request.

func FromContext

func FromContext(ctx context.Context) *Principal

FromContext returns the Principal stored in ctx by WithPrincipal, or nil if the request is unauthenticated (no Authenticate middleware ran, or it failed and returned before storing anything).

func (*Principal) HasRole

func (p *Principal) HasRole(role string) bool

HasRole reports whether the principal has been granted the given role. Safe to call on a nil Principal (returns false).

Directories

Path Synopsis
Package zitadel adapts github.com/zitadel/zitadel-go/v3's OIDC authorizer to the auth.Authenticator port.
Package zitadel adapts github.com/zitadel/zitadel-go/v3's OIDC authorizer to the auth.Authenticator port.

Jump to

Keyboard shortcuts

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