# Authentication Quickslice proxies OAuth between your app and users' Personal Data Servers (PDS). Your app never handles AT Protocol credentials directly. ## How It Works 1. User clicks login in your app 2. Your app redirects to Quickslice's `/oauth/authorize` endpoint 3. Quickslice redirects to the user's PDS for authorization 4. User enters credentials and approves your app 5. PDS redirects back to Quickslice with an auth code 6. Quickslice exchanges the code for tokens 7. Quickslice redirects back to your app with a code 8. Your app exchanges the code for an access token The access token authorizes mutations that write to the user's repository. ## Setting Up OAuth ### Generate a Signing Key Quickslice needs a private key to sign OAuth tokens. Generate one with `goat`: ```bash brew install goat goat key generate -t p256 ``` Set the output as your `OAUTH_SIGNING_KEY` environment variable. ### Register an OAuth Client 1. Open your Quickslice instance and navigate to **Settings** 2. Scroll to **OAuth Clients** and click **Register New Client** 3. Fill in the form: - **Client Name**: Your app's name - **Client Type**: Public (browser apps) or Confidential (server apps) - **Redirect URIs**: Where users return after auth (e.g., `http://localhost:3000`) - **Scope**: Leave as `atproto transition:generic` 4. Copy the **Client ID** ### Public vs Confidential Clients | Type | Use Case | Secret | |------|----------|--------| | **Public** | Browser apps, mobile apps | No secret (client cannot secure it) | | **Confidential** | Server-side apps, backend services | Secret (stored securely on server) | ## Using the Client SDK The Quickslice client SDK handles OAuth, PKCE, DPoP, token refresh, and GraphQL requests. ### Install ```bash npm install quickslice-client-js ``` Or via CDN: ```html ``` ### Initialize ```javascript import { createQuicksliceClient } from 'quickslice-client'; const client = await createQuicksliceClient({ server: "https://yourapp.slices.network", clientId: "YOUR_CLIENT_ID", }); ``` ### Login ```javascript await client.loginWithRedirect({ handle: "alice.bsky.social", }); ``` ### Handle the Callback After authentication, the user returns to your redirect URI: ```javascript if (window.location.search.includes("code=")) { await client.handleRedirectCallback(); } ``` ### Check Authentication State ```javascript const isLoggedIn = await client.isAuthenticated(); if (isLoggedIn) { const user = client.getUser(); console.log(user.did); // "did:plc:abc123..." } ``` ### Logout ```javascript await client.logout(); ``` ## Making Authenticated Requests ### With the SDK The SDK adds authentication headers automatically: ```javascript // Public query (no auth needed) const data = await client.publicQuery(` query { xyzStatusphereStatus { edges { node { status } } } } `); // Authenticated query const viewer = await client.query(` query { viewer { did handle } } `); // Mutation (requires auth) const result = await client.mutate(` mutation { createXyzStatusphereStatus(input: { status: "🎉", createdAt: "${new Date().toISOString()}" }) { uri } } `); ``` ### Without the SDK Without the SDK, include headers based on your OAuth flow: **DPoP flow** (public clients): ``` Authorization: DPoP DPoP: ``` **Bearer token flow** (confidential clients): ``` Authorization: Bearer ``` ## The Viewer Query The `viewer` query returns the authenticated user: ```graphql query { viewer { did handle appBskyActorProfileByDid { displayName avatar { url } } } } ``` Returns `null` when not authenticated (no error thrown). ## Security: PKCE and DPoP The SDK implements two security mechanisms for browser apps: **PKCE (Proof Key for Code Exchange)** prevents authorization code interception. Before redirecting, the SDK generates a random secret and sends only its hash to the server. When exchanging the code for tokens, the SDK proves it initiated the request. **DPoP (Demonstrating Proof-of-Possession)** binds tokens to a cryptographic key in your browser. Each request includes a signed proof. An attacker who steals your access token cannot use it without the key. ## OAuth Endpoints - `GET /oauth/authorize` - Start the OAuth flow - `POST /oauth/token` - Exchange authorization code for tokens - `GET /.well-known/oauth-authorization-server` - Server metadata - `GET /oauth/oauth-client-metadata.json` - Client metadata