# AshAtproto
Ash utilities built on top of [atex](https://tangled.org/comet.sh/atex) to make integrating with ATProto easier. It includes:
- An Ash extension that provides resource actions and attributes for an user.
- An `AshAuthentication` strategy to enable the OAuth flow.
- AN XRPC client to make requests using an user resource.
## Installation
The package can be installed by adding `ash_atproto` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:ash_atproto, "~> 0.1.0"}
]
end
```
## User resource extension
This extension modifies your resource to add the following attributes:
- `:did`: an user's DID. This will be used as a primary key.
- `:handle`: an user's handle. This is cached for easier access, but it can become stale.
- `:oauth_tokens`: a struct with the OAuth response data.
These attributes can be overridden if necessary, and new attributes can be added with no issues.
It also includes the following actions:
- `:register_with_atproto`: upsert used for both registers and sign ins.
- `:refresh`: updates the `:oauth_tokens` attribute.
- `:read`
- `:destroy`
### Example
```elixir
defmodule MyApp.Accounts.User do
use Ash.Resource,
otp_app: :my_app,
domain: MyApp.Accounts,
authorizers: [Ash.Policy.Authorizer],
extensions: [AshAuthentication, AshAtproto.Auth, AshAtproto.UserResource],
data_layer: AshPostgres.DataLayer
authentication do
tokens do
enabled? true
require_token_presence_for_authentication? true
token_resource MyApp.Accounts.Token
signing_secret MyApp.Secrets
store_all_tokens? true
end
strategies do
atproto do
registration_enabled? true
base_url MyApp.Secrets
private_key MyApp.Secrets
key_id(MyApp.Secrets)
end
end
end
postgres do
table "users"
repo MyApp.Repo
end
actions do
read :get_by_subject do
description "Get a user by the subject claim in a JWT"
argument :subject, :string, allow_nil?: false
get? true
prepare AshAuthentication.Preparations.FilterBySubject
end
end
policies do
bypass AshAuthentication.Checks.AshAuthenticationInteraction do
authorize_if always()
end
policy always() do
forbid_if always()
end
end
end
```
## AshAuthentication strategy
A strategy that enables seamless integration with the rest of [AshAuthentication](https://hexdocs.pm/ash_authentication/get-started.html). The atproto strategy is standalone, and can be used without the user resource extension (replacing it with `AshAuthentication.UserIdentity`, for example).
### Example
```elixir
use Ash.Resource,
extensions: [AshAuthentication, AshAtproto.Auth],
strategies do
atproto do
registration_enabled? true
base_url MyApp.Secrets
private_key MyApp.Secrets
key_id(MyApp.Secrets)
end
end
```
Configuration values can be passed directly, but using [AshAuthentication.Secret](https://hexdocs.pm/ash_authentication/AshAuthentication.Secret.html) is recommended.
## OAuth client
An HTTP API client that follows the [XRPC](https://atproto.com/specs/xrpc) conventions. Will automatically refresh tokens if needed.
### Example
```elixir
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"]
)
```
For more details, including lexicon code generation and typed parameters, check the [Atex.XRPC](https://hexdocs.pm/atex/Atex.XRPC.html) module.
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) and published on [HexDocs](https://hexdocs.pm). Once published, the docs can be found at <https://hexdocs.pm/ash_atproto>.