Go verifier for auth9-issued access tokens.
- RS256/ES256 signature verification against the issuer's JWKS (HS*/
nonealways rejected — no algorithm-confusion surface). - Pinned issuer and audience, required
exp,nbfhandling, 30s default clock-skew leeway. - Production JWKS cache: positive/negative TTLs, refresh floor, singleflight stampede control, redirect refusal, response-size cap, RSA/EC key sanity bounds. HTTPS required (plain HTTP only on loopback, opt-in).
- Typed failure reasons:
expired,not_yet_valid,audience_mismatch,issuer_mismatch,bad_signature,unknown_key,internal— every path fails closed. - Claim-provenance readers: distinguish issuer-attested top-level claims from
caller-asserted passthrough under the reserved
callercontainer (seeProvenanceClaims). - Ships the issuer-generated conformance corpus
(
conformance/fixtures.json) and replays every vector through this verifier in its own test suite.
This library answers exactly one question: was this token minted by your auth9 issuer, for your audience, and is it currently valid? Authorization — scopes, roles, tenancy rules, admission policy — deliberately does not live here; keep it in your service.
go get github.com/db9-ai/auth9token-go
import auth9token "github.com/db9-ai/auth9token-go"
cache, err := auth9token.NewJWKSCache(
"https://auth.example.com/.well-known/jwks.json",
5*time.Minute, // positive TTL
30*time.Second, // negative (unknown-kid) TTL
)
if err != nil { /* bad URL, config error */ }
v, err := auth9token.NewVerifier(auth9token.Config{
Keys: cache,
Issuer: "https://auth.example.com", // required, exact match
Audience: "my-service", // required, aud membership
})
if err != nil { /* incomplete config */ }
res, err := auth9token.Verify[auth9token.ProvenanceClaims](ctx, v, token)
if err != nil {
var verr *auth9token.Error
if errors.As(err, &verr) {
// verr.Reason: typed rejection (expired, bad_signature, ...)
}
return
}
// res.Claims: issuer-attested top-level claims.
// res.Claims.Caller() / CallerClaim(): caller-asserted passthrough — never
// readable as attested fact.Design notes worth knowing before deploying:
- Issuer is required. An empty
Config.Issueris a construction error: an unpinned issuer would accept a validly-signed token from a different trust domain sharing the same JWKS. expis required. A token without an expiry is rejected as expired.- JWKS URL is validated at construction —
https, orhttpon loopback only.
conformance/fixtures.json is generated by the auth9 issuer from its real
minting paths and vendored here on release: a JWKS (test key — public half
only) plus accept/reject vectors with canonical rejection reasons. This repo's
tests run every vector through the shipped verifier, so drift between what the
issuer mints and what this library accepts fails in CI.
Consumers with their own verification stack can replay the same bundle: build
a key source from jwks, pin meta.issuer / meta.audience, and assert each
vector.expect verdict.
Apache-2.0. See LICENSE.