Created
June 7, 2022 01:08
-
-
Save azechi/303a1539b01bb2d98ffe4767d85837e6 to your computer and use it in GitHub Desktop.
Call Firebase Admin APIs in Cloudflare Workers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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