requestobject

package
v0.17.0 Latest Latest
Warning

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

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

Documentation

Overview

Package requestobject implements signed JAR (RFC 9101) request-object construction and verification for the parameters carried in an authorization/PAR request.

create.go is used by client to build the request object it pushes to the AS; verify.go is used by server to authenticate and parse it, including replay detection via a ReplayChecker. Create and Verify intentionally take independent parameter types (CreateParams and VerifyPolicy), even though they share JOSE encoding and claim-parsing helpers — signing policy (what the client is allowed to assert) and verification policy (what the server is willing to accept) are independent decisions that must be configurable independently.

Only the JWT-standard claims (iss, aud, exp, nbf, iat, jti) are parsed into typed fields. Every other top-level claim — the actual authorization request parameters, including any registered extension/RAR parameter — is left as raw JSON in Parameters for the extension package to interpret; this package has no opinion on which parameters are valid, only on the JWT envelope around them.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrWrongType indicates the object's "typ" header was present but
	// did not identify a request object (RFC 9101 §10.8) even after the
	// case-insensitive, "application/"-prefix-tolerant comparison
	// isRequestObjectType applies. An absent "typ" header is not an
	// error — see jwtType's doc comment.
	ErrWrongType = errors.New("requestobject: header typ is not oauth-authz-req+jwt")

	// ErrMalformedClaims indicates the payload was not a JSON object, or
	// was missing a required top-level claim (iss, aud or exp).
	ErrMalformedClaims = errors.New("requestobject: malformed claims")

	// ErrClientIDIssuerMismatch indicates the payload's "client_id"
	// parameter (RFC 9101 §5.3) did not equal its "iss" claim.
	ErrClientIDIssuerMismatch = errors.New("requestobject: client_id parameter does not match iss")

	// ErrIssuerMismatch indicates the object's iss claim did not equal
	// the client ID the caller expected to authenticate.
	ErrIssuerMismatch = errors.New("requestobject: iss does not match expected client ID")

	// ErrAudienceMismatch indicates the object's aud claim (a single
	// value or, per RFC 7519 §4.1.3, an array of values) did not contain
	// the audience (authorization server issuer identifier) the caller
	// expected.
	ErrAudienceMismatch = errors.New("requestobject: aud does not match expected audience")

	// ErrExpired indicates the object's exp claim is not after the
	// verification time.
	ErrExpired = errors.New("requestobject: object has expired")

	// ErrNotYetValid indicates the object's nbf claim is in the future
	// beyond the configured clock-skew tolerance.
	ErrNotYetValid = errors.New("requestobject: object is not yet valid")

	// ErrMissingNotBefore indicates VerifyPolicy.RequireNotBefore was set
	// but the object carries no nbf claim at all.
	ErrMissingNotBefore = errors.New("requestobject: nbf claim is required")

	// ErrLifetimeExceeded indicates the object's exp claim is further in
	// the future than the configured maximum lifetime allows.
	ErrLifetimeExceeded = errors.New("requestobject: exp exceeds maximum allowed lifetime")

	// ErrNotBeforeTooOld indicates the object's nbf claim is further in
	// the past than the configured maximum lifetime allows. Symmetric
	// with ErrLifetimeExceeded: that bounds how far exp may sit in the
	// future of Now, this bounds how far nbf may sit in the past of
	// Now — without it, an object with a normal, unexpired exp but an
	// ancient nbf would sail through both other checks despite claiming
	// an unreasonably long validity window, which is exactly what FAPI
	// 2.0 Message Signing Final §5.3.1 (FAPI2-MS-ID1-5.3.1-3) requires
	// be rejected.
	ErrNotBeforeTooOld = errors.New("requestobject: nbf exceeds maximum allowed age")
)

Functions

func Create

func Create(p CreateParams) (string, error)

Create builds and signs a request object for p.

Types

type Claims

type Claims struct {
	Issuer string

	// Audience is the object's "aud" claim. RFC 7519 §4.1.3 permits a
	// JWT's "aud" to be either a single string or an array of strings —
	// both are normalized to this slice, so Verify's audience check
	// treats a single value the same as a one-element array.
	Audience   []string
	ExpiresAt  time.Time
	IssuedAt   time.Time // zero if absent
	NotBefore  time.Time // zero if absent
	JTI        string    // "" if absent
	Parameters map[string]json.RawMessage
}

Claims is a parsed request object payload. iss, aud and exp are the JWT-standard claims RFC 9101 relies on; everything else — the actual authorization request parameters (response_type, client_id, redirect_uri, scope, state, nonce, code_challenge, code_challenge_method, authorization_details, and any registered extension parameter) — is left in Parameters as raw JSON for the extension/RAR layer to interpret against its own registered definitions. This package does not reject unrecognized parameter names; deciding which parameters are allowed is policy that belongs above this package.

type CreateParams

