ANProto over ATProto -- using Bluesky PDSes to store ANProto messages and blobs
1# Architecture
2
3This reference app follows a standard server-side OAuth flow suited for a backend (Node.js/Express) application.
4
5## Components
6
71. **Express Server (`src/index.ts`)**
8 - Host web endpoints (`/`, `/login`, `/oauth/callback`).
9 - Manages the browser session (cookie-based) using `iron-session`.
10 - NOTE: The browser session is *separate* from the OAuth session. The browser session just remembers "Who is logged in here?" (by storing the DID).
11
122. **OAuth Client (`src/client.ts`)**
13 - Instance of `NodeOAuthClient`.
14 - Manages the complexity of the handshake, token exchanges, and key management (DPoP).
15 - Uses `client-metadata` to define itself to the world (redirect URIs, etc.).
16
173. **Storage Adapters (`src/storage.ts`)**
18 - **State Store**: Temporarily stores the random `state` parameter generated during the login request to prevent CSRF.
19 - **Session Store**: Persists the actual Access and Refresh tokens (the "OAuth Session") mapped to the user's DID.
20
214. **Database (`src/db.ts`)**
22 - A simple SQLite database to back the Storage Adapters.
23 - In a real app, this would be Postgres, Redis, etc.
24
25## The Flow
26
271. **Initiation**:
28 - User enters Handle.
29 - App calls `client.authorize(handle)`.
30 - App redirects User to the PDS (e.g., bsky.social login page).
312. **Authentication**:
32 - User logs in at the PDS.
33 - User approves the app.
343. **Callback**:
35 - PDS redirects User back to `/oauth/callback?code=...`.
36 - App calls `client.callback(params)`.
37 - `client` exchanges `code` for `tokens`.
38 - `client` saves tokens to `SessionStore`.
39 - App saves `session.did` to the browser cookie.
404. **Usage**:
41 - On subsequent requests, App reads DID from browser cookie.
42 - App loads OAuth tokens from `SessionStore` using the DID.
43 - App creates an `Agent` to make API calls.