I'd like to send a response code of 401 if the requesting user is not authenticated, but I'd also like to redirect when the request was an HTML request. I've been finding that Express 4 doesn't allow this:
res.status(401).redirect('/login')
Does anyone know of a way to handle this? This might not be a limitation of Express, since I'm asking to essentially pass two headers, but I don't see why that should be the case. I should be able to pass a "not authenticated" response and redirect the user all in one go.
The res. redirect() function lets you redirect the user to a different URL by sending an HTTP response with status 302. The HTTP client (browser, Axios, etc.) will then "follow" the redirect and send an HTTP request to the new URL as shown below.
In the specific case you show in your question, when you "approve" the login, you may then want to do a res. redirect() to whatever URL you want the user to start on after the login and then create a route for that URL which you will use res. render() to render that page.
It is unmaintained Express has not been updated for years, and its next version has been in alpha for 6 years. People may think it is not updated because the API is stable and does not need change. The reality is: Express does not know how to handle async/await .
There are some subtle diferences with the methods for sending back a new location header.
With redirect
:
app.get('/foobar', function (req, res) {
res.redirect(401, '/foo');
});
// Responds with
HTTP/1.1 401 Unauthorized
X-Powered-By: Express
Location: /foo
Vary: Accept
Content-Type: text/plain; charset=utf-8
Content-Length: 33
Date: Tue, 07 Apr 2015 01:25:17 GMT
Connection: keep-alive
Unauthorized. Redirecting to /foo
With status
and location
:
app.get('/foobar', function (req, res) {
res.status(401).location('/foo').end();
});
// Responds with
HTTP/1.1 401 Unauthorized
X-Powered-By: Express
Location: /foo
Date: Tue, 07 Apr 2015 01:30:45 GMT
Connection: keep-alive
Transfer-Encoding: chunked
With the original (incorrect) approach using redirect
:
app.get('/foobar', function (req, res) {
res.status(401).redirect('/foo')();
});
// Responds with
HTTP/1.1 302 Moved Temporarily
X-Powered-By: Express
Location: /foo
Vary: Accept
Content-Type: text/plain; charset=utf-8
Content-Length: 38
Date: Tue, 07 Apr 2015 01:26:38 GMT
Connection: keep-alive
Moved Temporarily. Redirecting to /foo
So it looks like redirect
will abandon any previous status codes and send the default value (unless specified inside the method call). This makes sense due to the use of middleware within Express. If you had some global middleware doing pre-checks on all requests (like checking for the correct accepts headers, etc.) they wouldn't know to redirect a request. However the authentication middleware would and thus it would know to override any previous settings to set them correctly.
UPDATE: As stated in the comments below that even though Express can send a 4XX status code with a Location header does not mean it is an acceptable response for a request client to understand according to the specs. In fact most will ignore the Location header unless the status code is a 3XX value.
You can certainly send a Location: /login
header alongside with your 401 page, however, this is ill-advised, and most browsers will not follow it, as per rfc2616.
One way to do overcome this, is to serve <meta http-equiv="refresh" content="0; url=/login">
alongside with your 401
page:
res.set('Content-Type', 'text/html');
res.status(401).send('<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=/login"></head></html>');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With