Atex.OAuth.Plug (atex v0.7.1)
View SourcePlug router for handling AT Protocol's OAuth flow.
This module provides three endpoints:
GET /login?handle=<handle>- Initiates the OAuth authorization flow for a given handleGET /callback- Handles the OAuth callback after user authorizationGET /client-metadata.json- Serves the OAuth client metadata
Usage
This module requires Plug.Session to be in your pipeline, as well as
secret_key_base to have been set on your connections. Ideally it should be
routed to via Plug.Router.forward/2, under a route like "/oauth".
The plug requires a :callback option that must be an MFA tuple (Module,
Function, Args). This callback is invoked after successful OAuth
authentication, receiving the connection with the authenticated session data.
Error Handling
Atex.OAuth.Error exceptions are raised when errors occur during the OAuth
flow (e.g. an invalid handle is provided, or validation failed). You should
implement a Plug.ErrorHandler to catch and handle these exceptions
gracefully.
Example
Example implementation showing how to set up the OAuth plug with proper session handling, error handling, and a callback function.
defmodule ExampleOAuthPlug do
use Plug.Router
use Plug.ErrorHandler
plug :put_secret_key_base
plug Plug.Session,
store: :cookie,
key: "atex-oauth",
signing_salt: "signing-salt"
plug :match
plug :dispatch
forward "/oauth", to: Atex.OAuth.Plug, init_opts: [callback: {__MODULE__, :oauth_callback, []}]
def oauth_callback(conn) do
# Handle successful OAuth authentication
conn
|> put_resp_header("Location", "/dashboard")
|> resp(307, "")
|> send_resp()
end
def put_secret_key_base(conn, _) do
put_in(
conn.secret_key_base,
"very long key base with at least 64 bytes"
)
end
# Error handler for OAuth exceptions
@impl Plug.ErrorHandler
def handle_errors(conn, %{kind: :error, reason: %Atex.OAuth.Error{} = error, stack: _stack}) do
status = case error.reason do
reason when reason in [:missing_handle, :invalid_handle, :invalid_callback_request, :issuer_mismatch] -> 400
_ -> 500
end
conn
|> put_resp_content_type("text/plain")
|> send_resp(status, error.message)
end
# Fallback for other errors
def handle_errors(conn, %{kind: _kind, reason: _reason, stack: _stack}) do
send_resp(conn, conn.status, "Something went wrong")
end
endSession Storage
After successful authentication, the plug stores these in the session:
:tokens- The access token response containing access_token, refresh_token, did, and expires_at:dpop_nonce-:dpop_key- The DPoP JWK for generating DPoP proofs
Summary
Functions
Callback implementation for Plug.call/2.
Callback implementation for Plug.init/1.