OAuth.jl
OAuth.jl is a reference implementation of modern OAuth 2.x client/server flows in Julia. It now includes:
- PAR/JAR support with automatic HTTPS validation and request-object signing via
RequestObjectSigner. - Resource Indicator (RFC 8707) and Rich Authorization Request (RFC 9396) propagation for PKCE, refresh tokens, device authorization, and client credentials.
- Dynamic Client Registration helpers for RFC 7591/7592 compliant authorization servers.
Quick Links
OAuth.PublicClientConfig — Type
PublicClientConfigConfiguration for apps that cannot keep a secret (CLIs, native apps, SPAs). Along with identifiers and scopes it stores optional DPoP credentials, refresh token persistence hooks, and whether to prefer pushed authorization requests or signed request objects.
OAuth.RequestObjectSigner — Type
RequestObjectSignerEncapsulates the inputs required to sign JWT request objects (PAR or direct request parameter). Created through the keyword constructor that accepts private keys, algorithm selections, optional kid, and any extra claims to embed.
OAuth.register_dynamic_client — Function
register_dynamic_client(metadata, client_metadata; http=HTTP, initial_access_token=nothing, verbose=false) -> JSONObjectCalls the Dynamic Client Registration endpoint declared in issuer metadata and returns the resulting JSON document (which typically holds client_secret, registration_access_token, etc.). Pass initial_access_token when the AS protects its registration endpoint.
OAuth.register_dynamic_client_from_issuer — Function
register_dynamic_client_from_issuer(issuer_url, client_metadata; kwargs...) -> NamedTupleFetches metadata for the issuer and forwards the request to register_dynamic_client. Returns both the JSON response and the metadata used.
OAuth.update_dynamic_client — Function
update_dynamic_client(configuration_endpoint; http=HTTP, client_metadata, registration_access_token, verbose=false) -> JSONObjectIssues a PUT request to the client configuration endpoint with the supplied metadata body. Requires the registration_access_token obtained during registration.
OAuth.delete_dynamic_client — Function
delete_dynamic_client(configuration_endpoint; http=HTTP, registration_access_token, verbose=false) -> BoolSends a DELETE to the client configuration endpoint, authenticating with the provided registration_access_token. Returns true on HTTP 2xx.
OAuth.JWTAccessTokenIssuer — Type
JWTAccessTokenIssuerHolds the signing material and metadata required to mint JWT access tokens for your resource server. Combine with issue_access_token and public_jwk to build your own auth server in a few lines.
OAuth.issue_access_token — Function
issue_access_token(issuer; subject=nothing, client_id=nothing, scope=[], authorization_details=nothing, extra_claims=Dict(), audience=nothing, now=Dates.now(UTC), store=nothing, confirmation=nothing, confirmation_jkt=nothing) -> IssuedAccessTokenSigns a JWT access token using the supplied JWTAccessTokenIssuer and optionally records it in an AccessTokenStore for later introspection or revocation checks. Set confirmation / confirmation_jkt to embed DPoP confirmation claims.
OAuth.public_jwk — Function
public_jwk(issuer::JWTAccessTokenIssuer) -> Dict{String,Any}Returns (and memoizes) the public JWK derived from the issuer’s private key so you can publish it via register_jwks_endpoint!.
OAuth.register_jwks_endpoint! — Function
register_jwks_endpoint!(router, keys; path=DEFAULT_JWKS_PATH) -> FunctionPublishes a JSON Web Key Set generated from the objects in keys. Each element can already be a dictionary or a struct with stringifiable fields.
OAuth.AccessTokenStore — Type
AccessTokenStoreAn AbstractStores.AbstractStore containing AccessTokenRecord values. OAuth owns the value type and token lifecycle. The application chooses the storage backend.
Records are always written with an expiry derived from the token's exp, so the store must report AbstractStores.supportsttl(store) == true; TokenEndpointConfig checks that when you hand it a token_store.
Expired records are never returned, but a store that does not expire entries natively — MemoryStore, FileStore — only reclaims one when it is read. Call AbstractStores.sweep! periodically on a long-lived store.
OAuth.AccessTokenRecord — Type
AccessTokenRecordStored representation of an issued access token.
OAuth.RefreshTokenGrantStore — Type
RefreshTokenGrantStoreAn AbstractStores.AbstractStore containing server-side RefreshTokenGrantRecord values. This is the authorization-server counterpart to the client-side RefreshTokenStore.
Refresh tokens are rotated by consuming them, so the store must report AbstractStores.isatomic(store) == true; it must additionally support TTL when refresh_token_ttl_seconds is set. TokenEndpointConfig checks both.
OAuth.RefreshTokenGrantRecord — Type
RefreshTokenGrantRecordEverything the token endpoint needs to honour a refresh token: the client it was issued to, the authenticated subject, and the scope/resource/claims of the original grant.
OAuth.RefreshTokenStore — Type
RefreshTokenStoreAbstract interface for persisting refresh tokens between OAuth sessions. Concrete stores implement three simple methods—load_refresh_token, save_refresh_token!, and clear_refresh_token!—so that the higher-level PKCE helpers can securely remember long-lived refresh tokens without you writing boilerplate.
OAuth.AuthorizationEndpointConfig — Type
AuthorizationEndpointConfigAggregates everything the built-in authorization endpoint needs: a store, redirect URI resolver, consent handler, and code TTL.
OAuth.TokenEndpointConfig — Type
TokenEndpointConfigHolds everything the built-in token endpoint needs: the authorization code store, token issuer, client authenticator, refresh token generator, extra claims callback, optional persistent token store, allowed grant types, and an optional TokenService for family-aware refresh-token rotation.
OAuth.AuthorizationServerStores — Type
AuthorizationServerStoresA concrete bundle of the three logical stores used by an OAuth authorization server. The stores may be typed views over one shared backend or independent stores chosen for their different persistence and atomicity requirements.
OAuth.TokenService — Type
TokenServiceCombines a JWTAccessTokenIssuer with the typed stores used to issue, look up, revoke, and refresh access tokens. Refresh tokens minted by this service rotate within one stored token family so replaying an older generation revokes the active family.
OAuth.IssuedTokenPair — Type
IssuedTokenPairThe access token and rotating refresh-token grant returned by issue_token_pair! and refresh_token_pair!.
OAuth.issue_token_pair! — Function
issue_token_pair!(service; client_id, subject=nothing, scope=[],
resource=[], authorization_details=nothing,
extra_claims=Dict(), audience=nothing,
now=Dates.now(UTC)) -> IssuedTokenPairIssue and persist an access token plus a rotating refresh token. client_id is required because every refresh grant is bound to the client that received it.
OAuth.refresh_token_pair! — Function
refresh_token_pair!(service, refresh_token; client_id, scope=nothing,
extra_claims=Dict(), audience=nothing,
now=Dates.now(UTC)) -> IssuedTokenPairAtomically rotate a refresh token and issue a new access token. Replaying an older token generation revokes the active token family. A requested scope may narrow, but never widen, the original grant. If access-token issuance fails after rotation, the service revokes the refresh family so it cannot return a partially issued token pair.
OAuth.revoke_refresh_token_grant! — Function
Revoke the complete refresh-token family containing token.