0

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");
        }
    });
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Nick Div
  • 5,338
  • 12
  • 65
  • 127
  • Does this help? https://stackoverflow.com/questions/71798164/cors-issue-with-ambassador-accessing-azuread – Heiko Theißen Oct 17 '22 at 15:07
  • Not really because the issue is not with handling expired tokens but with parallel instances not being able to handle the authentication. I wonder why though because the request object will remain the same and it is already authenticated :( – Nick Div Oct 17 '22 at 15:27
  • In both cases, the problem is that the API request does not have a valid session: in your case because a different instance is chosen, in the other case because the session is expired. Or how do you share sessions between the two instances? – Heiko Theißen Oct 17 '22 at 15:43
  • @HeikoTheißen I have added the logic that is used to check for a user in the post. Wouldn't the request object be same for each of the app/instance? If not, then what would be a solution in my situation? I wonder how do other load balanced apps work? – Nick Div Oct 17 '22 at 15:49
  • This makes perfect sense. Setting up a DB session store solved the issue. Thank you so much :) – Nick Div Oct 17 '22 at 16:22

1 Answers1

1

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.

Heiko Theißen
  • 12,807
  • 2
  • 7
  • 31