Skip to main content

AuthError

Enum AuthError 

Source
pub enum AuthError {
Show 51 variants AlgNone, AlgNotWhitelisted, AlgHmacRejected, AlgRsaRejected, AlgEcdsaRejected, HeaderJku, HeaderX5u, HeaderJwk, HeaderX5c, HeaderCrit, KidUnknown, TypMismatch, NestedJws, JwePayload, HeaderExtraParam, HeaderB64False, ExpMissing, Expired, ExpUpperBound, AudMissing, AudMismatch, IssMismatch, IatMissing, IatFuture, NotYetValid, JtiMissing, SubMissing, ClientIdMissing, TokenTypeMismatch, InvalidNumericType, JwsJsonRejected, DuplicateJsonKeys, LaxBase64, OversizedToken, SubFormatInvalid, AccountTypeInvalid, CapsShapeInvalid, ScopesShapeInvalid, ScopesTooLong, DlgDepthInvalid, AdminBandRejected, UnknownClaim(String), JtiReplayed, ReplayCacheUnavailable, SessionRevoked, SessionLookupUnavailable, SessionVersionStale, SessionVersionLookupUnavailable, NotJwsCompact, HeaderUnparseable, PayloadUnparseable,
}

Variants§

§

AlgNone

M01: token header carries alg: none (or a value the library cannot parse to a known Algorithm).

§

AlgNotWhitelisted

M02: header alg is parseable but not in the per-request whitelist.

§

AlgHmacRejected

M03: HMAC family (HS256/HS384/HS512) rejected — confusion attack against asymmetric public keys.

§

AlgRsaRejected

M04: RSA family (RS*/PS*) rejected.

§

AlgEcdsaRejected

M05: ECDSA family (ES*) rejected.

§

HeaderJku

M07: header carries jku (URL-loaded JWK Set).

§

HeaderX5u

M08: header carries x5u (URL-loaded X.509 chain).

§

HeaderJwk

M09: header carries inline jwk.

§

HeaderX5c

M10: header carries x5c (inline X.509 chain).

§

HeaderCrit

M11: header carries crit with unknown extensions.

§

KidUnknown

M12: kid missing or unknown to the server-pinned KeySet.

§

TypMismatch

M13/M13a: typ does not equal the configured value (default at+jwt). Strict equality — JWT is also rejected.

§

NestedJws

M14: nested JWS (payload is itself a JWT) — defended via cty header inspection.

§

JwePayload

M15: token is JWE (5-part) — encryption forbidden in this profile.

§

HeaderExtraParam

M16: header contains parameters outside the whitelist (typ, alg, kid).

§

HeaderB64False

M16a: header carries b64=false (RFC 7797 unencoded payload).

§

ExpMissing

M17: exp claim absent. RFC 8725 §3.10 — a token without an expiry contract has no admissibility window; reject before any value check.

§

Expired

M18: exp is in the past. RFC 8725 §3.10 — leeway = 0; the engine refuses any token whose expiry timestamp precedes the current instant. Distinct from ExpMissing: M17 fires when the claim is absent, M18 fires when it’s present but stale.

§

ExpUpperBound

M19: exp exceeds the per-profile upper bound (24h for access, 200d for refresh — Phase 2 is access-only; refresh issuance lands Phase 4). Bounds the blast radius of a leaked token: a malicious issuer cannot mint near-immortal credentials.

§

AudMissing

M20: aud claim absent. Without an audience binding the engine cannot enforce the verifier-specific match (M21/M22) — refuse before any value check.

§

AudMismatch

M21 + M22: aud value does not match cfg.audience. Phase 1’s M06 documented-collapse pattern applies — M21 covers the string form, M22 covers the array form, both surface the same audit signal. The variant carries the M-ID via the #[error] string; audit logs disambiguate via the cfg+token state.

§

IssMismatch

M23: iss is missing OR does not match the pinned issuer (cfg.issuer). Both cases collapse into one variant — the audit signal is identical: this token did not come from the trusted issuer. Distinguishing missing-vs-wrong adds no useful diagnostic (an attacker who omits iss and one who forges a wrong iss are both probing for issuer trust confusion).

§

IatMissing

M24 (first clause): iat claim absent. Without an issuance timestamp the engine can neither bound the token’s age (M19) nor enforce M24’s “must be in past” rule. M24’s future-iat clause surfaces as IatFuture.

