Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue initializing auth0 with Typescript and Inversify #863

Closed
5 tasks done
neeraj87 opened this issue May 19, 2023 · 9 comments
Closed
5 tasks done

Issue initializing auth0 with Typescript and Inversify #863

neeraj87 opened this issue May 19, 2023 · 9 comments
Labels
bug This points to a verified bug in the code

Comments

@neeraj87
Copy link

Checklist

  • I have looked into the Readme, Examples, and FAQ and have not found a suitable solution or answer.
  • I have looked into the API documentation and have not found a suitable solution or answer.
  • I have searched the issues and have not found a suitable solution or answer.
  • I have searched the Auth0 Community forums and have not found a suitable solution or answer.
  • I agree to the terms within the Auth0 Code of Conduct.

Description

I have a backend project running on AWS Lambda with Node.js and TypeScript. I am using serverless framework - more specifically serverless-bundle with inversify

The problem is auth0 does not initializes with inversify. This was a not a problem before but has suddenly started happening across all my projects wherever auth0 is being used.

I had raised another issue #815 with auth0 and even updated my project's auth0 version to latest one but it still fails.

Since the inversify container is being initialized from lambda, auth0 failure is causing the entire lambda failure for the project.

Reproduction

My lambda handler

'use strict';

import { APIGatewayProxyHandler } from 'aws-lambda';
import serverlessExpress from '@vendia/serverless-express';
import app from './auth-express.app';
import SQLDbConnectionService from './services/sqldb-connection-service';
import MongoDbConnectionService from './services/mongodb';

export const handler: APIGatewayProxyHandler = async (
  event,
  context,
  callback,
) => {
  context.callbackWaitsForEmptyEventLoop = false;
  
  const authHeaders = (event.requestContext || {}).authorizer || {};

  ['principalId'].forEach((headerKey) => {
    if (authHeaders[headerKey]) {
      event.headers[headerKey] = authHeaders[headerKey];
    }
  });

  await Promise.all([
    SQLDbConnectionService.connect(),
    MongoDbConnectionService.connect(),
  ]);

  const serverlessExpressInstance = serverlessExpress({ app });
  return serverlessExpressInstance(event, context, callback);
};

In the above lambda handler one line number 3, I am initializing my express server, which looks like the following

'use strict';

import cors from 'cors';
import express from 'express';
import compression from 'compression';
import 'reflect-metadata';
import { ExpressRouter } from './routes/auth-routes';
import helmet from 'helmet';
import { ContainerFactory } from './factories/container-factory';

class ExpressApplication {
  public app: express.Express;
  private readonly router: express.Router;

  constructor() {
    const container = ContainerFactory.getContainer();
    
    const expressRouter = new ExpressRouter();
    this.app = express();
    this.router = express.Router();
    this.app.use(cors());
    this.app.use(helmet());
    this.app.use(compression());
    this.app.use(express.json());
    this.app.use(express.urlencoded({ extended: true }));
    expressRouter.setRoutes(this.app, this.router, container);
  }
}

const app = new ExpressApplication();

export default app.app;

in the express code above, I am setting the inversify container from container-factory which looks like this

import 'reflect-metadata';
import { Container } from 'inversify';

//import service identifiers
import TYPES from "../utilities/types";

//import service interfaces
import Auth0ServiceInterface from 'interfaces/auth0-service-interface';
.
.
.

//import services and implementations
import { Auth0Service } from '../services/auth0-service';
.
.
.

export class ContainerFactory {
  public static getContainer(): Container {
    const container = new Container({ skipBaseClassChecks: true });
    ContainerFactory.configureServices(container);
    return container;
  }

  private static configureServices(container: Container) {
    //binding auth0 service
    container.bind<Auth0ServiceInterface>(TYPES.Auth0Service).to(Auth0Service);
    
    //binding other services
    .
    .
    .
  }
}

in the code above I am importing the interfaces and services and binding them. You can see that I am also binding my auth0 service - which is where the problem starts.

The auth0 service looks like this (have removed the functions for readability)

import { AuthenticationClient, ManagementClient, User } from 'auth0';
import Auth0ServiceInterface from 'interfaces/auth0-service-interface';
import { Auth0ClinicianMetaData } from 'interfaces/auth0-user-interfaces';
import { injectable } from 'inversify';

const AUTH0_AUDIENCE = process.env.AUTH0_AUDIENCE;

let AUTH0_DOMAIN = process.env.AUTH0_DOMAIN || '';
AUTH0_DOMAIN = AUTH0_DOMAIN.replace('https://', '');

let AUTH0_DOMAIN_NOT_CUSTOM = process.env.AUTH0_DOMAIN_NOT_CUSTOM || '';
AUTH0_DOMAIN_NOT_CUSTOM = AUTH0_DOMAIN_NOT_CUSTOM.replace('https://', '');

const AUTH0_M2M_CLIENT_ID = process.env.AUTH0_M2M_CLIENT_ID || '';
const AUTH0_M2M_SECRET = process.env.AUTH0_M2M_SECRET || '';
const AUTH0_REGULAR_WEB_CLIENT_ID = process.env.AUTH0_REGULAR_WEB_CLIENT_ID || '';
const AUTH0_REGULAR_WEB_CLIENT_SECRET = process.env.AUTH0_REGULAR_WEB_CLIENT_SECRET || '';

