a tool for shared writing and social publishing
at update/delete-leaflets 92 lines 2.9 kB view raw
1import { 2 NodeOAuthClient, 3 NodeSavedSession, 4 NodeSavedState, 5 RuntimeLock, 6} from "@atproto/oauth-client-node"; 7import { JoseKey } from "@atproto/jwk-jose"; 8import { oauth_metadata } from "app/api/oauth/[route]/oauth-metadata"; 9import { supabaseServerClient } from "supabase/serverClient"; 10 11import Client from "ioredis"; 12import Redlock from "redlock"; 13export async function createOauthClient() { 14 let keyset = 15 process.env.NODE_ENV === "production" 16 ? await Promise.all([ 17 JoseKey.fromImportable(process.env.JOSE_PRIVATE_KEY_1!), 18 ]) 19 : undefined; 20 let requestLock: RuntimeLock | undefined; 21 if (process.env.NODE_ENV === "production" && process.env.REDIS_URL) { 22 const client = new Client(process.env.REDIS_URL); 23 const redlock = new Redlock([client]); 24 requestLock = async (key, fn) => { 25 // 30 seconds should be enough. Since we will be using one lock per user id 26 // we can be quite liberal with the lock duration here. 27 const lock = await redlock.acquire([key], 45e3); 28 try { 29 return await fn(); 30 } finally { 31 await lock.release(); 32 } 33 }; 34 } 35 return new NodeOAuthClient({ 36 // This object will be used to build the payload of the /client-metadata.json 37 // endpoint metadata, exposing the client metadata to the OAuth server. 38 clientMetadata: oauth_metadata, 39 40 // Used to authenticate the client to the token endpoint. Will be used to 41 // build the jwks object to be exposed on the "jwks_uri" endpoint. 42 keyset, 43 44 // Interface to store authorization state data (during authorization flows) 45 stateStore, 46 // Interface to store authenticated session data 47 sessionStore, 48 requestLock, 49 }); 50} 51 52let stateStore = { 53 async set(key: string, state: NodeSavedState): Promise<void> { 54 await supabaseServerClient.from("oauth_state_store").upsert({ key, state }); 55 }, 56 async get(key: string): Promise<NodeSavedState | undefined> { 57 let { data } = await supabaseServerClient 58 .from("oauth_state_store") 59 .select("state") 60 .eq("key", key) 61 .single(); 62 return (data?.state as NodeSavedState) || undefined; 63 }, 64 async del(key: string): Promise<void> { 65 await supabaseServerClient 66 .from("oauth_state_store") 67 .delete() 68 .eq("key", key); 69 }, 70}; 71 72let sessionStore = { 73 async set(key: string, session: NodeSavedSession): Promise<void> { 74 await supabaseServerClient 75 .from("oauth_session_store") 76 .upsert({ key, session }); 77 }, 78 async get(key: string): Promise<NodeSavedSession | undefined> { 79 let { data } = await supabaseServerClient 80 .from("oauth_session_store") 81 .select("session") 82 .eq("key", key) 83 .single(); 84 return (data?.session as NodeSavedSession) || undefined; 85 }, 86 async del(key: string): Promise<void> { 87 await supabaseServerClient 88 .from("oauth_session_store") 89 .delete() 90 .eq("key", key); 91 }, 92};