awslabs/aws-jwt-verify

#node-web-compat missing upon execution

g-wozniak opened this issue ยท 13 comments

Question
The library works as expected when testing with local Express server on localhost via HTTP. However, when attempting to use with supertest and jest and my app server simulator (no changes in server implementation) I am getting an error:

    Cannot find module '#node-web-compat' from 'node_modules/aws-jwt-verify/dist/cjs/https.js'

    Require stack:
      node_modules/aws-jwt-verify/dist/cjs/https.js
      node_modules/aws-jwt-verify/dist/cjs/jwk.js
      node_modules/aws-jwt-verify/dist/cjs/jwt-rsa.js
      node_modules/aws-jwt-verify/dist/cjs/index.js
      src/server/services/cognito/cognito.ts
      src/server/services/index.ts

Tried to debug it, reinstall; checked and those modules are there. I am thinking might be something to do with supertest settings judging by https.js but might be a coincidence.

Test is simple:

         await request(app.server)
            .put(dummyRoute.route.uri)
            .set(common_Headers.xRequest, '1234')
            .expect(200)

Has anyone had similar issue before or saw anything like it?

Versions
Which version of aws-jwt-verify are you using?
^3.0.0

Are you using the library in Node.js or in the Web browser?
NodeJS

If Node.js, which version of Node.js are you using? (Should be at least 14)
16..13.0

If using TypeScript, which version of TypeScript are you using? (Should be at least 4)
4.5.2

Thanks for reporting this!

This is a bug (or at the very least a development opportunity) in jest.

I've logged it here, would appreciate your +1 : jestjs/jest#12619

A fix, or better said: a workaround, is documented here: https://github.com/ottokruse/jest-subpath-import

Thank you for the quick response. You're right. In my case the following mapping helped:

moduleMapperForServer = {
  ...
  '#node-web-compat': './node-web-compat-node.js'
}

where node-web-compat-node.js would be for Node and node-web-compat-web.js for web projects.

Thank you for looking into it.

hitting this error when trying to use the library in react native, is there anyway to work around it?

@mtj8033 - what does react native use for a crypto library? My google searching just finds things that are years old like https://github.com/imchintan/react-native-crypto-js and https://github.com/tradle/react-native-crypto as ways to shim in the node API.

Also, do you know if subpath imports work in react-native?

Had a look into supporting React Native and made some progress with this metro config:

module.exports = {
  resolver: {
    resolveRequest: (context, moduleName, platform, realModuleName) => {
      // Specific redirect for #node-web-compat
      if (moduleName === '#node-web-compat') {
        return {
          filePath: path.join(
            path.resolve(context.originModulePath, '..'),
            './node-web-compat-web.js',
          ),
          type: 'sourceFile',
        };
      }

      // Forward everything else to the default resolver
      return defaultResolver(
        {
          ...context,
          resolveRequest: null,
        },
        moduleName,
        platform,
        realModuleName,
      );
    },
  },
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: true,
      },
    }),
  },
};

However, now I run into another issue, as React Native does not support TextDecoder which we use here:

parseB64UrlString: (b64: string): string =>
new TextDecoder().decode(bufferFromBase64url(b64)),

It would be great to hear your use case in React Native @mtj8033 , we need to judge whether React Native would maybe be worth further effort / support.

For the record, after polyfilling TextDecoder I now run into [TypeError: undefined is not an object (evaluating 'window.crypto.subtle')] which brings us to @hakanson 's point: need to figure out which crypto backend to actually use in React Native.

Was able to get it working in a local emulator with the following metro.config.js file, the important part being the extraNodeModules configuration (or at least I think it's working):

/**
 * Metro configuration for React Native
 * https://github.com/facebook/react-native
 *
 * @format
 */
const rootDir = __dirname;
module.exports = {
  resolver: {
    extraNodeModules: {
      "#node-web-compat": `${rootDir}/node_modules/aws-jwt-verify/dist/cjs/node-web-compat-web.js`,
    },
  },
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: true,
      },
    }),
  },
};

Note I am also using the following package:
https://www.npmjs.com/package/node-libs-react-native

@mtj8033 interestingly you point to node-web-compat-web.js in your extraNodeModules but if you also use node-libs-react-native then it might be better to point to node-web-compat-node.js.

The best solution might be to create a custom compat-react-native.js, that implements the compat interface and then point to that compat-react-native.js in your extraNodeModules instead.

If feasible, it might be good to add such a RN compat implementation to this library, but it's not in the roadmap currently.

Please move any further React Native talk to #73
Thank you

In my case I had a similar issue while unit testing and downgrading from 3.1.0to 2.1.3 helped. My app is in Next.js based. When I run an app, it works as expected in my api in Next.js however when it comes to unit testing the issue appears. I think, the issue should be reopened in order to let know that the problem exists

the issue should be reopened in order to let know that the problem exists

I've just pinned this issue. But the ball is in Jest's court.

Should be solved in jest now: jestjs/jest#12270 (comment)

Thank you for the quick response. You're right. In my case the following mapping helped:

moduleMapperForServer = {
  ...
  '#node-web-compat': './node-web-compat-node.js'
}

where node-web-compat-node.js would be for Node and node-web-compat-web.js for web projects.

Thank you for looking into it.

thabks. it work for me