this repo has no description
1/**
2 * Generate an ES256 (P-256) keypair as JWKs for the atproto OAuth
3 * confidential client. Prints two env-var assignments:
4 * - OAUTH_PRIVATE_JWK (set in production secrets; never check in)
5 * - OAUTH_PUBLIC_JWK (used by /oauth/jwks.json)
6 *
7 * Usage:
8 * deno run --allow-read --allow-env scripts/generate-oauth-key.ts
9 */
10const KEY_USE_SIG = "sig";
11const ALG = "ES256";
12
13function bufToBase64Url(buf: ArrayBuffer): string {
14 const bytes = new Uint8Array(buf);
15 let binary = "";
16 for (const b of bytes) binary += String.fromCharCode(b);
17 return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(
18 /=+$/,
19 "",
20 );
21}
22
23async function main(): Promise<void> {
24 const keyPair = await crypto.subtle.generateKey(
25 { name: "ECDSA", namedCurve: "P-256" },
26 true,
27 ["sign", "verify"],
28 );
29
30 const privateJwk = await crypto.subtle.exportKey("jwk", keyPair.privateKey);
31 const publicJwk = await crypto.subtle.exportKey("jwk", keyPair.publicKey);
32
33 const kid = bufToBase64Url(crypto.getRandomValues(new Uint8Array(8)).buffer)
34 .slice(0, 12);
35
36 const enrich = (jwk: JsonWebKey): JsonWebKey =>
37 ({
38 ...jwk,
39 use: KEY_USE_SIG,
40 alg: ALG,
41 kid,
42 }) as JsonWebKey;
43
44 const priv = enrich(privateJwk);
45 const pub = enrich(publicJwk);
46
47 console.log("# Add the following to your environment.");
48 console.log("# - For .env / .env.local: paste the lines below as-is.");
49 console.log(
50 "# - For Deno Deploy / Vercel project secrets: paste only the value",
51 );
52 console.log(
53 "# to the right of '=' (the raw JSON object including the braces).",
54 );
55 console.log("# DO NOT commit OAUTH_PRIVATE_JWK to source control.\n");
56 /** Print values WITHOUT shell quotes. The raw JSON has no whitespace
57 * (JSON.stringify packs tightly) so it's a valid bare value for any
58 * reasonable .env parser, and it removes any temptation to strip
59 * surrounding quotes (which several users have accidentally done by
60 * also stripping the leading `{` / trailing `}`). */
61 console.log(`OAUTH_PRIVATE_JWK=${JSON.stringify(priv)}`);
62 console.log(`OAUTH_PUBLIC_JWK=${JSON.stringify(pub)}`);
63 console.log(`OAUTH_KID=${kid}`);
64 console.log();
65 console.log(
66 "# Optional: a 32+ byte random string for signing session cookies.",
67 );
68 const secret = bufToBase64Url(
69 crypto.getRandomValues(new Uint8Array(32)).buffer,
70 );
71 console.log(`SESSION_SECRET=${secret}`);
72}
73
74if (import.meta.main) {
75 await main();
76}