Error when logging in on Forest with admin backend deployed on AWS in lambda function

Since we made the upgrade to Liana 6, we face frequently following issue when logging into Forest with google SSO:
Oops can not reach the endpoint on your application.Check your Liana version.

Expected behavior

No error

Actual behavior

Error “Oops can not reach the endpoint on your application.Check your Liana version”

Failure Logs

On the backend we see also this log:
POST /forest/sessions-google 404

Context

Please provide any relevant information about your setup.

  • Package Version: 6.2.0
  • Express Version: 4.16.3
  • Sequelize Version: 5.15.1
  • Database Dialect: MySQL
  • Database Version: 5.6.10a
  • Project Name: Elyps

Important note: Forest backend is deploy on AWS in lambda function. We do not run the code in file server.js. Instead here is the code of our lambda function:

const awsServerlessExpress = require("aws-serverless-express");

const app = require("./app");

const server = awsServerlessExpress.createServer(app);

exports.handler = (event, context) => {

awsServerlessExpress.proxy(server, event, context);

};

Hello @Cyril_Limam !
Can you reach your forest backend manually (just hit the ip address + port) ?
What logs do you have on your server ? (I never used lambda functions, so I might ask dumb questions :sweat_smile:)

Did you follow these steps while upgrading to v6 ?

Hi Nicolas, yes it does work. Here is the response I get from Postman:

<html>

<head>
	<style>
		body {
			font-family: Arial, Helvetica, sans-serif;
			margin: 60px;
			font-size: 16px;
			background-color: #fcfdfc;
			color: #060f19;
		}

		#logo {
			display: block;
			width: 5rem;
			margin: 2rem auto;

		}

		h1 {
			text-align: center;
			color: #3b2512;
			font-weight: 500;
		}

		h2 {
			color: #d68a41;
			font-weight: 400;
			text-align: center;
		}

		span {
			display: block;
			margin: 4rem auto;
			height: 2px;
			width: 2rem;
			background-color: #61cf96;
		}

		div {
			border-radius: .25rem;
			background: white;
			box-shadow: 0 0 1rem rgba(59, 37, 18, 0.16);
			width: 50%;
			margin: 0 auto;
			padding: 1rem;
		}

		li {
			margin: 1rem;
			font-size: 1.25rem;
			line-height: 1.5rem;
		}

		ul {
			list-style: none;
			margin-bottom: 2rem;
		}

		ul li::before {
			content: "\2022";
			font-size: 1rem;
			color: #61cf96;
			display: inline-block;
			width: 1rem;
			height: 1rem;
			margin-left: -1rem;
		}
	</style>
	<title>LumberJS</title>
</head>

<body>
	<img id="logo" src="data:image/png;base64,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">
	<h1>Your application is running!</h1>
</body>

</html>

Here are the logs I got on the server side:

GET / 200 10026 - 7.470 ms

Note that before Liana upgrade we never had this issue and even after upgrade, Forest does work most of the time. The issue mentioned here only happen sometime.

Also, yes we did follow the steps mentioned in the upgrade procedure.

Do you have any logs on your lambda function when this happens ?

Yes,

POST /forest/sessions-google 404

Hello @Cyril_Limam :wave:

It looks like your server is running, but forest is not initialised. Can you check by attempting to reach /forest/healthcheck please ?

Keep me posted :raised_hands:

Steve.

Hi steve,

Maybe I do something wrong but I get this response:

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="utf-8">
	<title>Error</title>
</head>

<body>
	<pre>Cannot GET /forest/healthcheck</pre>
</body>

</html>

Hi @Cyril_Limam :wave:

This is correct :+1: here we clearly see that the forest routes are not initialised, although your server is running. Somehow the init is never called in your lambda.

If you have recently migrated to V6, I suspect this breaking change has not been taken into account :

Can you confirm ?

Steve.

Hi Steve,

No I do not confirm. We did implement the breaking changes you mentioned.

Best regards,
Cyril.

@Cyril_Limam

May I see the app.js file please ?

Steve.

Sure, here it is

const express = require("express");
const requireAll = require("require-all");
const path = require("path");
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const cors = require("cors");
const jwt = require("express-jwt");
const morgan = require("morgan");
const {
  ensureAuthenticated,
  PUBLIC_ROUTES,
} = require("forest-express-sequelize");

const app = express();

app.use(morgan("tiny"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));

let allowedOrigins = [/forestadmin\.com$/];

if (process.env.CORS_ORIGINS) {
  allowedOrigins = allowedOrigins.concat(process.env.CORS_ORIGINS.split(","));
}

app.use(
  cors({
    origin: allowedOrigins,
    allowedHeaders: ["Authorization", "X-Requested-With", "Content-Type"],
    maxAge: 86400, // NOTICE: 1 day
    credentials: true,
  })
);

app.use(
  jwt({
    secret: process.env.FOREST_AUTH_SECRET,
    credentialsRequired: false,
  })
);

