Home > Software engineering >  JWT Token Verification to decode and Protect Routes in MEAN App
JWT Token Verification to decode and Protect Routes in MEAN App

Time:10-21

I am trying to authenticate users using JWT. I am assigning a token on login.

if (client) {
      // Check if Client does exist, then compare password provided by Client
      if (!req.body.password) {
        res.json({ success: false, message: "No password provided" }); // Password was not provided
      } else {
        var validPassword = client.password === req.body.password; // Check if password matches password provided by Client
        if (!validPassword) {
          res.json({ success: false, message: {password: {message: "Incorrect Password"}} }); // Password does not match password in database
        } else {
          if (!client.active) {
            res.json({ success: false, message: {active: {message: "Account is not activated"}} }); // Account is not activated
          } else {
            var token = jwt.sign(
              { username: client.username, email: client.email },
              secret,
              { expiresIn: "24h" }
            ); // Logged in: Give Client token
            res.json({
              success: true,
              message: "Client authenticated!",
              token: token
            }); // Return token in JSON object to controller
          }
        }
      }
    }

After login, I am checking the token in requests made my the user.

router.use(function(req, res, next) {   
var token = req.body.token || req.body.query || req.headers['x-access-token']; // Check for token in body, URL, or headers
// Check if token is valid and not expired  
if (token) {
// Function to verify token
    jwt.verify(token, secret, (err, decoded) => {
        if (err) {
            res.json({ success: false, message: 'Token invalid' }); // Token has expired or is invalid
        } else {
            req.decoded = decoded; // Assign to req. variable to be able to use it in next() route ('/me' route)
            next(); // Required to leave middleware
        }
    });
} else {
    res.json({ success: false, message: 'No token provided' }); // Return error if no token was provided in the request
}   

});

I am putting all the protected routes after the check token. Users can access the profile page /me

router.post('/me', function(req, res) {
    res.send(req.decoded); // Return the token acquired from middleware
});

How can I check the token in req.body in Angular 11? I have tried to setToken using localStorage but it seems I am not doing it correctly.

localStorage.setItem('userToken', response.token);

It seems to be working fine in Postman when accessing the /me route by passing the token in body. It shows whether the token found or not. If found then it shows the result

{ "email": "[email protected]", "iat": 1634704834, "exp": 1634791234 }

CodePudding user response:

Everything seems fine. I think, you just need to implement an interceptor on the frontend side. It will pick the auth token from the local storage, and attach it with all the requests.

Sample code

import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthService } from './service/auth.module';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    constructor(private authService: AuthService) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        let loggedInUser = this.authService.currentUserValue;
        token = JSON.parse(localStorage.getItem(user.token));
        if (token) {
            request = request.clone({
                setHeaders: {
                    Authorization: `Bearer ${token}`
                }
            });
        }

        return next.handle(request);
    }
}

And yeah, sending authentication token in the body params is not considered a good practice. Safe method is to use headers always for such sensitive information. More details can be found here

CodePudding user response:

I have used the HttpInterceptor

import { Injectable, Injector } from '@angular/core';
import { HttpInterceptor } from '@angular/common/http';
import { AuthService } from './auth.service';

@Injectable()
export class TokenInterceptorService implements HttpInterceptor {
  constructor(private injector: Injector) {}
  intercept(req, next) {
    let auth = this.injector.get(AuthService);
    let tokenizedReq = req.clone({
      setHeaders: {
        Authorization: `Bearer ${auth.getToken()}`,
      },
    });
    return next.handle(tokenizedReq);
  }
}

It reflects the token in headers but prompts "Token Invalid" when I am trying to get the data from the backend on the any route. I am checking using console.log(response); whereas it's working fine in nodemon while passing token in headers.

Please assist.

  • Related