# `AshAtproto.XRPC.OAuthClient`

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

The client contains an Ash resource that uses the `AshAtproto.UserResource` extension to store sessions to make requests. As a result, it will only work for users that have gone through an OAuth flow; see `AshAuthentication.Strategy,` for an existing method of doing that through AshAuthentication.

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

The client's state can change if the token is refreshed, so make sure you update the client if the value is returned and you plan to reuse it.

## Usage

    # Create from a resource
    user_resource = Ash.read_one!(MyApp.Accounts.User, authorize?: false)
    {:ok, client} = AshAtproto.XRPC.OAuthClient.new(user_resource)

    # Make XRPC requests
    {:ok, response, client} =
      Atex.XRPC.get(client, "com.atproto.repo.listRecords",
        params: [repo: user.handle, collection: "app.bsky.graph.follow"]
      )

# `t`

```elixir
@type t() :: %AshAtproto.XRPC.OAuthClient{
  resource: Ash.Resource.t(),
  strategy: AshAtproto.Auth.t()
}
```

# `get`

Make a GET request to an XRPC endpoint.

See `Atex.XRPC.get/3` for details.

# `new`

```elixir
@spec new(Ash.Resource.t()) :: {:ok, t()} | {:error, atom()}
```

Create a new OAuthClient from an user resource. The resource must be using `AshAuthentication.Strategy`, otherwise the client will crash when it tries to access secrets. A strategy struct can be passed directly, if needed, avoiding the crash.

## Examples

    iex> user_resource = Ash.read_one!(MyApp.Accounts.User, authorize?: false)
    %MyApp.Accounts.User{
      did: "did:plc:dgzvruva4jbzqbta335jtvoz",
      handle: "lekkice.moe",
      ...
    }
    iex> {:ok, client} = AshAtproto.XRPC.OAuthClient.new(user_resource)
    {:ok,
     %AshAtproto.XRPC.OAuthClient{
       resource: %MyApp.Accounts.User{
         did: "did:plc:dgzvruva4jbzqbta335jtvoz",
         handle: "lekkice.moe",
         ...
       }
     }}

# `new`

```elixir
@spec new(Ash.Resource.t(), AshAtproto.Auth.t()) :: {:ok, t()} | {:error, atom()}
```

# `post`

Make a POST request to an XRPC endpoint.

See `Atex.XRPC.post/3` for details.

# `refresh`

```elixir
@spec refresh(client :: t()) :: {:ok, t()} | {:error, any()}
```

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

Refreshes the tokens, persists the new tokens, then returns the updated resource.

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.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
