Skip to content

Commit

Permalink
feat(authentication): add qr code library for 2fa authentication (#283)
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisPdgn authored Aug 23, 2022
1 parent 26d0a09 commit 37a6fa9
Show file tree
Hide file tree
Showing 8 changed files with 364 additions and 72 deletions.
1 change: 1 addition & 0 deletions modules/authentication/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"node-2fa": "^2.0.3",
"uuid": "^8.3.2"
},
"devDependencies": {
Expand Down
71 changes: 71 additions & 0 deletions modules/authentication/src/TwoFactorAuth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as twoFactor from 'node-2fa';
import ConduitGrpcSdk, { ConfigController, GrpcError } from '@conduitplatform/grpc-sdk';
import { status } from '@grpc/grpc-js';
import { AccessToken, RefreshToken, TwoFactorSecret, User } from './models';
import { isNil } from 'lodash';
import { AuthUtils } from './utils/auth';
import { ISignTokenOptions } from './interfaces/ISignTokenOptions';
import moment from 'moment';

export namespace TwoFactorAuth {
export function generateSecret(options?: { name: string; account: string }) {
return twoFactor.generateSecret(options);
}

export function generateToken(secret: string) {
return twoFactor.generateToken(secret);
}

export function verifyToken(secret: string, token?: string, window?: number) {
return twoFactor.verifyToken(secret, token, window);
}

export async function verifyCode(
grpcSdk: ConduitGrpcSdk,
clientId: string,
user: User,
code: string,
): Promise<{ userId: string; accessToken: string; refreshToken: string }> {
const secret = await TwoFactorSecret.getInstance().findOne({
userId: user._id,
});
if (isNil(secret)) throw new GrpcError(status.NOT_FOUND, 'Verification unsuccessful');

const verification = verifyToken(secret.secret, code);
if (isNil(verification)) {
throw new GrpcError(status.UNAUTHENTICATED, 'Verification unsuccessful');
}
await Promise.all(
AuthUtils.deleteUserTokens(grpcSdk, {
userId: user._id,
clientId,
}),
);
const config = ConfigController.getInstance().config;
const signTokenOptions: ISignTokenOptions = {
secret: config.jwtSecret,
expiresIn: config.tokenInvalidationPeriod,
};
const accessToken: AccessToken = await AccessToken.getInstance().create({
userId: user._id,
clientId,
token: AuthUtils.signToken({ id: user._id }, signTokenOptions),
expiresOn: moment()
.add(config.tokenInvalidationPeriod as number, 'milliseconds')
.toDate(),
});
const refreshToken: RefreshToken = await RefreshToken.getInstance().create({
userId: user._id,
clientId,
token: AuthUtils.randomToken(),
expiresOn: moment()
.add(config.refreshTokenInvalidationPeriod as number, 'milliseconds')
.toDate(),
});
return {
userId: user._id.toString(),
accessToken: accessToken.token,
refreshToken: refreshToken.token,
};
}
}
1 change: 1 addition & 0 deletions modules/authentication/src/constants/TokenType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export enum TokenType {
CHANGE_EMAIL_TOKEN = 'CHANGE_EMAIL_TOKEN',
TWO_FA_VERIFICATION_TOKEN = 'TWO_FA_VERIFICATION_TOKEN',
VERIFY_PHONE_NUMBER_TOKEN = 'VERIFY_PHONE_NUMBER_TOKEN',
VERIFY_QR_TOKEN = 'VERIFY_QR_TOKEN',
LOGIN_WITH_PHONE_NUMBER_TOKEN = 'LOGIN_WITH_PHONE_NUMBER_TOKEN',
}
Loading

0 comments on commit 37a6fa9

Please sign in to comment.