Documentation
¶
Overview ¶
Package oidcverify verifies tokens KySignOn issues: RS256 JWTs whose signing key is published at the issuer's JWKS endpoint. Five products parsed these with their own code, and at least one read the claims without checking the signature at all. One wrong check of alg, aud, iss, exp or kid accepts a token it should not, indistinguishable from a good one, so the check lives here once, on the standard library alone.
The algorithm is pinned to RS256 because that is what KySignOn signs with. A token whose header says anything else, including "none", is refused before any signature work.
Index ¶
- Constants
- Variables
- type Claims
- type LogoutClaims
- type Verifier
- func (v *Verifier) Middleware(onReject func(r *http.Request, err error)) func(http.Handler) http.Handler
- func (v *Verifier) Verify(ctx context.Context, token string) (Claims, error)
- func (v *Verifier) VerifyLogout(ctx context.Context, token string) (LogoutClaims, error)
- func (v *Verifier) VerifyWithNonce(ctx context.Context, token, nonce string) (Claims, error)
Constants ¶
const MaxLogoutTokenAge = 5 * time.Minute
MaxLogoutTokenAge bounds logout-token freshness even if exp is far in the future. KySignOn issues a fresh token for each attempt with a two-minute expiration.
Variables ¶
var ( ErrMalformed = errors.New("oidcverify: token is not a three-part JWT") ErrTokenType = errors.New("oidcverify: token purpose does not match") ErrAlgorithm = errors.New("oidcverify: token algorithm is not RS256") ErrUnknownKey = errors.New("oidcverify: no JWKS key matches the token's kid") ErrSignature = errors.New("oidcverify: signature does not verify") ErrIssuer = errors.New("oidcverify: issuer does not match") ErrAudience = errors.New("oidcverify: audience does not include this client") ErrExpired = errors.New("oidcverify: token has expired") ErrNotYetValid = errors.New("oidcverify: token is not yet valid") ErrIssuedInFuture = errors.New("oidcverify: token was issued in the future") ErrNoSubject = errors.New("oidcverify: token has no subject") ErrNonce = errors.New("oidcverify: nonce does not match") ErrJWKS = errors.New("oidcverify: JWKS fetch failed") )
var ErrInsecureIssuer = errors.New("oidcverify: issuer and JWKS URL must be https with a host")
ErrInsecureIssuer means the issuer or JWKS URL is not HTTPS. Key discovery over plaintext lets whoever answers the request decide which keys verify tokens.
var ErrLogoutClaims = errors.New("oidcverify: invalid logout claims")
ErrLogoutClaims means a signed token does not meet the KySignOn logout profile.
Functions ¶
This section is empty.
Types ¶
type Claims ¶
type Claims struct {
Issuer string
Subject string
Audience []string
ExpiresAt time.Time
IssuedAt time.Time
NotBefore time.Time
Nonce string
KeyID string
Raw map[string]json.RawMessage
}
Claims are the standard claims every KySignOn token carries, plus the raw set for product-specific ones (role, groups, email).
func ClaimsFromContext ¶
ClaimsFromContext returns the Claims Middleware stored.
type LogoutClaims ¶
type LogoutClaims struct {
Issuer string
Subject string
SessionID string
Audience []string
JWTID string
IssuedAt time.Time
ExpiresAt time.Time
ReplayUntil time.Time // last acceptance boundary, including clock-skew leeway
KeyID string
}
LogoutClaims identifies sessions to end, never an identity to authenticate. With a SessionID, match that issuer/client-scoped session and Subject when present. Without a SessionID, end all sessions for Issuer and Subject at this client. The receiver must atomically record (Issuer, JWTID) with session invalidation and retain it through ReplayUntil, including across restart. Verification is stateless.
type Verifier ¶
type Verifier struct {
Issuer string
Audience string
// AllowMultipleAudiences accepts an aud array that names this client among others.
// Off by default: a token minted for several clients is a token any of them can replay.
AllowMultipleAudiences bool
// JWKSURL defaults to Issuer + "/.well-known/jwks.json".
JWKSURL string
// HTTPClient defaults to a client with a ten-second timeout.
HTTPClient *http.Client
// Now defaults to time.Now.
Now func() time.Time
// Leeway is the clock-skew allowance for exp, nbf and iat.
Leeway time.Duration
// MinRefresh bounds how often an unknown kid may trigger a JWKS fetch. Default 30s.
MinRefresh time.Duration
// MaxAge is how long a fetched key set is trusted before a refresh. Default 1h.
MaxAge time.Duration
// contains filtered or unexported fields
}
Verifier checks tokens for one issuer and one audience. Zero Leeway means one minute.
func (*Verifier) Middleware ¶
func (v *Verifier) Middleware(onReject func(r *http.Request, err error)) func(http.Handler) http.Handler
Middleware reads a bearer token, verifies it, and stores the Claims on the context. Every failure answers 401 with a fixed body; the reason goes only to onReject.
func (*Verifier) Verify ¶
Verify checks an authentication token against the issuer's JWKS and standard claims. Logout and other security-event tokens are refused; use VerifyLogout for logout. An unknown kid triggers at most one rate-limited JWKS refresh.
func (*Verifier) VerifyLogout ¶
VerifyLogout verifies an RS256 logout+jwt with issuer, audience, required iat/exp/jti, a sub or sid, the back-channel event object, and no nonce or token_use claim. It shares Verify's JWKS cache, refresh limits, clock and leeway. Tokens older than MaxLogoutTokenAge plus leeway are refused. It neither records replay IDs nor ends sessions; the receiver owns those durable operations and bounds its HTTP request.
func (*Verifier) VerifyWithNonce ¶
VerifyWithNonce is Verify plus a nonce check, for ID tokens from the authorization-code flow. An empty nonce skips the check; a token carrying a nonce when none is expected is still accepted, since access tokens carry none.