Skip to content

Commit 26f2f4a

Browse files
committed
feat: add optional OTP verification for user registration
1 parent 92ddb52 commit 26f2f4a

File tree

7 files changed

+29
-11
lines changed

7 files changed

+29
-11
lines changed

.env.development

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ MAILGUN_FROM_EMAIL="[email protected]"
3131
# ADMIN
3232
ADMIN_EMAIL="[email protected]"
3333
ADMIN_PASSWORD="password"
34+
35+
# USER
36+
OTP_VERIFICATION_ENABLED=0

.env.sample

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,6 @@ MONGO_DATABASE_URL=""
4343
# ADMIN
4444
ADMIN_EMAIL="[email protected]"
4545
ADMIN_PASSWORD="password"
46+
47+
# USER
48+
OTP_VERIFICATION_ENABLED=0

src/config/config.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const configSchema = z.object({
4141
MAILGUN_FROM_EMAIL: z.string().email(),
4242
ADMIN_EMAIL: z.string().email(),
4343
ADMIN_PASSWORD: z.string().min(1),
44+
OTP_VERIFICATION_ENABLED: z.string().transform((value) => !!Number(value)),
4445
});
4546

4647
export type Config = z.infer<typeof configSchema>;

src/modules/auth/auth.controller.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ export const handleRegisterUser = async (
5353
) => {
5454
const user = await registerUserByEmail(req.body);
5555

56+
if (config.OTP_VERIFICATION_ENABLED) {
57+
return successResponse(res, "Please check your email for OTP", user);
58+
}
59+
5660
return successResponse(res, "User has been reigstered", user);
5761
};
5862

src/modules/auth/auth.router.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ authRouter.post(
3737

3838
authRouter.post("/logout", {}, handleLogout);
3939

40-
authRouter.get("/user", {}, canAccess(), handleGetCurrentUser);
40+
authRouter.get("/me", {}, canAccess(), handleGetCurrentUser);
4141

4242
authRouter.post(
4343
"/forget-password",

src/modules/auth/auth.service.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import config from "../../config/config.service";
12
import { ROLE_ENUM, type RoleType, SOCIAL_ACCOUNT_ENUM } from "../../enums";
23
import type { GoogleCallbackQuery } from "../../types";
34
import {
45
type JwtPayload,
56
compareHash,
67
fetchGoogleTokens,
8+
generateOTP,
79
getUserInfo,
810
hashPassword,
911
signToken,
@@ -94,9 +96,10 @@ export const registerUserByEmail = async (
9496

9597
const { confirmPassword, ...rest } = payload;
9698

97-
// OTP is null for now - it will set user as verified
99+
const otp = config.OTP_VERIFICATION_ENABLED ? generateOTP() : null;
100+
98101
const user = await createUser(
99-
{ ...rest, role: "DEFAULT_USER", otp: null },
102+
{ ...rest, role: "DEFAULT_USER", otp },
100103
false,
101104
);
102105

src/utils/auth.utils.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,14 @@ export const fetchGoogleTokens = async (
124124
return data;
125125
};
126126
export interface GoogleUserInfo {
127-
id: string; // User's unique Google ID
128-
email: string; // User's email address
129-
verified_email: boolean; // Whether the email is verified
130-
name: string; // User's full name
131-
given_name: string; // User's given name
132-
family_name: string; // User's family name
133-
picture: string; // URL of the user's profile picture
134-
locale: string; // User's locale
127+
id: string;
128+
email: string;
129+
verified_email: boolean;
130+
name: string;
131+
given_name: string;
132+
family_name: string;
133+
picture: string;
134+
locale: string;
135135
}
136136

137137
export const getUserInfo = async (accessToken: string) => {
@@ -146,3 +146,7 @@ export const getUserInfo = async (accessToken: string) => {
146146
}
147147
return userInfoResponse.json();
148148
};
149+
150+
export const generateOTP = (length = 6): string => {
151+
return crypto.randomBytes(length).toString("hex").slice(0, length);
152+
};

0 commit comments

Comments
 (0)