Jwt verify whitout checking expiration - jwt

I have a function which generates a refresh token.
async refreshToken(token: string): Promise<{ token: string } | ErrorDetails> {
if (!token)
throw new HttpException('No token provided', HttpStatus.BAD_REQUEST)
token = token.split(' ')[1]
const jwtToken = await this.jwtService
.verifyAsync(token, {
secret: process.env.JWT_SECRET,
})
.catch((error) => {
if (error === 'jwt expired') return
})
// Here if token is expired jwtToken is null
if (!jwtToken)
throw new HttpException('Invalid token', HttpStatus.FORBIDDEN)
const user = await this.userService.findUserByAllFields(jwtToken.user)
if (!user) throw new HttpException('Invalid token', HttpStatus.FORBIDDEN)
const userDetails = this.userService._getUserDetails(jwtToken.user)
const jwt = await this.jwtService.signAsync({ userDetails })
return { token: jwt }
}
I wan't to check if the token is right but without checking the expiration
Is there any way to handle it ?

this.jwtService.verify(token, {
secret,
ignoreExpiration: true,
});

If you don't pass expireIn option or exp claim there will not be any exp claim, so the JWT does not have any expiration.

Related

finding the user while assigning new access token

I have a website where when user logsIn, they are assigned an access and a refresh token. When the access token is expried, a request to the server is made and checks if the refresh token is present in the global array in the database. If it is, a new access token is assigned to the user.
But I wanted to ask if should also check for the user by the information given by the refresh token when it is decoded. Or it is not necessary.
Please suggest me good practice and also tell me if something is wrong with my process.
routes.post("/newAccessToken", async (req, res) => {
const token = req.headers.cookie?.split("=")[1];
try {
const existingToken = await refreshTokens.findOne({
tokens: { $in: [token] },
});
if (existingToken) {
const email = await jwt.verify(token, process.env.RefreshTokenSecret);
if (email) {
const user = await userSchema.findOne({ email });
if (user) {
const newAccessToken = await jwt.sign(
{ email },
process.env.AccessTokenSecret
);
res.json({ newAccessToken });
}
} else res.json({ message: "token is invalid" });
} else res.json({ message: "No token found" });
} catch (error) {
console.log(error);
}
});

How can I store data of decode JWT in nuxt?

I have pages with connexion and deconnexion to login on my nuxt app.
I use Symfony for the back and the librairy JWT for token authentification.
Here this is the code auth.js called when an user is login on my app. This works but I would like to store in my vuex the data into the token (I have the role and I would like to use it to display different things on page in function of the role). How can I do this ? Thanks for help
import axios from "axios";
import jwtDecode from "jwt-decode";
export const login = async (data) => {
const token = await axios
.post(process.env.baseUrl + 'login_check', data)
.then (response => response.data.token )
window.localStorage.setItem("authToken", token)
axios.defaults.headers["Authorization"] = "Bearer " + token;
}
export const logout = () => {
window.localStorage.removeItem("authToken")
delete axios.defaults.headers['Authorization'];
}
export const verifToken = () => {
const token = window.localStorage.getItem("authToken");
if (token ) {
const jwtData = jwtDecode(token);
if (jwtData.exp * 1000 > new Date().getTime()) //
{
axios.defaults.headers["Authorization"] = "Bearer " + token;
//console.log("connexion axios OK")
return true
}
else // if expired
{
logout();
}
}
//if no token
else {
logout();
console.log("no token")
}
}

How to log out using jwt token in node backend

