Documentation
¶
Overview ¶
Package token implements shared JWT access token (RFC 9068) and ID token (OIDC Core) issuance and validation logic that sits below the public TokenSet/TokenResult types.
issue.go is used by server to mint tokens, including DPoP sender constraint binding via a cnf.jkt claim; validate.go is used by client (validating an ID token it received from the token endpoint) and by resource (validating a presented JWT access token's signature, issuer, audience and lifetime). AccessToken.Validate exposes a verified token's cnf.jkt claim (ValidatedAccessToken.JKT) rather than checking it against an expected value itself — DPoP sender-constraint binding, ordinary expiry and revocation are resource.Verify()'s own job, enforced once, uniformly, for every access-token format resource.AccessTokenResolver supports, not just JWT (see that interface's doc comment in resource/accesstoken.go). Each token kind's Parse and Validate stay separate types from its Issue, even though they interpret the same claim set, because a server issuing a token and a verifier checking one make different trust assumptions about where the token came from.
Refresh tokens are not covered here: this module treats them as opaque, storage-backed credentials issued and redeemed by storage.GrantStore, not as JWTs with claims to parse.
As with internal/requestobject and internal/jarm, only the claims each token kind's governing spec defines are parsed into typed fields; anything else — most notably a granted authorization_details (RFC 9396) reflected into an access token — is left as raw JSON in Parameters.
Index ¶
- Variables
- func IssueAccessToken(p AccessTokenParams) (token string, jti string, err error)
- func IssueIDToken(p IDTokenParams) (string, error)
- type AccessToken
- type AccessTokenClaims
- type AccessTokenParams
- type AccessTokenValidatePolicy
- type Confirmation
- type IDToken
- type IDTokenClaims
- type IDTokenParams
- type IDTokenValidatePolicy
- type ValidatedAccessToken
- type ValidatedIDToken
Constants ¶
This section is empty.
Variables ¶
var ( // ErrWrongType indicates an access token header's "typ" was not // "at+jwt" (RFC 9068 §2.1). ErrWrongType = errors.New("token: header typ is not at+jwt") // ErrMalformedClaims indicates a payload was not a JSON object, was // missing a required top-level claim, or had a claim of the wrong // shape (including a "cnf" claim that was not a well-formed // DPoP-thumbprint confirmation). ErrMalformedClaims = errors.New("token: malformed claims") // ErrIssuerMismatch indicates a token's iss claim did not equal the // issuer the caller expected. ErrIssuerMismatch = errors.New("token: iss does not match expected issuer") // ErrAudienceMismatch indicates a token's aud claim did not contain // the audience the caller expected, or — for an ID token — named an // additional audience the caller's IDTokenValidatePolicy. // TrustedAudiences doesn't list (OIDC Core §3.1.3.7 step 3). ErrAudienceMismatch = errors.New("token: aud does not match expected audience") // ErrExpired indicates a token's exp claim is not after the // verification time. ErrExpired = errors.New("token: token has expired") // ErrLifetimeExceeded indicates a token's exp claim is further in // the future than the configured maximum lifetime allows. ErrLifetimeExceeded = errors.New("token: exp exceeds maximum allowed lifetime") // ErrNonceMismatch indicates an ID token's nonce claim did not match // the nonce the caller's authorization request carried. ErrNonceMismatch = errors.New("token: nonce does not match expected value") // ErrMissingAuthorizedParty indicates an ID token's aud claim named // more than one audience but carried no azp claim (OIDC Core // §3.1.3.7 step 9) — needed to disambiguate which of those // audiences the token was actually authorized for. ErrMissingAuthorizedParty = errors.New("token: aud has multiple audiences but azp is missing") // ErrAuthorizedPartyMismatch indicates an ID token's azp claim did // not equal the caller's own client ID (OIDC Core §3.1.3.7 step 10). ErrAuthorizedPartyMismatch = errors.New("token: azp does not match expected audience") // ErrIssuedAtTooOld indicates an ID token's iat claim is further in // the past than the configured maximum lifetime allows — OIDC Core // §3.1.3.7 step 10: "iat... can be used to reject tokens that were // issued too far away from the current time." Mirrors // ErrLifetimeExceeded's own bound on exp, applied to the opposite // direction around Now. ErrIssuedAtTooOld = errors.New("token: iat exceeds maximum allowed age") )
Functions ¶
func IssueAccessToken ¶
func IssueAccessToken(p AccessTokenParams) (token string, jti string, err error)
IssueAccessToken builds and signs a JWT access token for p, returning the compact JWT and the "jti" claim embedded in it — callers that need to later revoke this specific token (e.g. on detected authorization-code reuse, RFC 6749 §4.1.2) need the jti; previously generated internally and discarded.
func IssueIDToken ¶
func IssueIDToken(p IDTokenParams) (string, error)
IssueIDToken builds and signs an ID token for p.
Types ¶
type AccessToken ¶
type AccessToken struct {
// contains filtered or unexported fields
}
AccessToken is a parsed, but not yet signature-verified, JWT access token. KeyID, Algorithm and ClaimedIssuer are available before Validate succeeds so a caller can look up which key to verify against — that is a safe use of unverified data, since it only selects what to check against, not what to trust. Nothing from AccessToken, including its scope or confirmation claim, should influence an authorization decision until Validate returns a ValidatedAccessToken.
func ParseAccessToken ¶
func ParseAccessToken(tok string) (AccessToken, error)
ParseAccessToken parses a JWT access token without verifying its signature.
func (AccessToken) Algorithm ¶
func (t AccessToken) Algorithm() fapi.SignatureAlgorithm
Algorithm returns the algorithm the token header claims to use. Untrusted until Validate succeeds — callers must still supply the algorithm they expect via AccessTokenValidatePolicy rather than trusting this value, exactly as jose.Compact.Verify requires.
func (AccessToken) ClaimedIssuer ¶
func (t AccessToken) ClaimedIssuer() string
ClaimedIssuer returns the token's unverified "iss" claim, for use as a key-lookup hint only.
func (AccessToken) KeyID ¶
func (t AccessToken) KeyID() string
KeyID returns the token header's "kid", or "" if absent. Untrusted until Validate succeeds; use only to select which key to verify against.
func (AccessToken) Validate ¶
func (t AccessToken) Validate(pub crypto.PublicKey, policy AccessTokenValidatePolicy) (ValidatedAccessToken, error)
Validate checks t's signature against pub and its claims against policy.
type AccessTokenClaims ¶
type AccessTokenClaims struct {
Issuer string
Subject string
Audience []string
ClientID string
Scope string // space-delimited; "" if absent
ExpiresAt time.Time
IssuedAt time.Time
JTI string
Confirmation *Confirmation // nil if the token is not sender-constrained
Parameters map[string]json.RawMessage
}
AccessTokenClaims is a parsed JWT access token payload (RFC 9068). Audience is a slice because RFC 9068 §3 does not narrow RFC 7519 §4.1.3's general "aud" definition, which permits either a single string or an array — unlike internal/clientassertion's own Audience, which stays a single string because a client assertion is always addressed to exactly one token endpoint, never several audiences at once. Everything beyond the claims RFC 9068 defines — most importantly a granted authorization_details (RFC 9396) — is left in Parameters as raw JSON.
type AccessTokenParams ¶
type AccessTokenParams struct {
Signer crypto.Signer
Algorithm fapi.SignatureAlgorithm
KeyID string
Issuer string
Subject string
Audience string
ClientID string
Scope string // "" to omit
// Confirmation binds the token to a DPoP key or an mTLS client
// certificate by thumbprint (exactly one of Confirmation.JKT/X5TS256
// set, never both). Leave nil to issue a bearer (non-sender-constrained)
// token — whether that's acceptable is a policy decision made above
// this package.
Confirmation *Confirmation
Now time.Time
Lifetime time.Duration
// Random is the source of randomness for the token's "jti". If nil,
// crypto/rand.Reader is used.
Random io.Reader
// Parameters are additional top-level claims to embed — most
// notably a granted authorization_details (RFC 9396) — each already
// encoded as JSON. Parameters must not use the reserved claim names
// this package manages itself.
Parameters map[string]json.RawMessage
}
AccessTokenParams describes one access token to issue.
type AccessTokenValidatePolicy ¶
type AccessTokenValidatePolicy struct {
// ExpectedIssuer is the authorization server the caller expects this
// token to have come from. The token's iss claim must equal it
// exactly.
ExpectedIssuer string
// ExpectedAudience is the resource the caller expects this token to
// be scoped to. The token's aud claim must equal it exactly.
ExpectedAudience string
// Algorithm is the algorithm this authorization server is
// registered (or discovered) to sign access tokens with. The token
// header's algorithm must equal it exactly — this is what prevents
// algorithm-confusion attacks, so it must come from the server's
// metadata, never from the token itself.
Algorithm fapi.SignatureAlgorithm
Now time.Time
MaxLifetime time.Duration
}
AccessTokenValidatePolicy is the set of checks Validate enforces against an AccessToken.
type Confirmation ¶
Confirmation is the RFC 7800 "cnf" claim used to record a sender constraint on an access token — exactly one of JKT (DPoP key thumbprint, RFC 9449 §6.1) or X5TS256 (mTLS certificate thumbprint, RFC 8705 §3.1) is ever set on a given token, never both: a token is bound exactly one way.
type IDToken ¶
type IDToken struct {
// contains filtered or unexported fields
}
IDToken is a parsed, but not yet signature-verified, ID token. As with AccessToken, KeyID/Algorithm/ClaimedIssuer are safe to use as lookup hints before Validate succeeds, but nothing else should be trusted until then.
func ParseIDToken ¶
ParseIDToken parses an ID token without verifying its signature, rejecting one longer than jose.DefaultMaxCompactBytes.
func ParseIDTokenMax ¶ added in v0.14.0
ParseIDTokenMax is ParseIDToken with an explicit size ceiling, in bytes, instead of jose.DefaultMaxCompactBytes — for a caller whose issuer may legitimately return an ID token shaped by however many scopes/claims it granted, rather than a fixed handful.
func (IDToken) Algorithm ¶
func (t IDToken) Algorithm() fapi.SignatureAlgorithm
Algorithm returns the algorithm the token header claims to use. Untrusted until Validate succeeds.
func (IDToken) ClaimedIssuer ¶
ClaimedIssuer returns the token's unverified "iss" claim, for use as a key-lookup hint only.
func (IDToken) KeyID ¶
KeyID returns the token header's "kid", or "" if absent. Untrusted until Validate succeeds; use only to select which key to verify against.
func (IDToken) Validate ¶
func (t IDToken) Validate(pub crypto.PublicKey, policy IDTokenValidatePolicy) (ValidatedIDToken, error)
Validate checks t's signature against pub and its claims against policy.
type IDTokenClaims ¶
type IDTokenClaims struct {
Issuer string
Subject string
Audience []string
ExpiresAt time.Time
IssuedAt time.Time
Nonce string // "" if absent
AuthTime time.Time // zero if absent
ACR string // "" if absent
AMR []string // nil if absent
AZP string // "" if absent
Parameters map[string]json.RawMessage
}
IDTokenClaims is a parsed ID token payload (OIDC Core §2).
Audience is a slice because OIDC Core §2 explicitly documents "aud" as possibly multi-valued for an ID token ("In the general case, the aud value is an array of case sensitive strings" — a single string is just the one-element case) — unlike internal/clientassertion's own Audience, which stays a single string because a client assertion is always addressed to exactly one token endpoint, never several audiences at once. §3.1.3.7 step 9 additionally says a client "SHOULD verify that an azp Claim is present" when there's more than one audience, and step 10 that it "SHOULD verify" azp equals the client's own ID when present — IDTokenValidatePolicy.Validate enforces both.
Everything beyond the claims this struct names is left in Parameters as raw JSON.
type IDTokenParams ¶
type IDTokenParams struct {
Signer crypto.Signer
Algorithm fapi.SignatureAlgorithm
KeyID string
Issuer string
Subject string
Audience string
Nonce string // "" to omit
AuthTime time.Time // zero to omit
ACR string // "" to omit
AMR []string // nil to omit
Now time.Time
Lifetime time.Duration
// Parameters are additional top-level claims to embed, each already
// encoded as JSON. Parameters must not use the reserved claim names
// this package manages itself.
Parameters map[string]json.RawMessage
}
IDTokenParams describes one ID token to issue.
type IDTokenValidatePolicy ¶
type IDTokenValidatePolicy struct {
// ExpectedIssuer is the authorization server the caller expects this
// token to have come from. The token's iss claim must equal it
// exactly.
ExpectedIssuer string
// ExpectedAudience is the caller's own client ID. The token's aud
// claim — a single string or, per OIDC Core §2, an array — must
// contain it.
ExpectedAudience string
// TrustedAudiences lists any other party the caller trusts to also
// be named alongside ExpectedAudience in a multi-valued aud. OIDC
// Core §3.1.3.7 step 3 requires rejecting an ID token "if it
// contains additional audiences not trusted by the Client" — by
// default (nil/empty) this package trusts none, so every element of
// aud besides ExpectedAudience causes rejection, preserving the
// exact-match behavior this package has always had. Set only to
// entries the caller has an actual, specific reason to trust.
TrustedAudiences []string
// Algorithm is the algorithm this authorization server is
// registered (or discovered) to sign ID tokens with. The token
// header's algorithm must equal it exactly.
Algorithm fapi.SignatureAlgorithm
// ExpectedNonce, if non-empty, requires the token's nonce claim to
// equal it exactly — this is what binds the ID token back to the
// specific authorization request that requested it. Leave empty
// only when the authorization request itself carried no nonce.
ExpectedNonce string
Now time.Time
MaxLifetime time.Duration
MaxClockSkew time.Duration
}
IDTokenValidatePolicy is the set of checks Validate enforces against an IDToken.
type ValidatedAccessToken ¶
type ValidatedAccessToken struct {
Subject string
ClientID string
Scope string
Parameters map[string]json.RawMessage
ExpiresAt time.Time
// JTI is the token's "jti" claim, now trusted — the signature has
// been verified by this point, unlike AccessToken.KeyID()/
// ClaimedIssuer(), which are documented as pre-verification lookup
// hints only. A caller can use this to check token-specific
// revocation (RFC 6750 §3.1's invalid_token case).
JTI string
// JKT is the token's "cnf.jkt" claim, now trusted, or "" if the
// token carried no confirmation claim at all (or was bound via
// X5TS256 instead — the two are mutually exclusive, see
// Confirmation's own doc comment). This package no longer checks it
// against an expected value itself (see this struct's — and
// AccessTokenValidatePolicy's — history: that check moved to the
// resource package's Verify(), which enforces sender-constraint
// binding once, uniformly, regardless of access-token format).
// Callers that need sender-constraint enforcement must compare this
// themselves.
JKT string
// X5TS256 is the token's "cnf.x5t#S256" claim (RFC 8705 §3.1), now
// trusted, or "" if the token was bound via JKT instead (or not
// bound at all). Mirrors JKT's own contract exactly, for mTLS
// binding instead of DPoP.
X5TS256 string
}
ValidatedAccessToken is what remains once an access token has been validated.
type ValidatedIDToken ¶
type ValidatedIDToken struct {
Subject string
AuthTime time.Time // zero if the token carried no auth_time
ACR string
AMR []string
Parameters map[string]json.RawMessage
ExpiresAt time.Time
// IssuedAt is the token's "iat" — required to be present and
// well-formed for parsing to succeed at all, and bounded by
// MaxLifetime the same way ExpiresAt is (see Validate's own iat
// check). Exposed for a caller's own telemetry or cross-checks
// beyond that one bound.
IssuedAt time.Time
}
ValidatedIDToken is what remains once an ID token has been validated. AuthTime, ACR and AMR are exposed for the caller to apply its own freshness/assurance policy (e.g. a requested max_age or acr_values) — this package only checks what it can check generically.