Skip to content

Commit

Permalink
refactor: extract decode user to util
Browse files Browse the repository at this point in the history
Signed-off-by: jannyHou <[email protected]>
  • Loading branch information
jannyHou authored and Janny committed Jan 30, 2019
1 parent 3cbb0a8 commit 1d705b7
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 96 deletions.
87 changes: 0 additions & 87 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 2 additions & 8 deletions src/authentication-strategies/JWT.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

const jwt = require('jsonwebtoken');
import {promisify} from 'util';
const verifyAsync = promisify(jwt.verify);
// Consider turn it to a binding
const SECRET = 'secretforjwt';
import {Request, HttpErrors} from '@loopback/rest';
import {UserProfile} from '@loopback/authentication';
import * as _ from 'lodash';
import {AuthenticationStrategy} from './authentication.strategy';
import {decodeAccessToken} from '../utils/user.authentication';

export class JWTStrategy implements AuthenticationStrategy {
async authenticate(request: Request): Promise<UserProfile | undefined> {
Expand All @@ -23,10 +20,7 @@ export class JWTStrategy implements AuthenticationStrategy {
}

try {
const decoded = await verifyAsync(token, SECRET);
let user = _.pick(decoded, ['id', 'email', 'firstName']);
(user as UserProfile).name = user.firstName;
delete user.firstName;
const user = await decodeAccessToken(token, SECRET);
return user;
} catch (err) {
Object.assign(err, {
Expand Down
15 changes: 14 additions & 1 deletion src/utils/user.authentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import {toJSON} from '@loopback/testlab';
import {promisify} from 'util';
import * as isemail from 'isemail';
import {HttpErrors} from '@loopback/rest';
import {UserProfile} from '@loopback/authentication';
const jwt = require('jsonwebtoken');
const signAsync = promisify(jwt.sign);
const verifyAsync = promisify(jwt.verify);

export async function getAccessTokenForUser(
userRepository: UserRepository,
Expand All @@ -24,7 +26,6 @@ export async function getAccessTokenForUser(
}

const currentUser = _.pick(toJSON(foundUser), ['id', 'email', 'firstName']);

// Generate user token using JWT
const token = await signAsync(currentUser, 'secretforjwt', {
expiresIn: 300,
Expand All @@ -46,3 +47,15 @@ export function validateCredentials(credentials: Credentials) {
);
}
}

// secret should be injected
export async function decodeAccessToken(
token: string,
secret: string,
): Promise<UserProfile> {
const decoded = await verifyAsync(token, secret);
let user = _.pick(decoded, ['id', 'email', 'firstName']);
(user as UserProfile).name = user.firstName;
delete user.firstName;
return user;
}
65 changes: 65 additions & 0 deletions test/unit/utils.authentication.unit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright IBM Corp. 2019. All Rights Reserved.
// Node module: @loopback/example-shopping
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {expect, toJSON} from '@loopback/testlab';
import {MongoDataSource} from '../../src/datasources';
import {
decodeAccessToken,
getAccessTokenForUser,
} from '../../src/utils/user.authentication';
import {UserRepository, OrderRepository} from '../../src/repositories';
import {User} from '../../src/models';
import * as _ from 'lodash';
const SECRET = 'secretforjwt';

describe('authentication', () => {
const mongodbDS = new MongoDataSource();
const orderRepo = new OrderRepository(mongodbDS);
const userRepo = new UserRepository(mongodbDS, orderRepo);
const user = {
email: '[email protected]',
password: 'p4ssw0rd',
firstname: 'unit',
surname: 'test',
};
let newUser: User;

before('create user', async () => {
newUser = await userRepo.create(user);
});

it('decodes valid access token', async () => {
const token = await getAccessTokenForUser(userRepo, {
email: '[email protected]',
password: 'p4ssw0rd',
});
const expectedUser = getExpectedUser(newUser);
const currentUser = await decodeAccessToken(token, SECRET);
expect(currentUser).to.deepEqual(expectedUser);
});

it('throws error for invalid accesstoken', async () => {
const token = 'fake';
try {
await decodeAccessToken(token, SECRET);
expect('throws error').to.be.true();
} catch (err) {
expect(err.message).to.equal('jwt malformed');
}
});
});

function getExpectedUser(originalUser: User) {
const userProfile: Partial<User> = _.pick(toJSON(originalUser), [
'id',
'email',
'firstName',
]);
return {
id: userProfile.id,
email: userProfile.email,
name: userProfile.firstname,
};
}

0 comments on commit 1d705b7

Please sign in to comment.