clientassertion

package
v0.19.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 29, 2026 License: MIT Imports: 13 Imported by: 0

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

View Source
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

View Source
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 Parse

func Parse(assertion string) (Assertion, error)

Parse parses a client assertion without verifying its signature.

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

func (a Assertion) ClaimedIssuer() string

ClaimedIssuer returns the assertion's unverified "iss" claim, for use as a client-lookup key only.

func (Assertion) ClaimedSubject

func (a Assertion) ClaimedSubject() string

ClaimedSubject returns the assertion's unverified "sub" claim, for use as a client-lookup key only.

func (Assertion) KeyID

func (a Assertion) KeyID() string

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

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

type VerifiedAssertion struct {
	ClientID  string
	ExpiresAt time.Time
}

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL