A method to verify firebase auth tokens in Cloudflare workers. As of Dec, 2022, this works in Cloudflare workers, inside javascript V8 engine without the full nodejs runtime or firebase SDK.
/*
A method to verify firebase auth tokens in Cloudflare workers.
As of Dec, 2022, this works in Cloudflare workers, inside javascript V8 engine without the full nodejs runtime or firebase SDK.
*/
function _parseBase64Url(url) {
return new Uint8Array(Array.prototype.map.call(atob(url.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, '')), c => c.charCodeAt(0)))
}
function _utf8ToUint8Array(str) {
return _parseBase64Url(btoa(unescape(encodeURIComponent(str))))
}
async function _getFirebasePubKeys() {
const r = await fetch('https://www.googleapis.com/service_accounts/v1/jwk/[email protected]')
return await r.json()
}
async function verify(token, expectAud, expectIss) {
const payload = decode(token)
if (payload.exp <= Math.floor(Date.now() / 1000)) {
return false
}
if (payload.aud != expectAud || payload.iss != expectIss) {
return false
}
const pubKeys = await _getFirebasePubKeys()
const tokenParts = token.split('.')
const header = JSON.parse(atob(tokenParts[0]))
const keyData = pubKeys.keys.find(key => key.kid == header.kid)
const alg = { name: 'RSASSA-PKCS1-v1_5', hash: { name: 'SHA-256' } }
const key = await crypto.subtle.importKey('jwk', keyData, alg, false, ['verify'])
return await crypto.subtle.verify(alg, key, _parseBase64Url(tokenParts[2]), _utf8ToUint8Array(`${tokenParts[0]}.${tokenParts[1]}`))
}
function _decodePayload(raw) {
switch (raw.length % 4) {
case 0:
break
case 2:
raw += '=='
break
case 3:
raw += '='
break
default:
throw new Error('Illegal base64url string!')
}
try {
return JSON.parse(decodeURIComponent(escape(atob(raw))))
} catch {
return null
}
}
function decode(token) {
return _decodePayload(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'))
}
// To verify a JWT, pass token along with 'Audience' and 'Issuer' based on your Firebase project id
verify(token, FIREBASE_PROJECT_ID, `https://securetoken.google.com/${FIREBASE_PROJECT_ID}`)