I have used jwt token to login
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET);
.
Below is my code for router
router.post("/login", async (req, res) => {
try {
const { email, password } = req.body;
// validate
if (!email || !password)
return res.status(400).json({ msg: "Not all fields have been entered." });
const user = await Customer.findOne({ email: email });
if (!user)
return res
.status(400)
.json({ msg: "No account with this email has been registered." });
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json({ msg: "Invalid credentials." });
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET);
res.json({
token,
user: {
id: user._id,
displayName: user.displayName,
},
});
} catch (err) {
res.status(500).json({ error: err.message });
}
});
Can anybody provide code for loging out using jwt token
You just need to invalidate your jwt token in logout
more than one way you can achieve. Here I am going to explain a couple of ways
1.storing token in an array. In log out, you can remove the token
const refreshTokens = []; --> global declaration
in login, before res.json({...});
refreshTokens.push(refreshToken);
the constraint here is jwt tokens are time-bounded. You need to get a refresh token if old token expires. Whenever you issue a refresh token you need to remove the old and push the latest
router.post('/refreshtoken', function (req, res) {
const { token } = req.body;
if (!token) {
return res.sendStatus(401);
}
if (!refreshTokens.includes(token)) {
return res.sendStatus(403);
}
jwt.verify(token, refreshTokenSecret, (err, user) => {
if (err) {
return res.sendStatus(403);
}
const accessToken = jwt.sign({ username: user.username, role: user.role }, accessTokenSecret, { expiresIn: '20m' });
refreshTokens = refreshTokens.filter(token => t !== token);
refreshTokens.push(accessToken);
res.json({
accessToken
});
});
});
In Logout you need to invalidate token
app.post('/logout', (req, res) => {
const { token } = req.body;
refreshTokens = refreshTokens.filter(token => t !== token);
res.send("Logout successful");
});
2.Store token in cookie whenever you log in or reissues the token. verify jwt token from cookie instead of reading from headers.
res.cookie('jwt_token', token, {
expires: new Date(Date.now() + expiration),
secure: false, // set to true if your using https
httpOnly: true,
});
In Logout destroy the cookie
router.get('/logout', function (req, res) {
res.clearCookie('jwt_token');
req.session.destroy();
});

axios interceptors to update auth

I am using axios interceptors to check auth token on every request. This works fine. But when accessToken is null getToken() is fired twice. Is there a way to wait for the getToken to finish ? I just want getToken to fire once. The other requests needing a token should wait until getToken is fulfilled.
let isAlreadyFetchingAccessTokenRequest = false;
api.interceptors.request.use(
async config => {
let token = window.localStorage.getItem("accessToken");
if (!isAlreadyFetchingAccessTokenRequest && !token) {
isAlreadyFetchingAccessTokenRequest = true;
token = await getToken();
console.log("1. save token to local storage", token);
window.localStorage.setItem("accessToken", token);
}
config.headers.Authorization = `Bearer ${token}`;
return config;
},
function(error) {
return Promise.reject(error);
}
);
You are able to await a promise multiple times.
So could try something like this
let tokenPromise = null;
api.interceptors.request.use(
async config => {
let token = window.localStorage.getItem("accessToken");
if (!token) {
if (!tokenPromise) {
tokenPromise = getToken();
}
token = await tokenPromise;
console.log("1. save token to local storage", token);
window.localStorage.setItem("accessToken", token);
}
config.headers.Authorization = `Bearer ${token}`;
...

JWT - Why it generates extraordinary long tokens

Everything was working fine until I decided to save the tokens (as String) with the users. The tokens were used to be 5 lines long max, and now it is keep growing every time I refresh the token. The last token I generated was 100 lines long which is not acceptable.
Every time the user logs in, I am refreshing the token.
module.exports.login = function(req, res){
var user_name = req.body.username;
var password = req.body.password;
User.findOne({username: user_name}, function(err, user){
if(err || !user) {
return res.json({error: "cannot find the user"});
} else{
user.comparePassword(password, function(err, isMatch){
if (err){
return res.json({
error: "passowrd doesn't match"
});
}
});
var token = jwt.sign(user, process.env.SECRET, {
expiresIn: 4000
});
console.log(token); // printing the token
}
if(!token){
res.json({
success: false,
username: null,
token: null
});
}
else {
user.token = token;
User.updateUser(user._id, user, {new: true},function(err, updated_user){
res.json({
success: true,
username: user.username,
token: token
});
});
}
});
};
All the routes are secured, and it needs to verify the token for each request.
module.exports.secured = function(req, res, next){
var token;
var username = req.body.req_username || req.headers['req_username'];
if(username){
User.findOne({ 'username': username }, function (err, user) {
if (err || !user)
return res.json({
error: "cannot find the user"
});
else
token = user.token;
jwt.verify(token, process.env.SECRET, function(err, decode){
if(err){
res.status(500).send({
error: "wrong token or username"
});
} else{
next();
}
});
});
} else{
res.send({
error: "not found"
});
}
};
I think I am not refreshing the tokens correctly.
The token should not be stored in the server because it wastes unnecessary resources.
user.token = token;
User.updateUser(user._id, user, {new: true},function(err, updated_user){
res.json({
success: true,
username: user.username,
token: token
});
});
Each time the token is refreshed you encode the user variable that includes the previously issued token, therefore it grows
var token = jwt.sign(user, process.env.SECRET, {
expiresIn: 4000
});
Remove user.token = token
But the main issue is that the client MUST send the JWT in each request, not the username to recover the token. You are verifying the token stored in user entity. It does not make sense. Change the client code to.send the JWT in the headers instead of the username req.headers['req_username']