Skip to main content

Crate cratefield_auth_client

Crate cratefield_auth_client 

Source
Expand description

Verify auth-service tokens in a consuming app (issue #11).

Six ventures each writing their own JWT validation is six chances to forget the audience check. This crate does it once.

ⓘ
let auth = AuthClient::new(http, clock, "https://auth.acme.example", "client-kontinuum");
async fn handler(Authenticated(claims): Authenticated) -> String { claims.sub }

What it checks, in this order: the header names ES256 and a kid we hold; the signature verifies against that key; iss equals the configured issuer; aud equals this client’s id; exp has not passed and nbf/iat are not implausibly far in the future. Every one of those is a way a token from somewhere else gets accepted if it is skipped, so none of them is optional and none is configurable.

Algorithm confusion is refused structurally. The header’s alg must be exactly ES256. none and the HMAC families are rejected before any key is looked up, so a token asking to be verified with the public key as an HMAC secret never reaches verification.

wasm-safe. Time comes from the harness Clock port and HTTP from its HttpClient port, so this compiles for wasm32-unknown-unknown where std::time and chrono::Utc::now both panic.

cratefield-auth-client — Who the caller is.

cratefield-auth-client on crates.io cratefield-auth-client documentation MIT

§cratefield-auth-client

Verify auth-service tokens in a consuming app: JWKS fetch and cache, ES256 verification with the audience check that hand-rolled verifiers forget, and an axum extractor. Issue #11.

§Freshness and roles (issue #912)

Verification proves who signed a token and that it was minted for this client. It does not prove that the person just proved who they are. A relying party that is about to approve something (a payment, an offer, a change of ownership) must check that itself:

ⓘ
if !claims.stepped_up_within(120, now) {
    // ask the person to sign in again, with prompt=login and max_age=0
}

Payment, signing and other irreversible gates must use stepped_up_within, not authenticated_within. authenticated_within only checks the age of the last sign-in, whatever method it used. A federated (sso, federated) or password sign-in passes it, and the password was never proven fresh. stepped_up_within also requires a passkey or an email link in amr. The token’s acr is urn:cratefield:stepup when the session spent a step-up transaction; that is a fact about the session, and a relying party may check it too, but the age and method check above is the one that decides.

auth_time is epoch seconds of the person’s last real sign-in ceremony. A refresh never moves it, so a long-lived session does not look fresh. roles lists the account’s roles in the issuing instance (owner, admin, member) when the client was registered to receive them, and is empty otherwise. Only access tokens verify here: a token whose typ is not at+jwt (an ID token, for one) is refused.


MIT. Part of the Cratefield harness.

Structs§

AuthClient
Verifies tokens issued by one auth instance, for one registered client.
AuthState
Router state carrying the verifier.
Authenticated
A verified caller.
Claims
The claims a verified access token carries.
JwksCache
The cached key set and the times that govern refetching.

Enums§

VerifyError
Why a token was refused.

Constants§

ALGORITHM
The only signature algorithm this client accepts.
JWKS_MIN_REFETCH_SECS
The shortest gap between two forced refetches triggered by an unknown kid. Without it, a stream of tokens naming keys that do not exist would let anyone drive unbounded traffic at the auth service.
JWKS_TTL_SECS
How long a fetched key set is trusted before it is refetched.
LEEWAY_SECS
Clock skew tolerated on exp, nbf and iat.
UNAUTHENTICATED
The one refusal this crate ever returns.

Functions§

from_config
The Auth port a deployment gets from its environment (issue #153).
token_fingerprint
The SHA-256 of a token, for logging a token without logging it.