A set of utilities for working with the AT Protocol in Elixir.
at main 2.9 kB view raw
1defmodule ExampleOAuthPlug do 2 require Logger 3 use Plug.Router 4 use Plug.ErrorHandler 5 alias Atex.OAuth 6 alias Atex.XRPC 7 8 plug :put_secret_key_base 9 10 plug Plug.Session, 11 store: :cookie, 12 key: "atex-oauth", 13 signing_salt: "signing-salt" 14 15 plug :match 16 plug :dispatch 17 18 forward "/oauth", to: Atex.OAuth.Plug, init_opts: [callback: {__MODULE__, :oauth_callback, []}] 19 20 def oauth_callback(conn) do 21 IO.inspect(conn, label: "callback from oauth!") 22 23 conn 24 |> put_resp_header("Location", "/whoami") 25 |> resp(307, "") 26 |> send_resp() 27 end 28 29 get "/whoami" do 30 conn = fetch_session(conn) 31 32 case XRPC.OAuthClient.from_conn(conn) do 33 {:ok, client} -> 34 send_resp(conn, 200, "hello #{client.did}") 35 36 :error -> 37 send_resp(conn, 401, "Unauthorized") 38 end 39 end 40 41 get "/create-post" do 42 conn = fetch_session(conn) 43 44 with {:ok, client} <- XRPC.OAuthClient.from_conn(conn), 45 {:ok, response, client} <- 46 XRPC.post(client, %Com.Atproto.Repo.CreateRecord{ 47 input: %Com.Atproto.Repo.CreateRecord.Input{ 48 repo: client.did, 49 collection: "app.bsky.feed.post", 50 rkey: Atex.TID.now() |> to_string(), 51 record: %{ 52 "$type": "app.bsky.feed.post", 53 text: "Hello world from atex!", 54 createdAt: DateTime.to_iso8601(DateTime.utc_now()) 55 } 56 } 57 }) do 58 IO.inspect(response, label: "output") 59 60 send_resp(conn, 200, response.body.uri) 61 else 62 :error -> 63 send_resp(conn, 401, "Unauthorized") 64 65 {:error, :reauth} -> 66 send_resp(conn, 401, "session expired but still in your cookie") 67 68 err -> 69 IO.inspect(err, label: "xrpc failed") 70 send_resp(conn, 500, "xrpc failed") 71 end 72 end 73 74 match _ do 75 send_resp(conn, 404, "oops") 76 end 77 78 def put_secret_key_base(conn, _) do 79 put_in( 80 conn.secret_key_base, 81 # Don't use this in production 82 "5ef1078e1617463a3eb3feb9b152e76587a75a6809e0485a125b6bb7ae468f086680771f700d77ff61dfdc8d8ee8a5c7848024a41cf5ad4b6eb3115f74ce6e46" 83 ) 84 end 85 86 # Error handler for OAuth exceptions 87 @impl Plug.ErrorHandler 88 def handle_errors(conn, %{kind: :error, reason: %Atex.OAuth.Error{} = error, stack: _stack}) do 89 status = 90 case error.reason do 91 reason 92 when reason in [ 93 :missing_handle, 94 :invalid_handle, 95 :invalid_callback_request, 96 :issuer_mismatch 97 ] -> 98 400 99 100 _ -> 101 500 102 end 103 104 conn 105 |> put_resp_content_type("text/plain") 106 |> send_resp(status, error.message) 107 end 108 109 # Fallback for other errors 110 def handle_errors(conn, %{kind: _kind, reason: _reason, stack: _stack}) do 111 send_resp(conn, conn.status, "Something went wrong") 112 end 113end