the statusphere demo reworked into a vite/react app in a monorepo

setup to work as either loopback or internet-exposed client

+14 -38
+3 -5
.env.template
··· 2 2 NODE_ENV="development" # Options: 'development', 'production' 3 3 PORT="8080" # The port your server will listen on 4 4 HOST="localhost" # Hostname for the server 5 - PUBLIC_URL="https://localhost:8080" 5 + PUBLIC_URL="" 6 6 7 7 # CORS Settings 8 8 CORS_ORIGIN="http://localhost:*" # Allowed CORS origin, adjust as necessary ··· 12 12 COMMON_RATE_LIMIT_MAX_REQUESTS="20" # Max number of requests per window per IP 13 13 14 14 # Secrets 15 - # openssl rand -base64 33 16 - COOKIE_SECRET="" 17 - # openssl ecparam -name prime256v1 -genkey | openssl pkcs8 -topk8 -nocrypt | openssl base64 -A 18 - PRIVATE_KEY_ES256_B64="" 15 + # Must this in production. May be generated with `openssl rand -base64 33` 16 + # COOKIE_SECRET=""
+8 -20
src/auth/client.ts
··· 5 5 import { SessionStore, StateStore } from './storage' 6 6 7 7 export const createClient = async (db: Database) => { 8 - const url = env.PUBLIC_URL 9 - const privateKeyPKCS8 = Buffer.from(env.PRIVATE_KEY_ES256_B64, 'base64').toString() 10 - const privateKey = await JoseKey.fromImportable(privateKeyPKCS8, 'key1') 8 + const publicUrl = env.PUBLIC_URL 9 + const url = publicUrl || `http://127.0.0.1:${env.PORT}` 11 10 return new NodeOAuthClient({ 12 - // This object will be used to build the payload of the /client-metadata.json 13 - // endpoint metadata, exposing the client metadata to the OAuth server. 14 11 clientMetadata: { 15 - // Must be a URL that will be exposing this metadata 16 - client_id: `${url}/client-metadata.json`, 12 + client_name: 'AT Protocol Express App', 13 + client_id: publicUrl 14 + ? `${url}/client-metadata.json` 15 + : `http://localhost?redirect_uri=${encodeURIComponent(`${url}/oauth/callback`)}`, 17 16 client_uri: url, 18 - client_name: 'ATProto Express App', 19 - jwks_uri: `${url}/jwks.json`, 20 17 logo_uri: `${url}/logo.png`, 21 18 tos_uri: `${url}/tos`, 22 19 policy_uri: `${url}/policy`, 23 20 redirect_uris: [`${url}/oauth/callback`], 24 - token_endpoint_auth_signing_alg: 'ES256', 25 - scope: 'profile email offline_access', 21 + scope: 'profile offline_access', 26 22 grant_types: ['authorization_code', 'refresh_token'], 27 23 response_types: ['code'], 28 24 application_type: 'web', 29 - token_endpoint_auth_method: 'private_key_jwt', 25 + token_endpoint_auth_method: 'none', 30 26 dpop_bound_access_tokens: true, 31 27 }, 32 - 33 - // Used to authenticate the client to the token endpoint. Will be used to 34 - // build the jwks object to be exposed on the "jwks_uri" endpoint. 35 - keyset: [privateKey], 36 - 37 - // Interface to store authorization state data (during authorization flows) 38 28 stateStore: new StateStore(db), 39 - 40 - // Interface to store authenticated session data 41 29 sessionStore: new SessionStore(db), 42 30 }) 43 31 }
+2 -3
src/env.ts
··· 7 7 NODE_ENV: str({ devDefault: testOnly('test'), choices: ['development', 'production', 'test'] }), 8 8 HOST: host({ devDefault: testOnly('localhost') }), 9 9 PORT: port({ devDefault: testOnly(3000) }), 10 - PUBLIC_URL: str({ devDefault: testOnly('http://localhost:3000') }), 11 - COOKIE_SECRET: str(), 12 - PRIVATE_KEY_ES256_B64: str(), 10 + PUBLIC_URL: str({}), 11 + COOKIE_SECRET: str({ devDefault: '00000000000000000000000000000000' }), 13 12 CORS_ORIGIN: str({ devDefault: testOnly('http://localhost:3000') }), 14 13 COMMON_RATE_LIMIT_MAX_REQUESTS: num({ devDefault: testOnly(1000) }), 15 14 COMMON_RATE_LIMIT_WINDOW_MS: num({ devDefault: testOnly(1000) }),
+1 -1
src/firehose/ingester.ts
··· 1 - import type { Database } from '#/db/index' 1 + import type { Database } from '#/db' 2 2 import { Firehose } from '#/firehose/firehose' 3 3 4 4 export class Ingester {
-2
src/pages/login.ts
··· 1 - import { AtUri } from '@atproto/syntax' 2 - import type { Post } from '#/db/schema' 3 1 import { html } from '../view' 4 2 import { shell } from './shell' 5 3
-7
src/routes/index.ts
··· 12 12 const router = express.Router() 13 13 14 14 router.get( 15 - '/jwks.json', 16 - handler((_req, res) => { 17 - return res.json(ctx.oauthClient.jwks) 18 - }), 19 - ) 20 - 21 - router.get( 22 15 '/client-metadata.json', 23 16 handler((_req, res) => { 24 17 return res.json(ctx.oauthClient.clientMetadata)