Atex.OAuth (atex v0.6.0)
View SourceOAuth 2.0 implementation for AT Protocol authentication.
This module provides utilities for implementing OAuth flows compliant with the AT Protocol specification. It includes support for:
- Pushed Authorization Requests (PAR)
- DPoP (Demonstration of Proof of Possession) tokens
- JWT client assertions
- PKCE (Proof Key for Code Exchange)
- Token refresh
- Handle to PDS resolution
Configuration
See Atex.Config.OAuth module for configuration documentation.
Usage Example
iex> pds = "https://bsky.social"
iex> login_hint = "example.com"
iex> {:ok, authz_server} = Atex.OAuth.get_authorization_server(pds)
iex> {:ok, authz_metadata} = Atex.OAuth.get_authorization_server_metadata(authz_server)
iex> state = Atex.OAuth.create_nonce()
iex> code_verifier = Atex.OAuth.create_nonce()
iex> {:ok, auth_url} = Atex.OAuth.create_authorization_url(
authz_metadata,
state,
code_verifier,
login_hint
)
Summary
Functions
Create an OAuth authorization URL for a PDS.
Get a map cnotaining the client metadata information needed for an authorization server to validate this client.
Fetch the authorization server for a given Personal Data Server (PDS).
Fetch the metadata for an OAuth authorization server.
Retrieves the configured JWT private key for signing client assertions.
Exchange an OAuth authorization code for a set of access and refresh tokens.
Types
@type tokens() :: %{ access_token: String.t(), refresh_token: String.t(), did: String.t(), expires_at: NaiveDateTime.t() }
Functions
@spec create_authorization_url( authorization_metadata(), String.t(), String.t(), String.t() ) :: {:ok, String.t()} | {:error, any()}
Create an OAuth authorization URL for a PDS.
Submits a PAR request to the authorization server and constructs the authorization URL with the returned request URI. Supports PKCE, DPoP, and client assertions as required by the AT Protocol.
Parameters
authz_metadata- Authorization server metadata containing endpoints, fetched fromget_authorization_server_metadata/1state- Random token for session validationcode_verifier- PKCE code verifierlogin_hint- User identifier (handle or DID) for pre-filled login
Returns
{:ok, authorization_url}- Successfully created authorization URL{:ok, :invalid_par_response}- Server respondend incorrectly to the request{:error, reason}- Error creating authorization URL
@spec create_client_assertion(JOSE.JWK.t(), String.t(), String.t()) :: String.t()
@spec create_client_metadata() :: map()
Get a map cnotaining the client metadata information needed for an authorization server to validate this client.
@spec create_dpop_token(JOSE.JWK.t(), Req.Request.t(), any(), map()) :: String.t()
Fetch the authorization server for a given Personal Data Server (PDS).
Makes a request to the PDS's .well-known/oauth-protected-resource endpoint
to discover the associated authorization server that should be used for the
OAuth flow.
Parameters
pds_host- Base URL of the PDS (e.g., "https://bsky.social")
Returns
{:ok, authorization_server}- Successfully discovered authorization server URL{:error, :invalid_metadata}- Server returned invalid metadata{:error, reason}- Error discovering authorization server
@spec get_authorization_server_metadata(String.t()) :: {:ok, authorization_metadata()} | {:error, any()}
Fetch the metadata for an OAuth authorization server.
Retrieves the metadata from the authorization server's
.well-known/oauth-authorization-server endpoint, providing endpoint URLs
required for the OAuth flow.
Parameters
issuer- Authorization server issuer URL
Returns
{:ok, metadata}- Successfully retrieved authorization server metadata{:error, :invalid_metadata}- Server returned invalid metadata{:error, :invalid_issuer}- Issuer mismatch in metadata{:error, any()}- Other error fetching metadata
@spec get_key() :: JOSE.JWK.t()
Retrieves the configured JWT private key for signing client assertions.
Loads the private key from configuration, decodes the base64-encoded DER data, and creates a JOSE JWK structure with the key ID field set.
Returns
A JOSE.JWK struct containing the private key and key identifier.
Raises
Application.Env.Errorif the private_key or key_id configuration is missing
Examples
key = OAuth.get_key()
key = OAuth.get_key()
@spec request_protected_dpop_resource( Req.Request.t(), String.t(), String.t(), JOSE.JWK.t(), String.t() | nil ) :: {:ok, Req.Response.t(), String.t() | nil} | {:error, any()}
@spec send_oauth_dpop_request(Req.Request.t(), JOSE.JWK.t(), String.t() | nil) :: {:ok, map(), String.t()} | {:error, any(), String.t()}
@spec validate_authorization_code( authorization_metadata(), JOSE.JWK.t(), String.t(), String.t() ) :: {:ok, tokens(), String.t()} | {:error, any()}
Exchange an OAuth authorization code for a set of access and refresh tokens.
Validates the authorization code by submitting it to the token endpoint along with the PKCE code verifier and client assertion. Returns access tokens for making authenticated requests to the relevant user's PDS.
Parameters
authz_metadata- Authorization server metadata containing token endpointdpop_key- JWK for DPoP token generationcode- Authorization code from OAuth callbackcode_verifier- PKCE code verifier from authorization flow
Returns
{:ok, tokens, nonce}- Successfully obtained tokens with returned DPoP nonce{:error, reason}- Error exchanging code for tokens