§

IatFuture

M24 (second clause) + M25: iat is in the future beyond the 60s clock-skew leeway. Phase 1’s M06 documented-collapse pattern applies — M24’s must-be-in-past predicate and M25’s far-future ceiling enforce the same condition (iat > now + 60s); they share the variant. Audit logs disambiguate via the iat value itself (60s vs hours-in-the-future).

§

NotYetValid

M26: nbf (not-before) is present and in the future — the token has not yet entered its admissibility window. Distinct from IatFuture: nbf is the issuer’s explicit “valid from” boundary, where iat is the issuance instant. nbf is optional; absence is not an error.

§

JtiMissing

M27: jti claim absent. RFC 7519 §4.1.7 — the unique token identifier is the replay-cache key (M35). Without it the engine cannot enforce one-shot semantics on per-token operations.

§

SubMissing

M28: sub claim absent. RFC 7519 §4.1.2 — the subject identifies the principal the token is about; no useful authorization decision can follow when it’s missing.

§

ClientIdMissing

M28a: client_id claim absent. RFC 9068 §2.2 mandates this for access JWTs so the resource server can identify the originating OAuth client (audit, per-client rate limits).

§

TokenTypeMismatch

M29: cat (token category) is missing or not the expected value. RFC 9068 §2.2 + ppoppo extension — cat ∈ {access, refresh} is a payload-level discriminator that lets a single verifier refuse type-confusion attempts (refresh token at an access endpoint). Phase 2 verifies access tokens only; Phase 4 (refresh issuance) generalizes via cfg.expected_cat. Missing-cat collapses into the same variant — audit signal is identical (untrusted token type).

§

InvalidNumericType

M30: a numeric claim (exp/iat/nbf) is present but not a JSON integer. RFC 8725 §2.4 — string-coerced numerics are a classic substitution vector ("exp": "9999" parsed as a “valid” future expiry). Engine refuses any non-integer numeric claim before the value-violation rules can fire.

§

JwsJsonRejected

M31: input is JWS JSON serialization (or any non-compact form). RFC 8725 §2.4 — the profile accepts JWS Compact only. JSON-form JWS expands the implementation surface and has historically carried polyglot-payload attacks; refuse before any segment parser runs.

§

DuplicateJsonKeys

M32: header or payload JSON contains duplicate top-level keys. RFC 7515 §3 mandates rejection, but serde_json silently keeps the last occurrence by default — making the smuggling case (a forger duplicates a claim hoping the verifier reads one value while a downstream consumer reads another) invisible. Engine pre-validates every JSON object via a key-uniqueness Visitor before parsing.

§

LaxBase64

M33: a segment contains characters from the standard base64 alphabet (+, /, =) — RFC 8725 §2.4 requires strict base64url (URL_SAFE_NO_PAD: only A-Z a-z 0-9 - _). Standard b64 chars are rejected with their own variant so audit logs distinguish “intentional + injection” from generic decode failures (which surface as HeaderUnparseable / PayloadUnparseable).

§

OversizedToken

M34: total token length exceeds cfg.max_token_size (8 KB default for the access-token profile). A large token is either a misconfigured issuer (extras bloating beyond a reasonable claim set) or a denial-of-service vector (parser amplification). Engine refuses oversized input before any segment parsing runs.

§

SubFormatInvalid

M39: sub is present but not a 26-character Crockford-base32 ULID. PAS-issued tokens carry ppnum_id (Human ULID) or an AI-agent ULID in sub; any other shape is either an issuer drift or a forgery attempt. Distinct variant so audit logs distinguish “sub missing” (M28) from “sub ill-formed” (M39).

§

AccountTypeInvalid

M40: account_type is present but not in the whitelist {"human", "ai_agent"}. The claim is optional (legacy tokens minted before the field existed are admitted), but a present- but-unknown value is a forgery signal — the issuer never emits arbitrary strings here. Renamed from the matrix’s earlier actor to avoid collision with RFC 8693 token-exchange.

§

CapsShapeInvalid

M41: caps is present but the wire shape is wrong (not a JSON array of strings). The default-deny invariant lives in the interpretation: absent/empty both mean “no capabilities”, and any non-empty value MUST be an array of strings. A string-typed caps: "admin" is the canonical confusion — a forger hoping the verifier reads it as a one-element list.

