Choose & configure a verifier¶
authn ships three verifiers. Pick by the credential your clients present:
| Credential | Constructor | Interface |
|---|---|---|
| Shared API key / token | NewAPIKeyVerifier |
Verifier |
| JWT (OIDC / OAuth2 bearer) | NewJWTVerifier |
Verifier |
| Client certificate (mTLS) | NewMTLSVerifier |
CertVerifier |
API-key and JWT verifiers satisfy Verifier
(Verify(ctx, credential string)). mTLS uses
CertVerifier
because a certificate is a transport property, not a credential string.
API keys¶
NewAPIKeyVerifier
takes a set of {Key, Subject} entries and matches presented keys in constant time:
verifier, err := authn.NewAPIKeyVerifier(
authn.KeyEntry{Key: "s3cr3t", Subject: "ci-bot"},
authn.KeyEntry{Key: "adm1n", Subject: "admin"},
)
The resulting Identity.Method is "apikey" and Subject is the matched entry's
label. Construction fails if two entries share a key or a key is empty.
JWT / OIDC¶
NewJWTVerifier
validates a signed JWT: signature (against a cached JWKS), exp/nbf (with Leeway,
default 60s), iss, and aud. The verified Claims and parsed Scopes land on the
Identity.
Point it at a JWKS endpoint directly:
verifier, err := authn.NewJWTVerifier(ctx, authn.JWTConfig{
Issuer: "https://issuer.example.com",
Audiences: []string{"my-api"},
JWKSURL: "https://issuer.example.com/.well-known/jwks.json",
})
…or let OIDC discovery resolve the JWKS URL from the issuer's
/.well-known/openid-configuration:
verifier, err := authn.NewJWTVerifier(ctx,
authn.JWTConfig{Issuer: "https://issuer.example.com", Audiences: []string{"my-api"}},
authn.WithOIDCDiscovery("https://issuer.example.com"),
)
Signing keys are refetched no more often than RefreshInterval (default 15m).
AllowedAlgorithms defaults to the asymmetric RS/ES 256/384/512 set — the verifier
does not accept none, and pinning algorithms defends against algorithm-confusion
attacks. The JWKS endpoint must be HTTPS.
mTLS¶
NewMTLSVerifier
derives an identity from the client certificate chain the TLS stack already verified.
Because the credential is the connection, it implements CertVerifier —
VerifyCert(ctx, verifiedChains) — which you call from your transport with
tls.ConnectionState().VerifiedChains:
By default the Identity.Subject is the leaf certificate's subject. Override how the
subject is derived — for example to use a SAN URI or a specific RDN — with
WithCertSubject:
cv := authn.NewMTLSVerifier(
authn.WithCertSubject(func(c *x509.Certificate) string {
if len(c.URIs) > 0 {
return c.URIs[0].String() // SPIFFE-style identity
}
return c.Subject.CommonName
}),
)
VerifyCert rejects an empty chain, so a connection without a presented client
certificate fails closed.
Combining verifiers¶
The verifiers are independent values. To accept more than one credential type, run the
applicable verifier for the credential the transport extracted (a bearer token → JWT
or API key; a client cert → mTLS) and treat any success as authenticated. Each returns
a uniform Identity, so the rest of your stack — and your
authorization check — does not care which one succeeded.