Atex.XRPC.OAuthClient (atex v0.9.1)

View Source

OAuth client for making authenticated XRPC requests to AT Protocol servers.

The client holds a composite session key ("<did>:<nonce>") and talks to Atex.OAuth.SessionStore to retrieve sessions internally to make requests. It only works for users that have completed an OAuth flow; see Atex.OAuth.Plug for an existing method of doing that.

The entire OAuth session lifecycle is handled transparently, with the access token being refreshed automatically as required.

Usage

# Create from an existing composite session key
{:ok, client} = Atex.XRPC.OAuthClient.new("did:plc:abc123:device-nonce")

# Or extract from a Plug.Conn after OAuth flow
{:ok, client} = Atex.XRPC.OAuthClient.from_conn(conn)

# Retrieve just the DID from a client
"did:plc:abc123" = Atex.XRPC.OAuthClient.did(client)

# Make XRPC requests
{:ok, response, client} = Atex.XRPC.get(client, "com.atproto.repo.listRecords")

Summary

Functions

Returns the DID portion of the client's composite session key.

Create an OAuthClient from a Plug.Conn.

Make a GET request to an XRPC endpoint.

Create a new OAuthClient from a composite session key ("<did>:<nonce>").

Make a POST request to an XRPC endpoint.

Ask the client's OAuth server for a new set of auth tokens.

Types

t()

@type t() :: %Atex.XRPC.OAuthClient{session_key: String.t()}

Functions

did(o_auth_client)

@spec did(t()) :: String.t()

Returns the DID portion of the client's composite session key.

The session key has the form "<did>:<nonce>". This function extracts and returns everything up to the final : separator, which is the user's DID.

Examples

iex> client = %Atex.XRPC.OAuthClient{session_key: "did:plc:abc123:mynonce"}
iex> Atex.XRPC.OAuthClient.did(client)
"did:plc:abc123"

from_conn(conn)

@spec from_conn(Plug.Conn.t()) :: {:ok, t()} | :error | {:error, atom()}

Create an OAuthClient from a Plug.Conn.

Reads the active session key from conn.session (stored under :atex_active_session) and validates that the OAuth session is still valid. If the token is expired or expiring soon, it attempts to refresh it.

Requires the conn to have passed through Plug.Session and Plug.Conn.fetch_session/2.

Returns

  • {:ok, client} - Successfully created client
  • {:error, :reauth} - Session exists but refresh failed; user needs to re-authenticate
  • :error - No active session found in conn

Examples

# After OAuth flow completes
{:ok, client} = Atex.XRPC.OAuthClient.from_conn(conn)

get(client, resource, opts \\ [])

Make a GET request to an XRPC endpoint.

See Atex.XRPC.get/3 for details.

new(session_key)

@spec new(String.t()) :: {:ok, t()} | {:error, atom()}

Create a new OAuthClient from a composite session key ("<did>:<nonce>").

Validates that an OAuth session exists for the given key in the session store before returning the client struct.

Examples

iex> Atex.XRPC.OAuthClient.new("did:plc:abc123:mynonce")
{:ok, %Atex.XRPC.OAuthClient{session_key: "did:plc:abc123:mynonce"}}

iex> Atex.XRPC.OAuthClient.new("did:plc:nosession:nonce")
{:error, :not_found}

post(client, resource, opts \\ [])

Make a POST request to an XRPC endpoint.

See Atex.XRPC.post/3 for details.

refresh(client)

@spec refresh(client :: t()) :: {:ok, Atex.OAuth.Session.t()} | {:error, any()}

Ask the client's OAuth server for a new set of auth tokens.

Fetches the session, refreshes the tokens, creates a new session with the updated tokens, stores it, and returns the new session.

You shouldn't need to call this manually for the most part, the client does its best to refresh automatically when it needs to.

This function acquires a lock on the session to prevent concurrent refresh attempts.