Skip to content

Instantly share code, notes, and snippets.

@azechi
Created June 7, 2022 01:08
Show Gist options
  • Save azechi/303a1539b01bb2d98ffe4767d85837e6 to your computer and use it in GitHub Desktop.
Save azechi/303a1539b01bb2d98ffe4767d85837e6 to your computer and use it in GitHub Desktop.
Call Firebase Admin APIs in Cloudflare Workers
export interface Env {
project_id: string;
private_key: string;
client_email: string;
private_key_id: string;
}
export default {
async fetch(
_request: Request,
env: Env,
_ctx: ExecutionContext
): Promise<Response> {
const aud = "https://identitytoolkit.googleapis.com/";
const key = await importKey(env.private_key);
const jwt = await makeJwt(aud, key, env.client_email, env.private_key_id);
const resp = await fetch(
`https://identitytoolkit.googleapis.com/v1/projects/${env.project_id}/accounts:query`,
{
headers: {
Authorization: `Bearer ${jwt}`,
Accept: "application/json",
"Content-Type": "application/json",
},
body: "{}",
method: "POST",
}
);
return new Response(await resp.text());
},
};
function importKey(pem: string) {
const HEADER = "-----BEGIN PRIVATE KEY-----\n";
const FOOTER = "-----END PRIVATE KEY-----\n";
const contents = pem.substring(HEADER.length, pem.length - FOOTER.length);
const der = new Uint8Array(
(function* (s) {
for (let i = 0, len = s.length; i < len; i++) {
yield s.charCodeAt(i);
}
})(atob(contents))
);
return crypto.subtle.importKey(
"pkcs8",
der,
{
name: "RSASSA-PKCS1-v1_5",
hash: { name: "SHA-256" },
},
true,
["sign"]
);
}
function base64UrlEncode(s: string) {
return btoa(s).replace(
/\/|\+|=/g,
(m) => ({ "/": "_", "+": "-", "=": "" }[m] as string)
);
}
async function makeJwt(
aud: string,
key: CryptoKey,
client_email: string,
private_key_id: string
) {
const iat = Math.floor(Date.now() / 1000);
const exp = iat + 3600;
const payload = base64UrlEncode(
JSON.stringify({
iss: client_email,
sub: client_email,
aud: aud,
iat: iat,
exp: exp,
})
);
const header = base64UrlEncode(
JSON.stringify({
typ: "JWT",
alg: "RS256",
kid: private_key_id,
})
);
const signature = await crypto.subtle.sign(
{
name: "RSASSA-PKCS1-v1_5",
hash: { name: "SHA-256" },
},
key,
new TextEncoder().encode(`${header}.${payload}`)
);
const sign = base64UrlEncode(
String.fromCharCode(...new Uint8Array(signature))
);
return `${header}.${payload}.${sign}`;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment