oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
72.28k stars 2.58k forks source link

jwks-rsa and/or express-jwt not working with bun #10511

Open henrikericsson opened 3 months ago

henrikericsson commented 3 months ago

What version of Bun is running?

1.1.4+fbe2fe0c3

What platform is your computer?

Linux 5.15.146.1-microsoft-standard-WSL2 x86_64 x86_64

What steps can reproduce the bug?

Create an express middleware and apply it to any route served via express using https module.

Middleware:


import { Request, Response, NextFunction } from 'express'
import jwt from 'express-jwt'
import jwksRsa from 'jwks-rsa'

function requireAuth(req: Request, res: Response, next: NextFunction) {
  const jwksUri = 'https://login.microsoftonline.com/<TENANT_ID>/discovery/v2.0/keys'
  const issuer = 'https://login.microsoftonline.com/<TENANT_ID>/v2.0'
  const audience = '<CLIENT_ID>'

  const client = jwksRsa({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: jwksUri,
  })

  client
    .getSigningKeys()
    .then(keys => console.log('keys:', keys))
    .catch(err => console.log('error:', err))

  const expressJwtSecret = jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: jwksUri,
  }) as jwksRsa.GetVerificationKey

  const expressJwt = jwt.expressjwt({
    secret: expressJwtSecret,
    audience: audience,
    issuer: issuer,
    algorithms: ['RS256'],
  })

  expressJwt(req, res, (error: unknown) => {
    if (error) {
      return next(error)
    }

    return next()
  })
}

export default requireAuth

What is the expected behavior?

A collection of signing keys should be returned from the jwksUri using the jwks-rsa package.

What do you see instead?

No keys are returned and fails with error:

JwksError {
  name: "JwksError",
  message: "The JWKS endpoint did not contain any signing keys",
  toString: [Function: toString],
}

Additional information

The same flow works just fine running it with node

Middleware:


const jwt = require("express-jwt");
const jwksRsa = require("jwks-rsa");

function requireAuth(req, res, next) {
  const jwksUri = "https://login.microsoftonline.com/<TENANT_ID>/discovery/v2.0/keys";
  const issuer = "https://login.microsoftonline.com/<TENANT_ID>/v2.0";
  const audience = "<CLIENT_ID>";

  const client = jwksRsa({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: jwksUri,
  });

  client
    .getSigningKeys()
    .then((keys) => console.log("keys:", keys))
    .catch((err) => console.log("error:", err));

  const expressJwtSecret = jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: jwksUri,
  });

  const expressJwt = jwt.expressjwt({
    secret: expressJwtSecret,
    audience: audience,
    issuer: issuer,
    algorithms: ["RS256"],
  });

  expressJwt(req, res, (error) => {
    if (error) {
      return next(error);
    }

    return next();
  });
}

module.exports = requireAuth;
elliots commented 3 months ago

this is the error jose is throwing that jwks isn't logging... at least in my case


TypeError: CryptoKey is not extractable
      at /opt/core/api/node_modules/jwks-rsa/node_modules/jose/dist/browser/runtime/asn1.js:12:15
      at genericExport (/opt/core/api/node_modules/jwks-rsa/node_modules/jose/dist/browser/runtime/asn1.js:7:30)
      at exportSPKI (/opt/core/api/node_modules/jwks-rsa/node_modules/jose/dist/browser/key/export.js:4:34)
      at /opt/core/api/node_modules/jwks-rsa/src/utils.js:53:30```
elliots commented 3 months ago

It's using the browser runtime, not node. Not sure if that's whats supposed to be happening? Or maybe theres a bun one. Anyway, when using browser the ext field is looked at in the jwt. This gets past the issue for me. I think.


diff --git a/node_modules/jwks-rsa/src/utils.js b/node_modules/jwks-rsa/src/utils.js
index dcaf146..e40e613 100644
--- a/node_modules/jwks-rsa/src/utils.js
+++ b/node_modules/jwks-rsa/src/utils.js
@@ -43,6 +43,7 @@ async function retrieveSigningKeys(jwks) {

   for (const jwk of jwks) {
     try {
+      jwk.ext = true
       const key = await jose.importJWK(jwk, resolveAlg(jwk));
       if (key.type !== 'public') {
         continue;
henrikericsson commented 3 months ago

Thank you for your responses and for looking into this issue. I appreciate the time and effort you’ve put into investigating this.

I agree that the error seems to be related to the crypto library, specifically with the CryptoKey not being extractable. However, I would like to point out that the same code works perfectly fine when running in a Node.js environment. This suggests that the issue might not be with the jwks-rsa library itself, but rather with how it’s being used or configured in the Bun environment.

The jwks-rsa library is as far as I know designed for Node.js, and it seems to be functioning as expected in that context. Modifying the library directly might not be the best approach, as it could potentially introduce other issues or side effects. Instead, I believe we should focus on understanding why the library is not working as expected in the Bun environment.

It’s possible that there might be some configuration changes needed in Bun, or perhaps some adjustments within the framework itself. I think it would be beneficial to explore these possibilities further.

elliots commented 3 months ago

No worries, I’m hitting the same issue.

I’m not suggesting the change is an actual fix, just working out where the problem is :)

Looks like it is supposed to use the browser runtime: https://github.com/panva/jose/blob/main/package.json#L80

elliots commented 3 months ago

Related: https://github.com/auth0/node-jwks-rsa/issues/373

guidoffm commented 2 months ago

Version 2.1.5 works for me, version 3.1.0 not.

henrikericsson commented 2 months ago

A few months ago, I experimented with the 2.x version of the jwks-rsa library, using an older version of Bun but encountered the same issue then as I am with the latest version of Bun and the 3.x version of jwks-rsa.

But I haven't tried using the latest version of bun with an older version of jwks-rsa.

guidoffm commented 2 months ago

It is better to use the Jose library since it is certified for the use with Bun.