How to redirect user to a page that requires an access token without exposing token in a URL query

Viewed 792

I am trying to implement a way of only allowing authorized admins to access pages with sensitive information within my Web App/API. I am currently using Node.JS with Express to handle routing. Views are generated with Jade/Pug View Engine. CORS requests are handled using the request framework on github. (https://github.com/request/request)

Currently, clients are stored within a MongoDB collection. When they enter their login information, their passwords are compared to a Hash stored in the DB. If everything checks out, a JWT is generated for the user and saved in the client DB and also stored within the browser in localStorage.token.

The user is then redirected to a splash page which has an authentication function as middleware. The authentication function accepts the token in three forms:

var token = req.body.token || req.query.token || req.headers['x-access-token'];

I feel like the way redirection is handled is a bit hacky. I am using window.location = route?token=[token]

Token is handed over to the authentication function within req.query.token, but this is exposed in URL. Here is my login function:

function submitLogIn() {
    var credentials = {
        email: logInForm.userEmail.value,
        password: logInForm.pwField.value
    }

    fetch('/login', {
        headers:{
            'Content-Type': 'application/json'
        },
        method: 'POST',
        body: JSON.stringify(credentials)
    }).then(function(res){
        if(!res.ok) alert("Error!")
        else return res.json().then(function(result){

            localStorage.token = result.token;

 //This is how I'm doing redirecting:

            window.location = '/selection?token=' + result.token;


        }).catch(function(err){
            console.log(err);
            throw err;
        });
    });

Just for reference, this is the front-end route that it's going to at port 3001 which swings it over to 3000 as a reverse-proxy request:

router.post('/login', function(req, res, next) {
    request.post({
        url: 'http://localhost:3000/authorize',
        form: req.body 
    }).pipe(res)
});

My main question is this: How can I handle redirection at the front-end within fetch calls?

My splash screen is basically a menu of buttons which will take the user to different pages. The pages will contain information that only admins should see. Let's say I want to click on this navigation button. It goes to a /GET route that requires the token to be sent for an OK status. if no token, it returns a 403.

router.get('/main', authorize.adminRequired, function(req, res, next) {
    request.get({
        url: 'http://localhost:3000/menus'
        }, function(response, sensitiveItems) {
        return res.render('index', {menu: JSON.parse(sensitiveItems)});
    });
 });

That authorize.adminRequired function needs a token in the form of a query, x-access-token, or req.body. Can't send a body in a GET request. Don't want to expose in URL, so:

Here's what I tried. I have this redirect fetch call as an onclick function.

function redirectToSensitivePage() {
    fetch('/main', {
        headers: {
            'x-access-token': localStorage.token
        },
        method: 'GET'
    });
};

This gives me a 200, OK. But I don't load the page. The res.render(index) in the route does not fire. The response does contain all of the data, but I am not redirected to the visual representation.

I could do the same hacky redirect using window.location=/main?token=[token], but I don't want to expose the URL token. I could load everything I need into the webpage upon login instead of having separate pages, have those divs hidden out of sight until keypress to make that div the main visible div, but I would rather figure out how to do it via redirect.

I'm still getting my bearings with using Node, so please let me know if I have made any stupid glaring oversights.

Edit: Should I simply try

var token = localStorage.token || req.body.token || req.query.token || req.headers['x-access-token'];

Is there any disadvantage to simply scraping from the localStorage automatically with each request?

0 Answers
Related