@injectable()
export class Auth0Service implements Auth0ServiceInterface {
  private managementClient: ManagementClient;
  private authenticationClient: AuthenticationClient;

  constructor() {
    this.managementClient = new ManagementClient({
      domain: AUTH0_DOMAIN_NOT_CUSTOM,
      clientId: AUTH0_M2M_CLIENT_ID,
      clientSecret: AUTH0_M2M_SECRET,
      scope: 'read:users create:users update:users',
    });

    this.authenticationClient = new AuthenticationClient({
      domain: AUTH0_DOMAIN,
      clientId: AUTH0_REGULAR_WEB_CLIENT_ID,
      clientSecret: AUTH0_REGULAR_WEB_CLIENT_SECRET,
    });
  }

  //... functions for implementing the auth0 service - have removed for the sample
}

I get this kind of error when the lambda function is called

2023-05-17T10:16:31.760Z	undefined	ERROR	Uncaught Exception 	{
    "errorType": "TypeError",
    "errorMessage": "M is not a function",
    "stack": [
        "TypeError: M is not a function",
        "    at Object.91738 (/var/task/src/auth-lambda.js:540:5226)",
        "    at __webpack_require__ (/var/task/src/auth-lambda.js:3143:2090854)",
        "    at Object.59458 (/var/task/src/auth-lambda.js:540:15606)",
        "    at __webpack_require__ (/var/task/src/auth-lambda.js:3143:2090854)",
        "    at Object.16135 (/var/task/src/auth-lambda.js:2839:1079)",
        "    at __webpack_require__ (/var/task/src/auth-lambda.js:3143:2090854)",
        "    at Object.81557 (/var/task/src/auth-lambda.js:2726:36831)",
        "    at __webpack_require__ (/var/task/src/auth-lambda.js:3143:2090854)",
        "    at Object.96781 (/var/task/src/auth-lambda.js:2726:41526)",
        "    at __webpack_require__ (/var/task/src/auth-lambda.js:3143:2090854)"
    ]
}

If I comment the auth0 function binding in my container-factory then my lambda runs smoothly.

Here are the dependencies and dev-dependencies in my project

//dependencies
"auth0": "^3.4.0"
"express": "^4.17.1",
"inversify": "^6.0.1",

//dev dependencies
"@types/auth0": "^3.3.2",
"@types/aws-lambda": "^8.10.84",
"@types/express": "^4.17.13",

Additional context

My lambda is running on Node.js version 14

node-auth0 version

3.4.0

Node.js version

14

@neeraj87 neeraj87 added the bug This points to a verified bug in the code label May 19, 2023
@adamjmcgrath
Copy link
Contributor

adamjmcgrath commented May 19, 2023

HI @neeraj87 - thanks for raising this

I have an example repo using serverless-bundle to bundle a project with node-auth0@3.4.0 and it appears to be working AnomalyInnovations/serverless-nodejs-starter@master...adamjmcgrath:serverless-nodejs-starter:master

Could you share a minimal reproduction that demonstrates your issue and I'd be happy to debug it for you.

@neeraj87
Copy link
Author

Hey @adamjmcgrath, the issues seems to be happening when using inversify with auth0. I will create a minimal reproduction for you and share it here in some time.

@neeraj87
Copy link
Author

@adamjmcgrath Here is the minimal project file you can deploy on your lambda. You will need to add these 2 things

  1. In serverless.yml replace mydomain with your own domain name and certificate name
  2. Add the auth0 env vars in your AWS parameter store - they are mentioned in the serverless.yml file under environment

I deployed this project using AWS Codebuild and tested it and it is failing and showing the same error I mentioned above. However it works perfectly locally.

Do let me know if you need any more information to help you debug/investigate.
auth0-inversify-nodejs-sample.zip

@neeraj87
Copy link
Author

@adamjmcgrath - any updates on this?

@adamjmcgrath
Copy link
Contributor

Hi @neeraj87 - I don't have an AWS account so I'm unable to test this on Cloudbuild. Are you not able to reproduce this locally?

@neeraj87
Copy link
Author

Hey @adamjmcgrath, no this is not reproducible on local. The issue was initially limited to our staging env but now seems to have spilled into production. Is there a way we can sync up separately and discuss? A lot of our services rely on auth0 service and have started to fail one by one

@adamjmcgrath
Copy link
Contributor

@neeraj87 if you need to reach out to us directly you should be able to do this through your technical account manager or representative at auth0.

The ESM support doesn't support all use cases, if this is the case with you, you should try importing the CJS version of this library using the workaround here #832 (comment)

@adamjmcgrath
Copy link
Contributor

Closing as I believe #863 (comment) answers your question

@neeraj87
Copy link
Author

neeraj87 commented Jun 5, 2023

@adamjmcgrath yes you can close this. I actually managed to make this work by moving the auth0 dependency under bundle for my serverless.yml file as mentioned here

Thank you for your help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This points to a verified bug in the code
Projects
None yet
Development

No branches or pull requests

2 participants