javascriptnode.jsexpresscookiescors

Why does express router get blocked by CORS but router routes do not?


I have this function that I am using to protect my routes.

export function authUser(req, res, next) {
    let token = req.cookies?.token;
    if (token) {
        jwt.verify(token, process.env.jwt_secret, (err, data) => {
            if (err) {
                res.sendStatus(403);
            } else {
                req.username = data;
                next();
            }
        });
    } else {
        res.sendStatus(403);
    }
}

This works completely fine

const authRoutes = express.Router();

authRoutes.get('/content', authUser, (req, res) => {
    res.send(`This is the content in Content.vue for ${req.username}`);
});

app.use('/a', authRoutes);

But it would be annoying to add authUser to every route under authRoutes manually. I would like to do this so that every route in authRoutes goes through authUser

const authRoutes = express.Router();

authRoutes.use(authUser);

authRoutes.get('/content', (req, res) => {
    res.send(`This is the content in Content.vue for ${req.username}`);
});

app.use('/a', authRoutes);

But the problem is when I do this, I get this error on the frontend

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8182/a/content. (Reason: CORS preflight response did not succeed). Status code: 403.

I am puzzled on why the first approach works but the second doesn't. The issue is the fact that there are no cookies in req.cookies when we get to authUser.

This is how cookies are set

let options = {
    maxAge: 1000 * 60 * 0.25,
    httpOnly: true, // Cookie will not be exposed to client side code
    sameSite: 'none', // If client and server origins are different
    secure: true, // use with HTTPS only
};

const token = jwt.sign(req.body.identifier, process.env.jwt_secret);
res.cookie('token', token, options);
res.sendStatus(200);

Aren't the two requests flowing the same way? Does authRoutes.use send data back to the user before reaching a route?


Solution

  • The two setups are different: the first setup only applies the authUser middleware to GET /a/content, the second one applies it to every request made to /a/*, including OPTIONS requests used in CORS preflight requests.

    And, as documented here, "a CORS-preflight request never includes credentials".