diff --git a/src/config/errors.config.ts b/src/config/errors.config.ts index 1af12d5..d4f9f36 100644 --- a/src/config/errors.config.ts +++ b/src/config/errors.config.ts @@ -11,6 +11,7 @@ export const errors = Object.assign({}, defaults, { USER_DELETE_OWN: { code: 'USER_DELETE_OWN', message: 'You can\'t delete your own user' }, USER_DUPLICATE: { code: 'USER_DUPLICATE', message: 'A user with this email already exists' }, USER_INACTIVE: { code: 'USER_INACTIVE', message: 'Your account is not active. Please contact your administrator.' }, + USER_INVALID_CREDENTIALS: { code: 'USER_INVALID_CREDENTIALS', message: 'Incorrect username or password. Please try again.' }, USER_NOT_FOUND: { code: 'USER_NOT_FOUND', message: 'User not found' }, }); // tslint:enable:max-line-length diff --git a/src/services/auth.service.ts b/src/services/auth.service.ts index 9222a1a..89d43a4 100644 --- a/src/services/auth.service.ts +++ b/src/services/auth.service.ts @@ -31,7 +31,10 @@ export async function login(payload: AuthCredentials, role?: Role) { const { email, password } = payload; try { const user = await userRepository.findByEmail(email); - if (!user) throw new AuthenticationError(); + if (!user) throw new AuthenticationError(errors.USER_INVALID_CREDENTIALS); + + const passwordMatch = await comparePassword(password, user.password); + if (!passwordMatch) throw new AuthenticationError(errors.USER_INVALID_CREDENTIALS); // Must have a specific role to login here if (role && !hasRole(user, role)) throw new UnauthorizedError(errors.NO_PERMISSION); @@ -40,8 +43,6 @@ export async function login(payload: AuthCredentials, role?: Role) { if (!user.hasAccess) throw new UnauthorizedError(errors.USER_INACTIVE); // Match password - const passwordMatch = await comparePassword(password, user.password); - if (!passwordMatch) throw new AuthenticationError(); // Generate JWT and refresh token return await generateTokens(user.id); diff --git a/tests/integration/auth.route.test.ts b/tests/integration/auth.route.test.ts index 788073c..61157fe 100644 --- a/tests/integration/auth.route.test.ts +++ b/tests/integration/auth.route.test.ts @@ -91,7 +91,17 @@ describe('/auth', () => { email: regularUser.email, password: 'invalidPw', }); - + expect(status).toEqual(httpStatus.BAD_REQUEST); + expect(body.errors[0].code).toEqual(errors.USER_INVALID_CREDENTIALS.code); + expect(body.errors[0].detail).toEqual(errors.USER_INVALID_CREDENTIALS.message); + }); + it('Should throw error when invalid user is provided', async () => { + const { body, status } = await request(app) + .post(`${prefix}/auth/login`) + .send({ + email: 'fakeuser@icapps.com', + password: 'invalidPw', + }); expect(status).toEqual(httpStatus.BAD_REQUEST); }); @@ -104,6 +114,8 @@ describe('/auth', () => { }); expect(status).toEqual(httpStatus.BAD_REQUEST); + expect(body.errors[0].code).toEqual(errors.USER_INVALID_CREDENTIALS.code); + expect(body.errors[0].detail).toEqual(errors.USER_INVALID_CREDENTIALS.message); }); it('Should throw error when user has no access', async () => { @@ -112,9 +124,8 @@ describe('/auth', () => { .post(`${prefix}/auth/login`) .send({ email: 'newuser@gmail.com', - password: noAccessUser.password, + password: 'developer', }); - expect(status).toEqual(httpStatus.UNAUTHORIZED); expect(body.errors[0].code).toEqual(errors.USER_INACTIVE.code); expect(body.errors[0].title).toEqual(errors.USER_INACTIVE.message);