Reputation: 765
My setup is like this : I have a React front-end that makes requests to an express server (based on node obviously). When a user logs in his credentials are checked and finally a token is returned that will be used to perform further actions.
So that works all great, but I want to prevent users from doing bypassing the login screen and just do website.com/dashboard. My first thought was to check the token validation on every route change in the application, but I don't know if that is the right thing to do.
It seems a bit overkill to make a call every time the route changes... But I don't know if there is a better way of doing. Just checking if the token exists is obviously not enough because the users can just put whatever they want in it.
They won't be able to make modifications or fetching data because they need that token to make requests to the API, but it's still silly if you can view the interface by writing the route manually.
Here are my ideas to resolve it so far:
Upvotes: 0
Views: 616
Reputation: 386
You are right with how you want to do it. Here is more explanation :
What you are talking about is called Authorization (and is different from Authentication), which is handling what a user can access or not. You can verify authorization in different ways.
Using a session cookie is one way. But... since you are building an API, it is a good practice to keep frontend and backend "separated" (some say "agnostic"), meaning that the frontend is not supposed to know anything about backend, and vice-versa. That makes using a session cookie not ideal (since you have the cookie in the frontend and information about the session is stored in the backend).
So, using a token (JWT) is a good way to handle authorization.
In your case, you can indeed authenticate first the user and then store the token in the frontend.
Then, you can handle authorization like this :
Frontend : Send the token with all requests if it exists, in the header.
Backend: Verify the token. If it is valid, let the user pass. If not, send an error message to the frontend !
If the frontend gets back an error message, redirect to login (or anywhere you want).
How do you do that ? (I will focus on the backend. There nothing specific in the frontend).
In your main app file (usually app.js) :
const express = require('express')
const publicRoutes = require('./routes/publicroutes')
const privateRoutes = require('./routes/privateroutes')
const defineAuth = require('./helpers/defineauth')
const isAuth = require('./helpers/isAuth')
const app = express()
app.use(defineAuth)
app.use('/publicRoute', publicRoutes) // like /login, /signup, etc...
app.use(isAuth)
app.use('/privateRoute', privateRoutes) // accessible only with a valid token
In defineAuth middleware:
Verify if there is an authorization header
Validate the token
defineauth middleware :
const jwt = require('jsonwebtoken')
module.exports = (req, res, next) => {
const authHeader = req.get('Authorization')
if (!authHeader) {
req.isAuth = false
return next()
}
const token = authHeader.split(' ')[1]
let decodedToken
try {
decodedToken = jwt.verify(token, process.env.JWT_KEY)
} catch (err) {
req.isAuth = false
return next()
}
if (!decodedToken) {
req.isAuth = false
return next()
}
// Here, the token is valid so :
req.isAuth = true
next()
}
Then you can easily check anywhere in your code if the user is authorized or not. Here I check in app.js.
isAuth middleware :
const isAuth = (req, res, next) => {
if (!req.isAuth) {
const error = new Error('Authorization required')
error.status = 401
throw error
}
next()
}
module.exports = isAuth
You can verify authorization anywhere. So that, makes having different level of authorization much easier to handle (if you have for example free and premium users).
Upvotes: 1
Reputation: 51
If you're using express-session, a cookie called connect.sid is set upon successful login containing the session ID. You can read the value of this session ID from the cookie in React to check whether the user is logged in or not and block requests accordingly without making any API calls.
Upvotes: 1