Documentation
¶
Overview ¶
Package authn provides transport-agnostic credential verification primitives for the HTTP and gRPC server transports. It carries no HTTP or gRPC imports, so it is trivially unit-testable and reusable from both transports (and by tools directly).
A Verifier authenticates a credential and returns the verified Identity, or an error. Verifiers MUST NOT leak the reason for failure in a user-facing form — the returned error is for the server log only; the transport adapters map it to a generic wire status (401 / Unauthenticated) and log the detail redacted. Authorization (deciding what a verified principal may do) is a single tool-supplied predicate, AuthorizeFunc — GTB ships no policy engine.
Index ¶
- Variables
- func ContextWithIdentity(ctx context.Context, id *Identity) context.Context
- func ContextWithRequestMetadata(ctx context.Context, m RequestMetadata) context.Context
- type AuthorizeFunc
- type CertVerifier
- type Identity
- type JWTConfig
- type JWTOption
- type KeyEntry
- type MTLSOption
- type RequestMetadata
- type Verifier
Constants ¶
This section is empty.
Variables ¶
var ErrUnauthenticated = errors.New("authn: unauthenticated")
ErrUnauthenticated is the sentinel a Verifier wraps when a credential fails verification. Callers test for it with errors.Is, but treat any non-nil verify error the same way: a generic 401 / Unauthenticated on the wire, the wrapped detail logged server-side (redacted). It never crosses the wire.
Functions ¶
func ContextWithIdentity ¶
ContextWithIdentity returns a child context carrying the verified Identity. Auth adapters call this on success so downstream handlers can read it.
func ContextWithRequestMetadata ¶
func ContextWithRequestMetadata(ctx context.Context, m RequestMetadata) context.Context
ContextWithRequestMetadata returns a child context carrying request metadata for AuthorizeFunc. Auth adapters call this before running authorization.
Types ¶
type AuthorizeFunc ¶
AuthorizeFunc decides whether an authenticated Identity may proceed. It runs AFTER successful verification; returning false yields 403 / PermissionDenied.
This is the ENTIRE authorization surface GTB ships — there is no built-in RBAC engine and no policy DSL. It is deliberately shaped as a policy-model hole: it receives the resolved Identity and a context that carries the request metadata the adapter injected (see RequestMetadataFromContext), so a tool can implement arbitrary external authorization — evaluate a role map, call out to OPA, whatever — without GTB shipping the engine. Keep the predicate fast and pure; it runs on every authenticated request.
func RequireClaim ¶
func RequireClaim(name string, value any) AuthorizeFunc
RequireClaim returns an AuthorizeFunc that admits an Identity only if its verified claim named name deep-equals value. (DeepEqual avoids a panic on a non-comparable claim value.)
func RequireScopes ¶
func RequireScopes(scopes ...string) AuthorizeFunc
RequireScopes returns an AuthorizeFunc that admits an Identity only if it carries all of the named scopes. With no scopes it admits any authenticated identity.
type CertVerifier ¶
type CertVerifier interface {
VerifyCert(ctx context.Context, verifiedChains [][]*x509.Certificate) (*Identity, error)
}
CertVerifier authenticates a verified client-certificate chain from a completed mTLS handshake and returns the Identity, or an error. It is separate from Verifier because a client certificate is a transport property, not a bearer credential string.
The cryptographic verification (chain validation against the configured client CA pool) is the TLS stack's job — the server must be configured for RequireAndVerifyClientCert with a ClientCAs pool. A CertVerifier receives the already-verified chains (as in tls.ConnectionState.VerifiedChains) and only derives identity from them.
func NewMTLSVerifier ¶
func NewMTLSVerifier(opts ...MTLSOption) CertVerifier
NewMTLSVerifier returns a CertVerifier that derives the Subject from the leaf client certificate.
type Identity ¶
type Identity struct {
// Subject is the principal identifier: the "sub" claim for JWT, the
// configured label for an API key, or the certificate subject for mTLS.
Subject string
// Method records which verifier authenticated the request: "apikey", "jwt",
// or "mtls".
Method string
// Claims holds verified JWT claims (nil for API-key and mTLS auth).
Claims map[string]any
// Scopes is the parsed "scope"/"scp" claim when present, for convenience.
Scopes []string
}
Identity is the verified outcome of a successful authentication. It carries the minimum a downstream handler needs to make authorization decisions.
func IdentityFromContext ¶
IdentityFromContext returns the verified Identity stored by an auth adapter, and whether one was present. The HTTP and gRPC adapters share this key, so a handler reads identity the same way regardless of transport.
type JWTConfig ¶
type JWTConfig struct {
// Issuer is the required "iss". Verification fails if it does not match.
Issuer string
// Audiences are the acceptable "aud" values (any-of). Empty disables the aud
// check (logged-worthy; not recommended).
Audiences []string
// JWKSURL is the JSON Web Key Set endpoint (HTTPS). Signing keys are fetched
// and cached from here. Resolved automatically by WithOIDCDiscovery.
JWKSURL string
// Leeway tolerates small clock skew on exp/nbf/iat. Default 60s.
Leeway time.Duration
// RefreshInterval bounds how often the JWKS is refetched. Default 15m.
RefreshInterval time.Duration
// AllowedAlgorithms restricts accepted "alg" values. Default: RS/ES 256/384/512.
AllowedAlgorithms []string
// HTTPClient fetches the JWKS (and the OIDC document). Defaults to a client
// with a sane timeout. Must reach an HTTPS endpoint.
HTTPClient *http.Client
}
JWTConfig configures the JWT/OIDC bearer-token verifier.
type JWTOption ¶
type JWTOption func(*jwtSettings)
JWTOption configures NewJWTVerifier beyond the base JWTConfig.
func WithOIDCDiscovery ¶
WithOIDCDiscovery resolves JWKSURL (and validates Issuer) from the provider's /.well-known/openid-configuration document at construction time. This is the ONLY OIDC affordance: discovery of the JWKS endpoint — no login flow, no token endpoint use. The discovery URL must be HTTPS.
type KeyEntry ¶
type KeyEntry struct {
Key string // the shared secret
Subject string // identity label, e.g. "ci-runner", "admin"
}
KeyEntry pairs a valid API key with the Subject label recorded on success.
type MTLSOption ¶
type MTLSOption func(*mtlsVerifier)
MTLSOption configures the mTLS verifier.
func WithCertSubject ¶
func WithCertSubject(fn func(*x509.Certificate) string) MTLSOption
WithCertSubject overrides how the Subject is derived from the leaf certificate. The default uses the Common Name, then the first DNS SAN, then the first URI SAN.
type RequestMetadata ¶
type RequestMetadata struct {
// Method is the HTTP method (GET, POST, …) or "grpc" for an RPC.
Method string
// Path is the HTTP request path or the gRPC full method name.
Path string
}
RequestMetadata carries the minimal transport facts an AuthorizeFunc may want for a policy decision — the route being accessed. The auth adapters populate it before running authorization, so a policy can be route-aware without GTB shipping a routing model.
func RequestMetadataFromContext ¶
func RequestMetadataFromContext(ctx context.Context) (RequestMetadata, bool)
RequestMetadataFromContext returns the request metadata an adapter injected, and whether any was present. Use it from an AuthorizeFunc to make a route-aware authorization decision.
type Verifier ¶
Verifier authenticates a single credential string (the raw bearer token or API key, already extracted from the transport) and returns the verified Identity, or an error. Implementations MUST NOT encode the reason for failure in a user-facing way — callers redact the error and map it to a generic wire status.
mTLS client-certificate authentication does not implement this interface: a certificate is a transport property, not a credential string. See CertVerifier.
func NewAPIKeyVerifier ¶
NewAPIKeyVerifier returns a Verifier that accepts any of the given keys.
Comparison is constant-time. Because comparing variable-length input against a secret with subtle.ConstantTimeCompare is itself length-leaking (it short-circuits on unequal lengths), the verifier compares a fixed-width SHA-256 digest of the presented credential against the pre-computed digest of each configured key, iterating ALL entries with no early return — so neither match/no-match, key length, nor which key matched is timing-distinguishable.
An empty key set is a construction error (fail-closed: never accept "any key"), as is an entry with an empty key.
func NewJWTVerifier ¶
NewJWTVerifier returns a Verifier for JWT bearer tokens, fetching signing keys from the configured (or OIDC-discovered) JWKS endpoint. It performs an initial JWKS fetch so a misconfiguration fails fast.