tsndr / cloudflare-worker-jwt

A lightweight JWT implementation with ZERO dependencies for Cloudflare Workers.
MIT License
649 stars 51 forks source link

jwt.verify() always evaluates as false for Google-issued JWT when using certificate verification #46

Closed johnswarbrick closed 10 months ago

johnswarbrick commented 10 months ago

Hi -

Using @tsndr/cloudflare-worker-jwt@2.2.7 I always get false when trying to verify a Google-issued JWT with a certificate.

This is basically the same issue as https://github.com/tsndr/cloudflare-worker-jwt/issues/28 logged by @zombobot1

I'm using JWTs and certificates issued by Google firebase. The certificates are provided here:

https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com

I'm extracting the kid from the JWT and using that to match with the specific certificate that should be used to validate the JWT.

I tried using the raw certificate as supplied by Google, tried removing the -----BEGIN CERTIFICATE----- prefix/suffix and tried removing line feeds but it always verifies as false.

Rather than supplying my own JWT/certificate I've re-used those from the previously raised ticket.

Would really appreciate some help with this one!

async function test() {
  const token = `eyJhbGciOiJSUzI1NiIsImtpZCI6ImE5NmFkY2U5OTk5YmJmNWNkMzBmMjlmNDljZDM3ZjRjNWU2NDI3NDAiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiQWxpIE9tYXJvdiIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS0vQUZkWnVjcVdlUWd0RnE1cVZBcDJyOC1pbU8yeVhmVXUySWhBZktGWU5PZVA9czk2LWMiLCJpbml0ViI6MSwicm9sZSI6ImFkbWluIiwiYWNjb3VudCI6ImFkbWluIiwiaXNzIjoiaHR0cHM6Ly9zZWN1cmV0b2tlbi5nb29nbGUuY29tL3VuaXZlcnNlLTU1Y2VjIiwiYXVkIjoidW5pdmVyc2UtNTVjZWMiLCJhdXRoX3RpbWUiOjE2NjgwNDM3MTIsInVzZXJfaWQiOiJZWkZQN25RT28xUnNFakJqSjRzZHlzdWFQU28yIiwic3ViIjoiWVpGUDduUU9vMVJzRWpCako0c2R5c3VhUFNvMiIsImlhdCI6MTY2OTc0MDE4NywiZXhwIjoxNjY5NzQzNzg3LCJlbWFpbCI6ImFsaWsub21hcm92MzAwMEBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJnb29nbGUuY29tIjpbIjEwNzY5NjU3NjE2NTExNjE5MDgzNyJdLCJlbWFpbCI6WyJhbGlrLm9tYXJvdjMwMDBAZ21haWwuY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoiZ29vZ2xlLmNvbSJ9fQ.TJ6XeEcR3dtG-bVRDKrA4FXPN-v_U2c_HGRMWLc57Qg5lMt8sNYEhKWmFkrcoslSHPhKDRqQOD5JQlrVIgNzJoQY7pm4vSGpoTnz6pRfAtC64TrtanQaUChW8lI2StdKDNXe_j_b3F7mlZj9xFLNxjpnBim3LaF-mxLMqtC6IdQ9xENvJEsDDwOHS77VjNtY2ZhlXwnTWVq7UTbThOQETQdlYBBCLPgqMYSACzTfLli-wgfe3pIEAUXeygBxWqAgYnSDAm-Z47X1yAzQUyVlbITAfCUZZXiGonHs4YoNMWVqWDkWgNsIspKWRWUcSzgVjZFS7HChyYI_uIP0FejgsA`
  const key = `-----BEGIN CERTIFICATE-----
MIIDHTCCAgWgAwIBAgIJAJsmCdlCEtdXMA0GCSqGSIb3DQEBBQUAMDExLzAtBgNV
BAMMJnNlY3VyZXRva2VuLnN5c3RlbS5nc2VydmljZWFjY291bnQuY29tMB4XDTIy
MTExOTA5MzkwOFoXDTIyMTIwNTIxNTQwOFowMTEvMC0GA1UEAwwmc2VjdXJldG9r
ZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDPx5SngqCrMJVQ/lFC9kP7Mgnhs4aIIbaquM42Z/zG1c80
EPEhTlRz9Cltc6wtj0wmRPi9x8HtIRlyoo4ps6LCXH0GxJZ6hZHGlcGUbFTAbVsY
aUWqteiXb2umTEnFV8+IaeOqVvSnJ97RIRcMSa7McKL+AkdjKPuDvdK5R6SHnnML
3HNJ8Xla1YOWmYkgCAgUNGLLg5bl8M6zyicNg8ZPGV7ndIzjrXuy9yKorpljNzZJ
hymT29yIq3hFInk+GGaSEaRIW6Zz0QjxUSgjDS75yxHnNM9Sgik3I6X8SHKO6mdY
aG4GAQUcuHr8eaZH9vYR0RG50c+fMw/P38nr0i8VAgMBAAGjODA2MAwGA1UdEwEB
/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMCMA0G
CSqGSIb3DQEBBQUAA4IBAQCvRsaUOJj8yA5Ul/LhoBFwEmZaQuU5sUKWGMJJj4ug
WzBPtCEfsmYsMQWmaSY7PiHn7eOF7rUL6FRaHvy1sMwF+xp4xomrIp+GQPQA4hra
AlgJRUUslTMJkbypsZ6PMWMLJw2WtyFcaIq/5vdywExwcfi+Gi7lDHTyfSCTiDvq
qK85W7OpqkmSxFKcva9Gi0tLLNgrRR9953Pwqis3LRVwKX6yXQ0j0v2pTmIyH/zp
VrUK77PjKaWlZISsmLH5dF4Olclx6hRFhvUYVXmT0K/hqr4pBZWukt4D9cD6ZSem
qFbFBUPmxj4clHXqiqRmQ3tv6MkpudXzCNb0wYWk+3TU
-----END CERTIFICATE-----`
  console.log(await jwt.verify(token, key, { algorithm: 'RS256' }))
}
johnswarbrick commented 10 months ago

Update - the error seems to be:

NotSupportedError: Unrecognized key import format \"spki\"."

I've tried lots of other JWT validation libraries, but none of them run on Cloudflare Workers due to missing crypto library dependencies. Hoping there is a solution with cloudflare-worker-jwt

tsndr commented 10 months ago

Hey @johnswarbrick,

thanks for bringing this to my attention and providing data to test with, really appreciated.

Will take a look and let you know once I've implemented a fix :)

tsndr commented 10 months ago

Hey @johnswarbrick,

The WebCrypto API doesn't currently support importing X.509 keys, supporting this would require a bit more work, and since I want to keep this library lightweight, I don't really want to ship all of that code just to support this scenario. I hope you can understand :)

If you're looking for a heavier, but more feature-full implementation of JWT, check out panva/jose

johnswarbrick commented 10 months ago

Thanks @tsndr, that's a shame as I like your very lightweight library, but I completely understand your decision! Really appreciate you looking into this so quickly.

tsndr commented 10 months ago

If you really want to keep using this library you could Parse the X509 certificate on your end and just pass the resulting public key to jwt.verify().