§

ScopesShapeInvalid

M42 (shape): scopes is present but not a JSON array of strings. Mirrors CapsShapeInvalid — collapsed into its own variant because the audit signal is meaningfully different (a scope confusion attack reads a different threat model than a capability shape attack).

§

ScopesTooLong

M42 (length): scopes has more than 256 entries. Bounds the per-token audit surface and stops a misconfigured issuer (or a forger who got hold of a signing key) from minting a token whose authorization vector is itself a DoS — a 10k-entry scopes array pessimizes every per-request scope check.

§

DlgDepthInvalid

M43: dlg_depth is present but exceeds the 4-step delegation chain bound (or is the wrong wire shape — non-integer, negative). Bounds the audit-trail explosion of arbitrarily deep Token Exchange chains; dlg_depth = 4 is the inclusive bound, matching RFC §6.5. Single variant covers both shape and bound errors — audit signal is “delegation chain rejected”, and the value itself surfaces in structured logging at the rejection site.

§

AdminBandRejected

M44 (band gate): token claims admin: true but the supporting active_ppnum is either absent or its first 3 digits don’t fall in the admin allocation band. PAS issues admin tokens only on ppnums minted from the admin band, so a token outside the band is either a forgery (with a stolen signing key) or an issuer drift. This is defense-in-depth on top of is_admin DB lookup (STANDARDS_AUTH_PPOPPO §3.2 — DB is the source of truth); it turns a stolen-key forgery into an “active_ppnum needs to be banded” forgery, narrowing the attack window meaningfully.

§

UnknownClaim(String)

M45: payload contains a claim outside the engine’s strict allowlist. The PAS issuance pipeline only emits claims listed in engine::check_domain::ALLOWED_CLAIMS; anything else is a forgery / misconfiguration / PII smuggling attempt (M45 is the “no PII in payload” defense — email / phone / name get rejected by name). The variant carries the offending claim name for audit logs so operators can see at a glance which claim triggered the rejection.

§

JtiReplayed

M35: jti has been seen within the replay-cache TTL — replayed token. Engine refuses on the second sighting; implementations of ReplayDefense MUST treat the cache check and record as a single atomic primitive (KVRocks SET NX EX, equivalent) to avoid a TOCTOU window between check and record.

§

ReplayCacheUnavailable

M35 (substrate transient): replay-cache substrate is unreachable. Engine fails closed — admitting on substrate failure would let a replayer slip through during the outage. Audit logs surface this as a SEPARATE signal from JtiReplayed so ops can distinguish “active attack” (replay) from “infrastructure issue” (cache down).

§

SessionRevoked

M36: (sub, sid) row absent from user_sessions — the session was revoked. STANDARDS_JWT_DETAILS_MITIGATION §E “row deletion = revocation” — this is the textbook stateful-revocation gate that makes the system “stateful by design” (OVERVIEW §6: stateless 환상 폐기). Distinct from SessionVersionStale (account-wide epoch) because this axis kicks one device while leaving the account’s other sessions alive.

§

SessionLookupUnavailable

M36 (substrate transient): session-row lookup substrate is unreachable. Engine fails closed.

§

SessionVersionStale

sv-port (Phase 5): token’s sv claim is strictly less than the current per-account session_version. Break-glass / LogoutAll bump current_sv inside the substrate; tokens minted before the bump fail this gate within the cache TTL (60s default — see SV_CACHE_TTL). PAS-internal callers preemptively flip sv:{ppnum_id}; remote consumers (PCS chat-auth, pas-external SDK) converge via the cache TTL.

§

SessionVersionLookupUnavailable

sv-port (substrate transient): EpochRevocation::current failed. Engine fails closed.

§

NotJwsCompact

Token cannot be split into a JWS Compact form (3 segments).

§

HeaderUnparseable

Header segment cannot be base64url-decoded or is not valid JSON.

§

PayloadUnparseable

Payload segment cannot be base64url-decoded or is not valid JSON. Mirrors HeaderUnparseable for the second segment — structural, not an M-row enforcement.

Trait Implementations§

Source§

impl Clone for AuthError

Source§

fn clone(&self) -> AuthError

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AuthError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for AuthError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for AuthError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl PartialEq for AuthError

Source§

fn eq(&self, other: &AuthError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for AuthError

Source§

impl StructuralPartialEq for AuthError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more