Atex.OAuth (atex v0.6.0)

View Source

OAuth 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

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

authorization_metadata()

@type authorization_metadata() :: %{
  issuer: String.t(),
  par_endpoint: String.t(),
  token_endpoint: String.t(),
  authorization_endpoint: String.t()
}

tokens()

@type tokens() :: %{
  access_token: String.t(),
  refresh_token: String.t(),
  did: String.t(),
  expires_at: NaiveDateTime.t()
}

Functions

create_authorization_url(authz_metadata, state, code_verifier, login_hint)

@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 from get_authorization_server_metadata/1
  • state - Random token for session validation
  • code_verifier - PKCE code verifier
  • login_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

create_client_assertion(jwk, client_id, issuer)

@spec create_client_assertion(JOSE.JWK.t(), String.t(), String.t()) :: String.t()

create_client_metadata()

@spec create_client_metadata() :: map()

Get a map cnotaining the client metadata information needed for an authorization server to validate this client.

create_dpop_token(jwk, request, nonce \\ nil, attrs \\ %{})

@spec create_dpop_token(JOSE.JWK.t(), Req.Request.t(), any(), map()) :: String.t()

get_authorization_server(pds_host)

@spec get_authorization_server(String.t()) :: {:ok, String.t()} | {:error, any()}

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

Returns

  • {:ok, authorization_server} - Successfully discovered authorization server URL
  • {:error, :invalid_metadata} - Server returned invalid metadata
  • {:error, reason} - Error discovering authorization server

get_authorization_server_metadata(issuer)

@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

get_key()

@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.Error if the private_key or key_id configuration is missing

Examples

key = OAuth.get_key()
key = OAuth.get_key()

refresh_token(refresh_token, dpop_key, issuer, token_endpoint)

request_protected_dpop_resource(request, issuer, access_token, dpop_key, nonce \\ nil)

@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()}

send_oauth_dpop_request(request, dpop_key, nonce \\ nil)

@spec send_oauth_dpop_request(Req.Request.t(), JOSE.JWK.t(), String.t() | nil) ::
  {:ok, map(), String.t()} | {:error, any(), String.t()}

validate_authorization_code(authz_metadata, dpop_key, code, code_verifier)

@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 endpoint
  • dpop_key - JWK for DPoP token generation
  • code - Authorization code from OAuth callback
  • code_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