Verify Firebase auth tokens in Cloudflare workers

2 min read

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}`)

firebase auth cloudflare workers verify JWT in cloudflare workers

Related

  1. Scraping webpages