auth

package
v1.9.0 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package auth authenticates gateway keys at the HTTP and gRPC edges: KeyAuth, RequireScope, Authenticate and AuthenticateWithTenants. See the Identity & Auth docs page for the request flow.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Authenticate

func Authenticate(ctx context.Context, keys KeyValidator, rawKey string) (context.Context, error)

Authenticate validates rawKey and returns ctx carrying the key's tenant, id and scopes for the pipeline. It checks the key only, not its tenant: use AuthenticateWithTenants at an edge, so a key whose tenant is not active is refused there. Every error message is a fixed string: none carries the key.

func AuthenticateWithTenants

func AuthenticateWithTenants(ctx context.Context, keys KeyValidator, tenants TenantGetter, rawKey string) (context.Context, error)

AuthenticateWithTenants is Authenticate plus a check of the key's tenant. When tenants is not nil, a key whose tenant is not active is refused 403 forbidden ("tenant is suspended", say), a tenant that no longer exists is refused 403 "unknown tenant", and a lookup that fails is 503 unavailable with the cause kept for the log. KeyAuth and the grpcsrv interceptor call it, so suspending a tenant stops every one of its keys, admin keys too. With tenants nil it is exactly Authenticate.

func KeyAuth

func KeyAuth(o KeyAuthOptions) func(http.Handler) http.Handler

KeyAuth authenticates every request with a gateway key. Its refusals happen before the pipeline and are not recorded as usage: they have no tenant to charge. It marks every request it passes, anonymous ones too, so that RequireScope can tell "no key" from "KeyAuth never ran". It panics when o.Keys is nil.

func LogServerError

func LogServerError(ctx context.Context, log Logger, path string, err error)

LogServerError logs err, with the request id, when the client is told nothing about it: an error that is not a refusal (answered as a fixed 500) and a refusal with a status of 500 or above (the 503 whose cause is hidden). A cancel is the client leaving and is not logged. The logged text is the error's own: the auth messages are fixed strings and never carry a key. As a backstop, query values that name a credential (key, api_key, apikey, access_token, token) are redacted from the logged text, because a provider's transport error prints the URL it called.

func RawKey

func RawKey(r *http.Request) string

RawKey returns the key a request presents, from x-api-key or Authorization: Bearer, or "".

func RequestID

func RequestID() func(http.Handler) http.Handler

RequestID gives every request an id of its own and returns it in the X-Request-Id response header. It never takes an id from the client: the header is the gateway's to set. The pipeline keeps an id that is already in the context, so the usage record, the logs and the header all name the same request. Put it ahead of KeyAuth so that a refusal at the edge has one too.

func RequireScope

func RequireScope(scope string, onError func(http.ResponseWriter, *http.Request, error)) func(http.Handler) http.Handler

RequireScope refuses a request unless a key authenticated by KeyAuth holds scope: 401 when no key authenticated it (KeyAuth never ran, or let an anonymous request through), 403 when the key lacks the scope. It fails closed, so a route that needs a scope always needs a key, whatever KeyAuthOptions.Required says. Put it behind KeyAuth.

func WriteError

func WriteError(w http.ResponseWriter, err error)

WriteError writes err as {"error":{"message","type","code"}} with the refusal's status, and Retry-After in whole seconds when the refusal says how long to wait. Only a pipeline.Refusal's own text reaches the client, never a wrapper's: anything else (a provider or store error, which may carry URLs, bodies or DSNs) is answered as a 500 "internal error". A 401 carries WWW-Authenticate: Bearer.

func WriteFailure

func WriteFailure(w http.ResponseWriter, r *http.Request, log Logger, err error)

WriteFailure logs err when it answers as a 5xx, then writes it with WriteError: the refusal's own status and text, or a fixed 500.

Types

type Claims

type Claims struct {
	Subject  string            // user or service ID
	TenantID string            // tenant scope
	KeyID    string            // API key ID (if key-based auth)
	Roles    []string          // roles / permissions
	Metadata map[string]string // arbitrary claims
}

Claims represents the authenticated identity a Provider returns. The gateway does not use it: a request's identity is its tenant, key id and scopes in the pipeline context (pipeline.TenantID, pipeline.KeyID, pipeline.Scopes).

type KeyAuthOptions

type KeyAuthOptions struct {
	Keys KeyValidator
	// Tenants, when set, refuses a key whose tenant is not active (403) or
	// cannot be read (503), at the edge. api and proxy pass gw.Tenants().
	// Without it only the key's own status is checked here, and the
	// pipeline's access stage checks the tenant later, which the admin
	// routes never reach.
	Tenants TenantGetter
	// Required refuses a request without a key. When false, a request
	// without one passes unauthenticated, and a key that is presented is
	// still checked. Any non-empty Authorization header counts as presented,
	// so an unrelated Basic or Bearer credential sent to an open gateway
	// gets 401.
	Required bool
	// OnError writes a refusal. The default is WriteError.
	OnError func(http.ResponseWriter, *http.Request, error)
}

KeyAuthOptions configures KeyAuth.

type KeyValidator

type KeyValidator interface {
	Validate(ctx context.Context, rawKey string) (*key.APIKey, error)
}

KeyValidator checks a raw gateway key. key.Service satisfies it.

type Logger

type Logger interface {
	Error(msg string, args ...any)
}

Logger is the part of the gateway logger the HTTP edges need. nexus.Logger satisfies it.

type NoopProvider deprecated

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

NoopProvider allows all requests (for development / single-tenant).

Deprecated: nothing consults an auth.Provider, so this never allowed or refused anything. For local work without keys, use nexus.WithRequireAPIKey(false), which opens the /v1 routes only.

func NewNoop deprecated

func NewNoop(defaultTenant ...string) *NoopProvider

NewNoop creates a noop auth provider that allows all requests.

Deprecated: see NoopProvider.

func (*NoopProvider) Authenticate

func (n *NoopProvider) Authenticate(_ context.Context) (*Claims, error)

func (*NoopProvider) AuthenticateAPIKey

func (n *NoopProvider) AuthenticateAPIKey(ctx context.Context, _ string) (*Claims, error)

type Provider deprecated

type Provider interface {
	// Authenticate extracts and validates credentials from the request context.
	// Returns Claims on success, error on failure.
	Authenticate(ctx context.Context) (*Claims, error)

	// AuthenticateAPIKey validates a Nexus-issued API key.
	AuthenticateAPIKey(ctx context.Context, apiKey string) (*Claims, error)
}

Provider resolves the identity of an incoming request.

Deprecated: nothing consults a Provider. Gateway keys are checked by KeyAuth (HTTP) and the grpcsrv KeyAuth interceptor, both through AuthenticateWithTenants, and nexus.WithAuth has no effect on them. It stays only so existing code compiles, and goes in the v1 break.

type TenantGetter

type TenantGetter interface {
	Get(ctx context.Context, id string) (*tenant.Tenant, error)
}

TenantGetter reads a tenant by id. tenant.Service satisfies it.

Directories

Path Synopsis
Package authsome provides an adapter that bridges an external Authsome authentication service to the Nexus auth.Provider interface.
Package authsome provides an adapter that bridges an external Authsome authentication service to the Nexus auth.Provider interface.

Jump to

Keyboard shortcuts

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