Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d19068c

Browse files
committedApr 11, 2020
modify token validation logic
1 parent fae6e2c commit d19068c

File tree

7 files changed

+23
-42
lines changed

7 files changed

+23
-42
lines changed
 

‎.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,4 @@ DB_ADMIN_PWD=changeit
3939
ACCESS_TOKEN_VALIDITY_DAYS=30
4040
REFRESH_TOKEN_VALIDITY_DAYS=120
4141
TOKEN_ISSUER=afteracademy.com
42-
TOKEN_AUDIENCE=afteracademy_users
42+
TOKEN_AUDIENCE=afteracademy.com

‎src/auth/authUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ export const getAccessToken = (authorization: string) => {
1111
return authorization.split(' ')[1];
1212
};
1313

14-
export const validateTokenData = (payload: JwtPayload, userId: Types.ObjectId): boolean => {
14+
export const validateTokenData = (payload: JwtPayload): boolean => {
1515
if (!payload || !payload.iss || !payload.sub || !payload.aud || !payload.prm
1616
|| payload.iss !== tokenInfo.issuer
1717
|| payload.aud !== tokenInfo.audience
18-
|| payload.sub !== userId.toHexString())
18+
|| !Types.ObjectId.isValid(payload.sub))
1919
throw new AuthFailureError('Invalid Access Token');
2020
return true;
2121
};

