| 1 | import { JoseKey } from "@atproto/jwk-jose"; |
| 2 | import { OAuthClient } from "@atproto/oauth-client"; |
| 3 | import { AtprotoDohHandleResolver } from "@atproto-labs/handle-resolver"; |
| 4 | import { createStateStore, createSessionStore } from "./kv-stores"; |
| 5 | |
| 6 | export function createOAuthClient(kv: KVNamespace, clientUrl: string) { |
| 7 | const clientId = `${clientUrl}/oauth/client-metadata.json`; |
| 8 | const redirectUri = `${clientUrl}/oauth/callback`; |
| 9 | |
| 10 | return new OAuthClient({ |
| 11 | responseMode: "query", |
| 12 | handleResolver: new AtprotoDohHandleResolver({ |
| 13 | dohEndpoint: "https://cloudflare-dns.com/dns-query", |
| 14 | }), |
| 15 | clientMetadata: { |
| 16 | client_id: clientId, |
| 17 | client_name: "Sequoia", |
| 18 | client_uri: clientUrl, |
| 19 | redirect_uris: [redirectUri], |
| 20 | grant_types: ["authorization_code", "refresh_token"], |
| 21 | response_types: ["code"], |
| 22 | scope: "atproto site.standard.graph.subscription", |
| 23 | token_endpoint_auth_method: "none", |
| 24 | application_type: "web", |
| 25 | dpop_bound_access_tokens: true, |
| 26 | }, |
| 27 | runtimeImplementation: { |
| 28 | createKey: (algs: string[]) => JoseKey.generate(algs), |
| 29 | getRandomValues: (length: number) => |
| 30 | crypto.getRandomValues(new Uint8Array(length)), |
| 31 | digest: async (data: Uint8Array, { name }: { name: string }) => { |
| 32 | const buf = await crypto.subtle.digest( |
| 33 | name.replace("sha", "SHA-"), |
| 34 | new Uint8Array(data), |
| 35 | ); |
| 36 | return new Uint8Array(buf); |
| 37 | }, |
| 38 | requestLock: <T>(_name: string, fn: () => T | PromiseLike<T>) => fn(), |
| 39 | }, |
| 40 | stateStore: createStateStore(kv), |
| 41 | sessionStore: createSessionStore(kv), |
| 42 | }); |
| 43 | } |