使用此 JWT 库检查令牌是否过期

我已经像这样配置了令牌:

jwt.sign(
{
user: pick(user, ['_id', 'username'])
},
secret,
{
expiresIn: '2m'
}
);

但是当我想检查令牌是否过期时,这段代码不起作用:

function isAuthenticated() {
const token = localStorage.getItem('token');
const refreshToken = localStorage.getItem('refreshToken');
try {
decode(token);
const { exp } = decode(refreshToken);
if (exp < (new Date().getTime() + 1) / 1000) {
return false;
}
} catch (err) {
return false;
}
return true;
}

问题在于这部分:

if (exp < (new Date().getTime() + 1) / 1000) {
return false;
}

New Date () . getTime () + 1)/1000 = 1531335468.113

Exp = 1531334595

因为我不知道 JWT 使用什么格式的时间..。

我该怎么办?

238479 次浏览

This is the answer:

if (Date.now() >= exp * 1000) {
return false;
}

You should use jwt.verify. It will check if the token is expired.

jwt.decode should not be used if the source is not trusted as it doesn't check if the token is valid.

Sadly, Andrés Montoya's answer has a flaw which is related to how he compares the object.

I found a solution here which should solve this:

const now = Date.now().valueOf() / 1000


if (typeof decoded.exp !== 'undefined' && decoded.exp < now) {
throw new Error(`token expired: ${JSON.stringify(decoded)}`)
}
if (typeof decoded.nbf !== 'undefined' && decoded.nbf > now) {
throw new Error(`token expired: ${JSON.stringify(decoded)}`)
}

Thanks to user thejohnfreeman!

verify itself returns an error if expired. It is safer as Gabriel said.

const jwt = require('jsonwebtoken')


router.use((req, res, next) => {
const token = yourJwtService.getToken(req) // Get your token from the request
jwt.verify(token, 'your-secret', function(err, decoded) {
if (err) throw new Error(err) // Manage different errors here (Expired, untrusted...)
req.auth = decoded // If no error, token info is returned in 'decoded'
next()
});
})

This is for React Native, but login will work for all types.

isTokenExpired = async () => {
try {
const LoginTokenValue = await AsyncStorage.getItem('LoginTokenValue');
if (JSON.parse(LoginTokenValue).RememberMe) {
const { exp } = JwtDecode(LoginTokenValue);
if (exp < (new Date().getTime() + 1) / 1000) {
this.handleSetTimeout();
return false;
} else {
//Navigate inside the application
return true;
}
} else {
//Navigate to the login page
}
} catch (err) {
console.log('Spalsh -> isTokenExpired -> err', err);
//Navigate to the login page
return false;
}
}
// Pass in function expiration date to check token
function checkToken(exp) {
if (Date.now() <= exp * 1000) {
console.log(true, 'token is not expired')
} else {
console.log(false, 'token is expired')
}
}

You can use the jwt verify method to check the validity of your token. err means the token is expired and will throw an error so you can remove the stored token.

 jwt.verify(token, SECRET, (err, decoded) => {
if (err) {
localStorage.clear();
}}
});

The following function works without any libraries:

function getJWTExpireDate(jwtToken: string) {
if (jwtToken) {
try {
const [, payload] = jwtToken.split('.');
const { exp: expires } = JSON.parse(window.atob(payload));
if (typeof expires === 'number') {
return new Date(expires * 1000);
}
} catch {
// ignore
}
}
return null;
}

Don't use this to check whether the token is valid. One good use case is displaying when the token expires in the frontend.

Function without the jwt library:

Browser

function isTokenExpired(token) {
const base64Url = token.split(".")[1];
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
const jsonPayload = decodeURIComponent(
atob(base64)
.split("")
.map(function (c) {
return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
})
.join("")
);


const { exp } = JSON.parse(jsonPayload);
const expired = Date.now() >= exp * 1000
return expired
}

Or simpler

function isTokenExpired(token) {
const expiry = (JSON.parse(atob(token.split('.')[1]))).exp;
return (Math.floor((new Date).getTime() / 1000)) >= expiry;
}

Or a one-liner:

const isTokenExpired = token => Date.now() >= (JSON.parse(atob(token.split('.')[1]))).exp * 1000

Node.js

function isTokenExpired(token) {
const payloadBase64 = token.split('.')[1];
const decodedJson = Buffer.from(payloadBase64, 'base64').toString();
const decoded = JSON.parse(decodedJson)
const exp = decoded.exp;
const expired = (Date.now() >= exp * 1000)
return expired
}

Or a one-liner:

const isTokenExpired = (token) => (Date.now() >= JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).exp * 1000)
const JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyMzQ1Njc4OTAsIm5hbWUiOiJKb2huIERvZSIsImlhdCI6MTUxNjIzOTAyMn0.1c_yQjnMZfKUb4UTDE_WvbC71f8xxtyMsdqKKkI1hF8";


const jwtPayload = JSON.parse(window.atob(JWT.split('.')[1]))
const isExpired = Date.now() >= jwtPayload.exp * 1000;


some answers omit verification step which is super dangerous!

safe replacement for jwt.verify with following changes

  • it does NOT throw when token is expired, but does throw for invalid token.
  • return object is {payload, expired} instead of payload

js version

export function verifyJWT(token) {
try {
return { payload: jwt.verify(token, publicKey), expired: false };
} catch (error) {
if (error.name == "TokenExpiredError") {
return { payload: jwt.decode(token), expired: true };
}
throw error;
}
}

ts version

export function verifyJWT(token: string) {
try {
return { payload: jwt.verify(token, publicKey), expired: false };
} catch (error) {
if ((error as Error).name == "TokenExpiredError") {
return { payload: jwt.decode(token), expired: true };
}
throw error;
}
}