Skip to content

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 CertVerifierVerifyCert(ctx, verifiedChains) — which you call from your transport with tls.ConnectionState().VerifiedChains:

cv := authn.NewMTLSVerifier()

id, err := cv.VerifyCert(ctx, connState.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.