type CreateParams struct {
	// Signer produces the object's signature.
	Signer crypto.Signer

	// Algorithm the object is signed with. Signer's key must match it.
	Algorithm fapi.SignatureAlgorithm

	// KeyID, if non-empty, is recorded in the object'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 the "iss" claim (RFC 9101 §5.3). If Parameters
	// contains a "client_id" entry, it must equal ClientID exactly.
	ClientID string

	// Audience is the "aud" claim — the authorization server issuer
	// identifier this object is scoped to.
	Audience string

	// Now is the object's issuance time.
	Now time.Time

	// Lifetime bounds how long the object is valid for (exp = Now +
	// Lifetime). FAPI profiles expect this to be short.
	Lifetime time.Duration

	// Random is the source of randomness for the object's "jti". If
	// nil, crypto/rand.Reader is used.
	Random io.Reader

	// Parameters are the authorization request parameters to embed as
	// top-level claims — response_type, client_id, redirect_uri, scope,
	// state, nonce, code_challenge, code_challenge_method,
	// authorization_details, and any registered extension parameter —
	// each already encoded as JSON. Parameters must not use the
	// JWT-standard claim names iss, aud, exp, nbf, iat or jti; Create
	// sets those itself.
	Parameters map[string]json.RawMessage
}

CreateParams describes one request object to create.

type Object

type Object struct {
	// contains filtered or unexported fields
}

Object is a parsed, but not yet signature-verified, request object. KeyID, Algorithm, ClaimedIssuer and Parameter are available before Verify succeeds so a caller can look up which registered client and key to verify against, and which client to attribute a rejected request to for error reporting — that is a safe use of unverified data, since it only selects what to check against, not what to trust. Nothing from Object should influence an authorization decision until Verify returns a VerifiedObject.

func Parse

func Parse(token string) (Object, error)

Parse parses a request object without verifying its signature.

func (Object) Algorithm

func (o Object) Algorithm() fapi.SignatureAlgorithm

Algorithm returns the algorithm the object 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 (Object) ClaimedIssuer

func (o Object) ClaimedIssuer() string

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

func (Object) KeyID

func (o Object) KeyID() string

KeyID returns the object header's "kid", or "" if absent. Untrusted until Verify succeeds; use only to select which key to verify against.

func (Object) Parameter

func (o Object) Parameter(name string) (json.RawMessage, bool)

Parameter returns the unverified authorization request parameter named name, for use as a lookup key only (e.g. resolving a registered redirect_uri set before the signature has been checked). Nothing derived from it should influence an authorization decision until Verify succeeds.

func (Object) Verify

func (o Object) Verify(ctx context.Context, pub crypto.PublicKey, policy VerifyPolicy) (VerifiedObject, error)

Verify checks o's signature against pub and its claims against policy.

type ReplayChecker

type ReplayChecker interface {
	UseOnce(ctx context.Context, jti string, expiresAt time.Time) error
}

ReplayChecker records that a request object's "jti" has been used, failing if it has been seen before. As with dpop.ReplayChecker and clientassertion.ReplayChecker, implementations are expected to key storage by a namespaced digest of jti, not the raw value.

type VerifiedObject

type VerifiedObject struct {
	ClientID   string
	Parameters map[string]json.RawMessage
	ExpiresAt  time.Time
}

VerifiedObject is what remains once a request object has been verified: the authenticated client ID and the authorization request parameters it carried.

type VerifyPolicy

type VerifyPolicy struct {
	// ExpectedClientID is the client the caller is trying to
	// authenticate. The object's iss claim must equal it exactly.
	ExpectedClientID string

	// ExpectedAudience is the authorization server issuer identifier the
	// object's aud claim must equal exactly.
	ExpectedAudience string

	// Algorithm is the algorithm this client is registered to sign
	// request objects with. The object 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 object
	// 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
	// object's exp claim may be, and symmetrically how far in the past
	// its nbf claim may be — an object is meant to represent one short,
	// coherent validity window around when it was created, not two
	// independently-bounded claims, so the same limit governs both
	// directions. 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 object is still
	// accepted. Zero means no tolerance.
	MaxClockSkew time.Duration

	// RequireNotBefore rejects an object with no nbf claim at all,
	// rather than simply skipping the not-yet-valid check for it. FAPI
	// 2.0 Message Signing Final §5.3.1 mandates nbf ("shall require the
	// request object to contain an nbf claim"); the base FAPI 2.0
	// Security Profile does not (it relies on request_uri's own short
	// lifetime instead, per its "Main differences to FAPI 1.0" table) —
	// so the caller sets this only under
	// ProfileFAPISecurityWithMessageSigning, not unconditionally.
	RequireNotBefore bool

	// Replay, if non-nil, is used to detect object replay by jti — but
	// only when the object actually carries one. Neither RFC 9101 nor
	// FAPI 2.0 Message Signing Final requires a request object to
	// include jti (message-signing's own replay defense is its
	// mandatory, tightly-bounded nbf/exp window, not a jti claim), and
	// the OIDF conformance suite's own request objects never carry one
	// under the plain FAPI2 profile — only its Brazil-specific profile
	// behavior adds one. So a missing jti here is not an error; it just
	// means this particular object skips replay-by-jti, the same as a
	// nil Replay would. This is fine architecturally because — when a
	// request object is only ever accepted via a PAR request_uri that is
	// itself single-use — replay detection here was always meant as
	// defense in depth, not the primary control.
	Replay ReplayChecker
}

VerifyPolicy is the set of checks Verify enforces against an Object.

Jump to

Keyboard shortcuts

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