Skip to main content

Module client_metadata

Module client_metadata 

Source
Expand description

Fetching, validating, and caching OAuth client metadata documents.

atproto’s OAuth profile has no registered-client table: a client_id is an HTTPS URL, and the document served there is the client’s registration, fetched fresh (or from a short-lived cache) on every use. plan/app-allowlist.md needs more than the URL to enforce “an app that changes its redirect URIs is a different app” — so ClientKey is computed over the validated document’s own content, not over the client_id string, and it is what ClientMetadataCache keys on.

This module does not decide whether a client is admitted; it decides whether a document is usable at all. Admission is plan/app-allowlist.md’s hook, called from oauth::par once a validated document exists.

One client_id form is the exception to “fetched fresh”: the atproto profile’s “Localhost Client Development” client_id, exactly http://localhost with no port and an empty or / path. There is nothing to fetch — parse_loopback_client_id builds the document straight from that URL’s own redirect_uri/scope query parameters, and resolve_client returns it before ever reaching the network.

No other client_id may name a port: the profile says “there must not be a port number included”. A development deployment reaches a client serving on another port through didbot_identity::did::RESOLVE_PORTS, as it reaches a did:web.

Structs§

CachedClientMetadata
A cached, validated document plus when it was fetched.
ClientKey
A validated document’s own identity, for ClientMetadataCache and for plan/app-allowlist.md’s “an admitted app that changes its redirect URIs is a different app” — computed over the document’s content, so two fetches of the same client_id that disagree produce two different keys.
ClientMetadataDocument
A validated client metadata document.
MemoryClientMetadataCache
The in-process client metadata cache.

Enums§

ApplicationType
A document’s application_type, which the atproto profile borrows from OpenID Connect. Absent, it is web; any other word refuses the document.
ClientMetadataError
Why a client metadata document could not be used.
LoopbackClients
Whether this deployment will fetch a client metadata document over loopback http://.

Constants§

CACHE_CAPACITY
How many distinct client_ids MemoryClientMetadataCache holds at once.
CACHE_TTL
How long a fetched document is trusted before it is fetched again.
FETCH_TIMEOUT
How long the whole client metadata fetch may take — connect, headers and body together, not just the handshake.
MAX_DOCUMENT_BYTES
The most of a client metadata document this server will read before giving up on it.

Traits§

ClientMetadataCache
Where fetched client metadata is cached, keyed by client_id.

Functions§

check_authentication 🔒
Refuses what the atproto profile’s “Confidential Client Authentication” refuses of a document’s client authentication fields.
fetch_bounded 🔒
GETs url on client_id’s behalf, under every bound resolve_client names: FETCH_TIMEOUT for the whole fetch, MAX_DOCUMENT_BYTES for the body, and no redirect. Only a 200 OK is read, and when json_only, only one served as application/json.
fetch_jwks 🔒
The key set a confidential client publishes at jwks_uri, fetched the way its document is (fetch_bounded).
is_loopback_redirect_uri 🔒
Whether raw is a usable loopback redirect URI: http://127.0.0.1 or http://[::1], any port, per the atproto profile’s “Localhost Client Development” form. Stricter than didbot_http::is_loopback on purpose — that one also accepts the literal name localhost, which this form forbids for a redirect.
is_native_redirect_uri 🔒
Whether a native client named client_id may register raw as a redirect, by the atproto profile’s rules for native clients.
is_web_redirect_uri 🔒
Whether a web client may register raw as a redirect: the profile says a web client’s redirect “is a HTTPS URL”. A loopback http:// redirect belongs to a native client.
parse_loopback_client_id 🔒
Recognises the atproto OAuth profile’s “Localhost Client Development” client_id form — exactly http://localhost, no port, path empty or / — and builds its virtual client metadata document straight from the redirect_uri (repeatable) and scope query parameters, fetching nothing.
pinned_public_client 🔒
A client for fetching url, pinned to the addresses its host resolves to, and refused unless every one of them is one didbot_http::is_public_address allows.
read_bounded 🔒
Reads at most MAX_DOCUMENT_BYTES of a response body.
redirected_away_from 🔒
Where a response landed, if that is not requested.
resolve_client
Fetches, validates, and caches the client metadata document for client_id.
same_loopback_redirect 🔒
Whether requested is the loopback redirect registered, on any port.
validate
Validates a raw fetched document against client_id, the URL it was fetched from.
validate_url_scheme 🔒
Checks a URL is https:// (or loopback http://) with no fragment.