node.jspm2adfspassport-saml

Node JS passport-saml authentication fails with "preflight request doesn't pass access control check" when deploying multiple instance using pm2


I have tried plenty of answers posted for a similar question but my issue is slightly different from straight forward CORS issue.

I am using passport-saml with my Node JS app to authenticate my web-application with ADFS. Everything works fine as long as I deploy only one instance of the app but as soon as I run multiple instances using pm2 I get the following error:

Access to XMLHttpRequest at 'https://login.microsoftonline.com/.....' 
(redirected from 'https://sampleserver.com/get/employee') 
from origin 'https://sampleserver.com' has been blocked by 
CORS policy: Response to preflight request doesn't pass access control check: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

This is my pm2 config file:

{
    "apps": [
    {
        "name" : "sample-worker",
        "script" : "./app",
        "log_date_format": "YYYY-MM-DD HH:mm:ss.SSS",
        "autorestart" : true,
        "instances" : 3,
        "exec_mode" : "cluster",
        "instance_var": "INSTANCE_ID"
    }
    ]
}

Based on some of the questions posted online I tried the following:

app.use(express.json());
app.use(cors({ origin: true }));

ALSO

const corsOptions = {
    origin: '*',
    optionsSuccessStatus: 200
};
app.options('*', cors(corsOptions));

And also tried some other options from the questions below:

Question_1

Question_2

Question_3

Please let me know if you would need any other information to shed some more light on the issue. I really appreciate any help I can get on this. I've been stuck on this for days now.

P.S. The app works perfectly fine when only a single instance is deployed - regardless of whether it is deployed using node command or pm2 command.

Edit: This is the code that checks for presence of a user in the request object:

app.get("/", function (req, res, next) {
        if (req.isAuthenticated()) {
            console.log(JSON.stringify(req.user));
            next();
        } else {
            console.log("***************************");
            console.log('User not authenticated, routing to AD for authentication');
            console.log('***************************');
            res.redirect("/login");
        }
    });

Solution

  • This is not a CORS problem, but a session management problem:

    After successful SAML logon flow, the server issues a session cookie, which the browser re-sends with every subsequent request.

    For this to work with multiple backend instances, it must be ensured that a session cookie that was issued by one instance is also recognized by all other instances. In other words: The instances need a common session store, for example a database. Storing sessions in a global Node.js variable does not work, because every instance has its own global variables.

    The pm2 documentation also says as much.