Module oidc

Module oidc 

Source
Expand description

An OpenID Connect relying party — the half of docs/10 D6 that 48 §48.13 named as unbuilt.

crate::identity made an actor a decision of the runtime and offered two providers, both of which the process can also mint for: DevIdentity believes a claim and SignedIdentity verifies a shared secret. Neither suits a public identity provider, because a process that can verify a credential it could also have issued cannot tell “this user authenticated” from “this process said so”. This module is the asymmetric answer: the signature is checked against a public key fetched from the issuer, so the only thing that can produce a credential is the issuer.

§What is here

  • Discovery — {issuer}/.well-known/openid-configuration, which supplies the authorization, token and JWKS endpoints so an operator configures one URL rather than four.
  • A key set, fetched over TLS, cached, and refetched when a kid misses.
  • ID-token verification — RS256/384/512, PS256/384/512, ES256 and ES384, and nothing else: none and the HMAC family are refused by name, because “verify with whatever the token says” is how a relying party is talked into treating a public key as a shared secret.
  • The claim checks, all of them, in one place: issuer, audience, authorized party, expiry, not-before, and the nonce when there is a nonce to check.
  • The authorization-code flow with PKCE, so a browser can obtain a token in the first place.

§Where the trust actually comes from

Two links, and both are load-bearing. The signature says the issuer produced the token. TLS says the key set came from the issuer — there is nothing else protecting it, which is why the issuer must be an https URL and why there is no flag to relax that. crate::outbound is what makes the second link real, and its own tests are where a handshake is actually performed: this module is tested against a scripted [beck_core::net::Outbound], because a relying party tested against a server written beside it tests agreement with itself (docs/82 §82.10).

§What is deliberately not here

No session of Beck’s own: the cookie the flow sets is the ID token, so a session lasts as long as the issuer said it should and no longer. That makes token refresh unnecessary rather than missing — there is no local session to keep alive — and it makes logout the deletion of one cookie. §48.13 of the report says what it costs: a user is sent back to the issuer when the token expires, and an issuer that mints five-minute tokens will do that every five minutes.

No UserInfo request: the claims are the ID token’s. identity = managed() is built and is beck-infra’s (§48.8) — what reaches here from it is one thing, Config::in_cluster, and its field says what it costs.

Structs§

Completion
The browser came back and the token verified.
Config
What an operator states. Everything else is discovered.
Login
Where to send the browser, and what to remember while it is gone.
Provider
The endpoints, as the issuer published them.
Refusal
Why a token was refused, in the operator’s words.
RelyingParty
A relying party: one issuer, one client, one key set.
Verified
What a verified ID token said.

Constants§

CLOCK_SKEW_MS
How far the clock may be wrong before a token is refused for it.
LOGIN_WINDOW_MS
How long a login may take between /auth/login and /auth/callback.
REFETCH_FLOOR_MS
The floor between two key-set fetches, whatever asks for one.
REFRESH_EVERY_MS
How long a fetched key set is used before it is fetched again.

Functions§

query_params
a=1&b=2, decoded. A repeated name keeps every value, and the reader takes the first — which is the behaviour that makes ?code=good&code=evil unambiguous.