this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Prepare for production

+69 -5
+18
app/.well-known/jwks.json/route.ts
··· 1 + import { NextResponse } from "next/server"; 2 + import { JoseKey } from "@atproto/oauth-client-node"; 3 + 4 + // Serves the public keys for the OAuth client 5 + // Required for confidential clients using private_key_jwt authentication 6 + 7 + const PRIVATE_KEY = process.env.PRIVATE_KEY; 8 + 9 + export async function GET() { 10 + if (!PRIVATE_KEY) { 11 + return NextResponse.json({ keys: [] }); 12 + } 13 + 14 + const key = await JoseKey.fromJWK(JSON.parse(PRIVATE_KEY)); 15 + return NextResponse.json({ 16 + keys: [key.publicJwk], 17 + }); 18 + }
+40 -4
lib/auth/client.ts
··· 1 + 1 2 import { 2 3 NodeOAuthClient, 3 4 buildAtprotoLoopbackClientMetadata, 5 + JoseKey, 6 + Keyset, 4 7 } from "@atproto/oauth-client-node"; 5 8 import type { 6 9 NodeSavedSession, 7 10 NodeSavedState, 11 + OAuthClientMetadataInput, 8 12 } from "@atproto/oauth-client-node"; 9 13 import { getDb } from "../db"; 10 14 ··· 18 22 globalAuth.stateStore ??= new Map(); 19 23 globalAuth.sessionStore ??= new Map(); 20 24 25 + const PUBLIC_URL = process.env.PUBLIC_URL; 26 + const PRIVATE_KEY = process.env.PRIVATE_KEY; 27 + 21 28 let client: NodeOAuthClient | null = null; 22 29 30 + function getClientMetadata(): OAuthClientMetadataInput { 31 + if (PUBLIC_URL) { 32 + return { 33 + client_id: `${PUBLIC_URL}/oauth-client-metadata.json`, 34 + client_name: "indiemusi.ch", 35 + client_uri: PUBLIC_URL, 36 + redirect_uris: [`${PUBLIC_URL}/oauth/callback`], 37 + grant_types: ["authorization_code", "refresh_token"], 38 + response_types: ["code"], 39 + scope: SCOPE, 40 + token_endpoint_auth_method: "private_key_jwt" as const, 41 + token_endpoint_auth_signing_alg: "ES256" as const, // must match the alg in scripts/gen-key.ts 42 + jwks_uri: `${PUBLIC_URL}/.well-known/jwks.json`, 43 + dpop_bound_access_tokens: true, 44 + }; 45 + } else { 46 + return buildAtprotoLoopbackClientMetadata({ 47 + scope: SCOPE, 48 + redirect_uris: ["http://127.0.0.1:3000/oauth/callback"], 49 + }); 50 + } 51 + } 52 + 53 + async function getKeyset(): Promise<Keyset | undefined> { 54 + if (PUBLIC_URL && PRIVATE_KEY) { 55 + return new Keyset([await JoseKey.fromJWK(JSON.parse(PRIVATE_KEY))]); 56 + } else { 57 + return undefined; 58 + } 59 + } 60 + 23 61 export async function getOAuthClient(): Promise<NodeOAuthClient> { 24 62 if (client) return client; 25 63 26 64 client = new NodeOAuthClient({ 27 - clientMetadata: buildAtprotoLoopbackClientMetadata({ 28 - scope: SCOPE, 29 - redirect_uris: ["http://127.0.0.1:3000/oauth/callback"], 30 - }), 65 + clientMetadata: getClientMetadata(), 66 + keyset: await getKeyset(), 31 67 32 68 stateStore: { 33 69 async get(key: string) {
+2 -1
package.json
··· 7 7 "build": "next build", 8 8 "start": "pnpm migrate && next start", 9 9 "lint": "eslint", 10 - "migrate": "tsx scripts/migrate.ts" 10 + "migrate": "tsx scripts/migrate.ts", 11 + "gen-key": "tsx scripts/gen-key.ts" 11 12 }, 12 13 "dependencies": { 13 14 "@atproto/lex": "^0.0.20",
+9
scripts/gen-key.ts
··· 1 + import { JoseKey } from "@atproto/oauth-client-node"; 2 + 3 + async function main() { 4 + const kid = Date.now().toString(); 5 + const key = await JoseKey.generate(["ES256"], kid); 6 + console.log(JSON.stringify(key.privateJwk)); 7 + }; 8 + 9 + main();