Skip to content

Issue initializing auth0 with Typescript and Inversify #863

Closed
@neeraj87

Description

@neeraj87

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis points to a verified bug in the code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions