Search code examples
expresscookie-session

Session id undefined express


I am having trouble identifying why exactly my session id is not being set in my expressjs backend api.

When I run Postman via a post request to /provision:

const express = require("express");
require("express-async-errors");
const cors = require("cors");
const cookieSession = require("cookie-session");
const createTables = require("./queries/create-tables");
const keys = require("./keys");
const cleanup = require("./queries/cleanup");

const app = express();

app.set("trust proxy", "127.0.0.1");
app.use(
  cors({
    origin:
      process.env.NODE_ENV === "production"
        ? ["<some-domain>", "<some-domain>"]
        : ["http://localhost:3000"],
    credentials: true,
  })
);
app.use(express.json());
app.use(
  cookieSession({
    secure: process.env.NODE_ENV === "production",
    keys: [keys.cookieKey],
    sameSite: "Lax",
    httpOnly: true,
    domain: "<some-domain>",
  })
);

app.use((req, res, next) => {
  console.log("Session:", req.session);
  if (!req.session) {
    return next(new Error("Session is not set up properly"));
  }
  next();
});

app.post("/provision", require("./provision"));
app.post("/query", require("./query"));
app.post("/reset", require("./reset"));

It appears to successfully run the provision.js logic:

const pool = require("./pool");
const createRole = require("./queries/create-role");
const createDb = require("./queries/create-db");
const { createId, validateId } = require("./queries/id");

module.exports = async (req, res) => {
  let id = req.session.id;

  if (!id) {
    id = createId(8);
    req.session.id = id;
  }

  validateId(id);

  try {
    await createRole(id);
    await createDb(id);

    res.send({ status: "ok" });
  } catch (err) {
    console.error(err);
    throw new Error("Failed to provision db");
  }
};

But when I go to run a post request on /query with the following query:

{
    "query": "SELECT * FROM users WHERE id = 1"
}

I get:

{
    "error": "Session ID is missing"
}

After verifying session middleware is correct, the session handling appears correct, but why is the session id still not being set?

This is the code inside of query.js:

const createClient = require("./queries/create-client");
const { validateId } = require("./queries/id");
const dbExists = require("./queries/db-exists");
const touchLogin = require("./queries/touch-login");

module.exports = async (req, res) => {
  const { id } = req.session;

  console.log("Session:", id);
  if (!id) {
    return res.status(400).json({ error: "Session ID is missing" });
  }
  validateId(id);

  if (!(await dbExists(id))) {
    throw new Error("No database found. Reload this page.");
  }
  await touchLogin(id);

  const client = await createClient(id);

  try {
    console.log("Query:", req.body.query);
    const result = await client.query(req.body.query);

    if (Array.isArray(result)) {
      res.send(
        result.map(({ rows, fields, command, rowCount }) => ({
          command,
          rows,
          fields,
          rowCount,
        }))
      );
    } else {
      res.send([
        {
          command: result.command,
          rows: result.rows,
          fields: result.fields,
          rowCount: result.rowCount,
        },
      ]);
    }
  } catch (err) {
    console.error("Query Execution Error:", err);
    res.status(500).json({ error: err.message });
  } finally {
    await client.end();
  }
};

Solution

  • So I have @WeDoTheBest4You to thank for helping me arrive at my solution. So because the domain names I am using do not actually exist yet and yet I have these domains If the domains do not exist, the user agent will fail to resolve the domain names, leading to errors when attempting to connect to those servers. As a result, the user agent won't even reach the point where cookies could be set or sent:

    {
        "query": "SELECT * FROM users WHERE id = 1"
    }
    

    If I do not have a crystal clear understanding of it, please someone feel free to edit my solution or comment and I will edit it accordingly.

    The solution was to refactor my index.js file to the following:

    const allowedOrigins =
      process.env.NODE_ENV === "production"
        ? ["<some-domain>", "<some-other-domain>"]
        : ["http://localhost:3000"];
    
    app.set("trust proxy", process.env.NODE_ENV === "production" ? 1 : 0);
    app.use(
      cors({
        origin: function (origin, callback) {
          if (!origin) {
            return callback(null, true);
          }
          if (allowedOrigins.indexOf(origin) === -1) {
            const msg =
              "The CORS policy for this site does not allow access from the specified origin";
            return callback(new Error(msg), false);
          }
          return callback(null, true);
        },
        credentials: true,
      })
    );
    
    // app.use(
    //   cors({
    //     origin:
    //       process.env.NODE_ENV === "production"
    //         ? ["<some-domain>", "<some-other-domain>"]
    //         : ["http://localhost:3000"],
    //     credentials: true,
    //   })
    // );
    app.use(express.json());
    app.use(
      cookieSession({
        secure: process.env.NODE_ENV === "production",
        keys: [keys.cookieKey],
        sameSite: "Lax",
        httpOnly: true,
        domain: process.env.NODE_ENV === "production" ? "<some-domain>" : undefined,
      })
    );
    

    And this worked. Now the API is still not working in that now I am getting a different error, but this error has now been resolved. Thanks again.