‎src/auth/authentication.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import express from 'express';
22
import { ProtectedRequest, Tokens } from 'app-request';
33
import UserRepo from '../database/repository/UserRepo';
44
import { AuthFailureError, AccessTokenError, TokenExpiredError } from '../core/ApiError';
5-
import JWT, { ValidationParams } from '../core/JWT';
5+
import JWT from '../core/JWT';
66
import KeystoreRepo from '../database/repository/KeystoreRepo';
77
import { Types } from 'mongoose';
8-
import { getAccessToken } from './authUtils';
8+
import { getAccessToken, validateTokenData } from './authUtils';
99
import { tokenInfo } from '../config';
1010
import validator, { ValidationSource } from '../helpers/validator';
1111
import schema from './schema';
@@ -18,18 +18,13 @@ export default router.use(validator(schema.auth, ValidationSource.HEADER),
1818
req.accessToken = getAccessToken(req.headers.authorization); // Express headers are auto converted to lowercase
1919

2020
try {
21-
const jwtPayload = await JWT.decode(req.accessToken);
22-
if (!jwtPayload.sub || !Types.ObjectId.isValid(jwtPayload.sub))
23-
throw new AuthFailureError('Invalid access token');
21+
const payload = await JWT.validate(req.accessToken);
22+
validateTokenData(payload);
2423

25-
const user = await UserRepo.findById(new Types.ObjectId(jwtPayload.sub));
24+
const user = await UserRepo.findById(new Types.ObjectId(payload.sub));
2625
if (!user) throw new AuthFailureError('User not registered');
2726
req.user = user;
2827

29-
const payload = await JWT.validate(
30-
req.accessToken,
31-
new ValidationParams(tokenInfo.issuer, tokenInfo.audience, req.user._id.toHexString()));
32-
3328
const keystore = await KeystoreRepo.findforKey(req.user._id, payload.prm);
3429

3530
if (!keystore || keystore.primaryKey !== payload.prm)

‎src/core/JWT.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ export default class JWT {
3434
/**
3535
* This method checks the token and returns the decoded data when token is valid in all respect
3636
*/
37-
public static async validate(token: string, validations: ValidationParams): Promise<JwtPayload> {
37+
public static async validate(token: string): Promise<JwtPayload> {
3838
const cert = await this.readPublicKey();
3939
try {
4040
// @ts-ignore
41-
return <JwtPayload>await promisify(verify)(token, cert, validations);
41+
return <JwtPayload>await promisify(verify)(token, cert);
4242
} catch (e) {
4343
Logger.debug(e);
4444
if (e && e.name === 'TokenExpiredError') throw new TokenExpiredError();
@@ -48,29 +48,20 @@ export default class JWT {
4848
}
4949

5050
/**
51-
* Returns the decoded payload without verifying if the signature is valid.
51+
* Returns the decoded payload if the signature is valid even if it is expired
5252
*/
5353
public static async decode(token: string): Promise<JwtPayload> {
54+
const cert = await this.readPublicKey();
5455
try {
55-
return <JwtPayload>decode(token);
56+
// @ts-ignore
57+
return <JwtPayload>await promisify(verify)(token, cert, { ignoreExpiration: true });
5658
} catch (e) {
5759
Logger.debug(e);
5860
throw new BadTokenError();
5961
}
6062
}
6163
}
6264

63-
export class ValidationParams {
64-
issuer: string;
65-
audience: string;
66-
subject: string;
67-
constructor(issuer: string, audience: string, subject: string) {
68-
this.issuer = issuer;
69-
this.audience = audience;
70-
this.subject = subject;
71-
}
72-
}
73-
7465
export class JwtPayload {
7566
aud: string;
7667
sub: string;

‎src/routes/v1/access/schema.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Joi from '@hapi/joi';
2-
import { JoiObjectId } from '../../../helpers/validator';
2+
import { JoiAuthBearer } from '../../../helpers/validator';
33

44
export default {
55
userCredential: Joi.object().keys({
@@ -10,8 +10,7 @@ export default {
1010
refreshToken: Joi.string().required().min(1),
1111
}),
1212
auth: Joi.object().keys({
13-
'x-access-token': Joi.string().required().min(1),
14-
'x-user-id': JoiObjectId().required(),
13+
'authorization': JoiAuthBearer().required()
1514
}).unknown(true),
1615
signup: Joi.object().keys({
1716
name: Joi.string().required().min(3),

‎src/routes/v1/access/token.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import { ProtectedRequest } from 'app-request';
44
import { Types } from 'mongoose';
55
import UserRepo from '../../../database/repository/UserRepo';
66
import { AuthFailureError, } from '../../../core/ApiError';
7-
import JWT, { ValidationParams } from '../../../core/JWT';
7+
import JWT from '../../../core/JWT';
88
import KeystoreRepo from '../../../database/repository/KeystoreRepo';
99
import crypto from 'crypto';
1010
import { validateTokenData, createTokens, getAccessToken } from '../../../auth/authUtils';
1111
import validator, { ValidationSource } from '../../../helpers/validator';
1212
import schema from './schema';
1313
import asyncHandler from '../../../helpers/asyncHandler';
14-
import { tokenInfo } from '../../../config';
1514

1615
const router = express.Router();
1716

@@ -21,20 +20,17 @@ router.post('/refresh',
2120
req.accessToken = getAccessToken(req.headers.authorization); // Express headers are auto converted to lowercase
2221

2322
const accessTokenPayload = await JWT.decode(req.accessToken);
24-
if (!accessTokenPayload.sub || !Types.ObjectId.isValid(accessTokenPayload.sub))
25-
throw new AuthFailureError('Invalid access token');
23+
validateTokenData(accessTokenPayload);
2624

2725
const user = await UserRepo.findById(new Types.ObjectId(accessTokenPayload.sub));
2826
if (!user) throw new AuthFailureError('User not registered');
2927
req.user = user;
3028

31-
validateTokenData(accessTokenPayload, req.user._id);
29+
const refreshTokenPayload = await JWT.validate(req.body.refreshToken);
30+
validateTokenData(refreshTokenPayload);
3231

33-
const refreshTokenPayload = await JWT.validate(req.body.refreshToken,
34-
new ValidationParams(
35-
tokenInfo.issuer,
36-
tokenInfo.audience,
37-
req.user._id.toHexString()));
32+
if (accessTokenPayload.sub !== refreshTokenPayload.sub)
33+
throw new AuthFailureError('Invalid access token');
3834

3935
const keystore = await KeystoreRepo.find(
4036
req.user._id,

‎tests/.env.test.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,4 @@ DB_USER_PWD=changeit
3232
ACCESS_TOKEN_VALIDITY_DAYS=30
3333
REFRESH_TOKEN_VALIDITY_DAYS=120
3434
TOKEN_ISSUER=test.afteracademy.com
35-
TOKEN_AUDIENCE=test.afteracademy_users
35+
TOKEN_AUDIENCE=test.afteracademy.com

0 commit comments

Comments
 (0)
Please sign in to comment.