Documentation
¶
Overview ¶
Package clientassertion implements private_key_jwt-style client authentication: assertion construction and verification.
create.go is used by client when authenticating to the PAR and token endpoints; verify.go is used by server when authenticating an inbound request. As with internal/requestobject, the two directions are kept as separate types so signing and verification policy can evolve independently.
Index ¶
Constants ¶
const AssertionType = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
AssertionType is the required client_assertion_type value (RFC 7523 §2.2) for a JWT bearer client assertion. Callers should check an inbound client_assertion_type form parameter against this constant before attempting to parse client_assertion as an assertion at all.
Variables ¶
var ( // ErrMalformedClaims indicates the assertion payload was missing a // required claim (iss, sub, aud, jti or exp), had an aud claim that // was not a single string, or contained a claim this package does // not recognize. ErrMalformedClaims = errors.New("clientassertion: malformed claims") // ErrIssuerSubjectMismatch indicates the assertion's iss and/or sub // claim did not equal the client ID the caller expected to // authenticate. ErrIssuerSubjectMismatch = errors.New("clientassertion: iss/sub does not match expected client ID") // ErrAudienceMismatch indicates the assertion's aud claim did not // equal the audience the caller expected (typically its own token // or PAR endpoint URL). ErrAudienceMismatch = errors.New("clientassertion: aud does not match expected audience") // ErrExpired indicates the assertion's exp claim is not after the // verification time. ErrExpired = errors.New("clientassertion: assertion has expired") // ErrNotYetValid indicates the assertion's nbf claim is in the // future beyond the configured clock-skew tolerance. ErrNotYetValid = errors.New("clientassertion: assertion is not yet valid") // ErrLifetimeExceeded indicates the assertion's exp claim is further // in the future than the configured maximum lifetime allows. ErrLifetimeExceeded = errors.New("clientassertion: exp exceeds maximum allowed lifetime") )
Functions ¶
func CreateAssertion ¶
func CreateAssertion(req AssertionRequest) (string, error)
CreateAssertion builds and signs a client assertion JWT for req.
Types ¶
type Assertion ¶
type Assertion struct {
// contains filtered or unexported fields
}
Assertion is a parsed, but not yet signature-verified, client assertion. KeyID, Algorithm, ClaimedIssuer and ClaimedSubject are available before Verify succeeds so a caller can look up which registered client and 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 Assertion should influence an authorization decision until Verify returns a VerifiedAssertion.
func (Assertion) Algorithm ¶
func (a Assertion) Algorithm() fapi.SignatureAlgorithm
Algorithm returns the algorithm the assertion header claims to use. Untrusted until Verify succeeds — callers must still supply the algorithm they expect via VerifyPolicy rather than trusting this value, exactly as jose.Compact.Verify requires.
func (Assertion) ClaimedIssuer ¶
ClaimedIssuer returns the assertion's unverified "iss" claim, for use as a client-lookup key only.
func (Assertion) ClaimedSubject ¶
ClaimedSubject returns the assertion's unverified "sub" claim, for use as a client-lookup key only.
func (Assertion) KeyID ¶
KeyID returns the assertion header's "kid", or "" if absent. Untrusted until Verify succeeds; use only to select which key to verify against.
func (Assertion) Verify ¶
func (a Assertion) Verify(ctx context.Context, pub crypto.PublicKey, policy VerifyPolicy) (VerifiedAssertion, error)
Verify checks a's signature against pub and its claims against policy.
type AssertionRequest ¶
type AssertionRequest struct {
// Signer produces the assertion's signature.
Signer crypto.Signer
// Algorithm the assertion is signed with. Signer's key must match
// it.
Algorithm fapi.SignatureAlgorithm
// KeyID, if non-empty, is recorded in the assertion's "kid" header
// so the verifier can select the right key from this client's
// registered JWKS without trial and error.
KeyID string
// ClientID is used as both the "iss" and "sub" claims, per RFC 7523
// §3.
ClientID string
// Audience is the "aud" claim — the authorization server's token or
// PAR endpoint URL that this assertion is scoped to.
Audience string
// Now is the assertion's issuance time.
Now time.Time
// Lifetime bounds how long the assertion is valid for (exp = Now +
// Lifetime). Callers should keep this short — a client assertion is
// a bearer credential for as long as it remains unexpired and
// unused.
Lifetime time.Duration
// Random is the source of randomness for the assertion's "jti". If
// nil, crypto/rand.Reader is used.
Random io.Reader
}
AssertionRequest describes one client assertion to create.
type ReplayChecker ¶
type ReplayChecker interface {
UseOnce(ctx context.Context, jti string, expiresAt time.Time) error
}
ReplayChecker records that a client assertion's "jti" has been used, failing if it has been seen before. As with dpop.ReplayChecker, implementations are expected to key storage by a namespaced digest of jti, not the raw value — that adaptation is the caller's responsibility so this package stays decoupled from a specific storage contract.
type VerifiedAssertion ¶
VerifiedAssertion is what remains once a client assertion has been verified: the authenticated client ID and when the assertion expires.
type VerifyPolicy ¶
type VerifyPolicy struct {
// ExpectedClientID is the client the caller is trying to
// authenticate. Both the assertion's iss and sub claims must equal
// it exactly.
ExpectedClientID string
// ExpectedAudiences is the set of endpoint URLs (or issuer
// identifiers) the assertion's aud claim may equal — one match is
// enough. Almost always a single value; a caller that also accepts
// requests via an RFC 8705 §5 mtls_endpoint_aliases URL passes both
// that alias and the issuer, since a legitimate client's assertion
// may target either depending on which endpoint it called.
ExpectedAudiences []string
// Algorithm is the algorithm this client is registered to sign
// assertions with. The assertion header's algorithm must equal it
// exactly — this is what prevents algorithm-confusion attacks, so
// it must come from the client's registration, never from the
// assertion itself.
Algorithm fapi.SignatureAlgorithm
// Now is the time to validate exp/nbf against.
Now time.Time
// MaxLifetime bounds how far in the future (relative to Now) the
// assertion's exp claim may be. Required — there is no implicit
// default.
MaxLifetime time.Duration
// MaxClockSkew bounds how far in the future (relative to Now) an nbf
// claim may be, and extends how long past exp an assertion is still
// accepted. Zero means no tolerance.
MaxClockSkew time.Duration
// Replay, if non-nil, is used to detect assertion replay by jti. A
// nil Replay skips replay detection; server authentication must
// always supply one.
Replay ReplayChecker
}
VerifyPolicy is the set of checks Verify enforces against an Assertion.