app.use("/forest", (request, response, next) => {
  if (PUBLIC_ROUTES.includes(request.url)) {
    return next();
  }
  return ensureAuthenticated(request, response, next);
});

requireAll({
  dirname: path.join(__dirname, "routes"),
  recursive: true,
  resolve: (Module) => app.use("/forest", Module),
});

requireAll({
  dirname: path.join(__dirname, "middlewares"),
  recursive: true,
  resolve: (Module) => Module(app),
});

module.exports = app;

I believe the implementation you propose can not guarantee that the app.use(await Liana…) is fully resolved before we start our server. We should await for app to be ready before doing http.createServer(app).

I have had similar use case in another project and had to do something like this:

async function startServer() {
    const app = await createApp(...)
    const server = http.createServer(app);
...
}

startServer()

Hi @Cyril_Limam

I believe the implementation you propose can not guarantee that the app.use(await Liana…) is fully resolved before we start our server. We should await for app to be ready before doing http.createServer(app).

Yes indeed, I suspect you have to do the same, and wait the liana for being initialised.

Can you try it please ?

keep me posted :+1:

Steve.

Hi @Steve_Bunlon,

I do confirm that it was the issue.
Here is our app.js:

const express = require("express");
const requireAll = require("require-all");
const path = require("path");
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const cors = require("cors");
const jwt = require("express-jwt");
const morgan = require("morgan");
const {
  ensureAuthenticated,
  PUBLIC_ROUTES,
} = require("forest-express-sequelize");

async function createApp() {
  const app = express();

  app.use(morgan("tiny"));
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: false }));
  app.use(cookieParser());
  app.use(express.static(path.join(__dirname, "public")));

  let allowedOrigins = [/forestadmin\.com$/];

  if (process.env.CORS_ORIGINS) {
    allowedOrigins = allowedOrigins.concat(process.env.CORS_ORIGINS.split(","));
  }

  app.use(
    cors({
      origin: allowedOrigins,
      allowedHeaders: ["Authorization", "X-Requested-With", "Content-Type"],
      maxAge: 86400, // NOTICE: 1 day
      credentials: true,
    })
  );

  app.use(
    jwt({
      secret: process.env.FOREST_AUTH_SECRET,
      credentialsRequired: false,
    })
  );

  app.use("/forest", (request, response, next) => {
    if (PUBLIC_ROUTES.includes(request.url)) {
      return next();
    }
    return ensureAuthenticated(request, response, next);
  });

  requireAll({
    dirname: path.join(__dirname, "routes"),
    recursive: true,
    resolve: (Module) => app.use("/forest", Module),
  });

  const middlewares = requireAll({
    dirname: path.join(__dirname, "middlewares"),
    recursive: true,
    resolve: (Module) => Module(app),
  });

  await Promise.all(Object.keys(middlewares).map((key) => middlewares[key]));

  return app;
}

module.exports = createApp;

Here is our server.js:

require("dotenv").config();
const createApp = require("./app");
const debug = require("debug")("{name}:server");
const http = require("http");
const chalk = require("chalk");

function normalizePort(val) {
  const port = parseInt(val, 10);

  if (Number.isNaN(port)) {
    return val;
  }
  if (port >= 0) {
    return port;
  }

  return false;
}

async function createServer() {
  const port = normalizePort(
    process.env.PORT || process.env.APPLICATION_PORT || "3310"
  );

  const app = await createApp();
  app.set("port", port);

  const server = http.createServer(app);
  server.listen(port);

  function onError(error) {
    if (error.syscall !== "listen") {
      throw error;
    }

    const bind = typeof port === "string" ? `Pipe ${port}` : `Port ${port}`;

    switch (error.code) {
      case "EACCES":
        console.error(`${bind} requires elevated privileges`);
        process.exit(1);
        break;
      case "EADDRINUSE":
        console.error(`${bind} is already in use`);
        process.exit(1);
        break;
      default:
        throw error;
    }
  }

  function onListening() {
    const addr = server.address();
    const bind =
      typeof addr === "string" ? `pipe ${addr}` : `port ${addr.port}`;
    debug(`Listening on ${bind}`);

    console.log(chalk.cyan(`Your application is listening on ${bind}.`));
  }

  server.on("error", onError);
  server.on("listening", onListening);
}

createServer();

And as a bonus, here is our lambda.js (this is what is running on AWS lambda, we only use server,.js for local tests):

const awsServerlessExpress = require("aws-serverless-express");
const createApp = require("./app");

let app;
let server;

exports.handler = async (event, context) => {
  if (!app) {
    app = await createApp();
  }
  if (!server) {
    server = awsServerlessExpress.createServer(app);
  }
  return awsServerlessExpress.proxy(server, event, context, "PROMISE").promise;
};

2 Likes

@Cyril_Limam glad it helped! And thanks for sharing this :green_heart:

1 Like

Hello @Cyril_Limam :wave:

Woaw amazing! Thanks a lot for providing the entire code :muscle:

I’m glad we figured this out :raised_hands:

Steve.

1 Like