Skip to content

Fix: authentication logic improved for saving only verified users.#153

Merged
bhavik-mangla merged 4 commits intoAOSSIE-Org:mainfrom
ayush00git:fix/auth-logic-v2
Jan 8, 2026
Merged

Fix: authentication logic improved for saving only verified users.#153
bhavik-mangla merged 4 commits intoAOSSIE-Org:mainfrom
ayush00git:fix/auth-logic-v2

Conversation

@ayush00git
Copy link
Contributor

@ayush00git ayush00git commented Dec 29, 2025

Closes #143
Changes I made -

  • Backend:
  1. Fixed Login handler verification check to block all unverified users.
    Previously it relied on two checks - if password is empty and isVerified = false then only it blocks the user, but if only one was correct like isVerified=false it does not stops the user, i've added a single check to fix this.
  2. SignUp handler now generates jwt token instead of inserting the user to databse.
  3. Refactored VerifyEmail handler to decode jwt token and create verified user.
  • Frontend:
  1. Updated signup() to store jwt token in localStorage.
  2. Updated verifyEmail() to retrieve the token from localStorage and send to backend.

Summary by CodeRabbit

  • New Features

    • Email verification required for new accounts with 24-hour expiry validation
    • Automatic login after successful email verification (access token + user returned)
    • Enhanced verification email content with welcome header and expiration notice
    • Sign-up now returns a generic success response (no user payload)
  • User Flow

    • Login now only requires the account to be verified (relaxed setup checks)
    • Front-end stores access token and full user data on successful verification

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 29, 2025

📝 Walkthrough

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective of saving only verified users by implementing JWT-based signup and database-save-on-verification flow.
Linked Issues check ✅ Passed The PR implements the recommended Opt1 solution: SignUp generates JWT without saving user, VerifyEmail decodes JWT and saves verified user to database, ensuring only verified users are persisted.
Out of Scope Changes check ✅ Passed All changes are directly aligned with fixing the authentication logic per issue #143; frontend updates to email verification UI and minor formatting adjustments are supporting changes within scope.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
backend/controllers/auth.go (1)

594-613: Consider using a separate secret for signup tokens.

Using the same JWT secret for both signup and authentication tokens works due to the type claim differentiation, but using separate secrets would provide better isolation between token types and reduce blast radius if one secret is compromised.

frontend/src/Pages/Authentication/forms.tsx (1)

204-223: Unused email prop after API change.

The email prop is still being passed to OTPVerificationForm but is no longer used since verifyEmail now only takes the OTP code. Consider removing it from the interface if it's not needed elsewhere.

Also, the handleSubmit function lacks a try-catch block. If verifyEmail throws an error (via handleError in authContext), handleOtpVerified() won't be called, but the unhandled rejection could cause issues.

🔎 Proposed fix
 const handleSubmit = async (e: React.FormEvent) => {
   e.preventDefault();
-  await verifyEmail(otp);
-  handleOtpVerified();
+  try {
+    await verifyEmail(otp);
+    handleOtpVerified();
+  } catch {
+    // Error is already handled by authContext
+  }
 };

And if email is truly unused, update the interface:

 interface OTPVerificationFormProps {
-  email: string;
   handleOtpVerified: () => void;
 }

-export const OTPVerificationForm: React.FC<OTPVerificationFormProps> = ({ email, handleOtpVerified }) => {
+export const OTPVerificationForm: React.FC<OTPVerificationFormProps> = ({ handleOtpVerified }) => {
frontend/src/context/authContext.tsx (1)

192-253: LGTM with a minor suggestion.

The verification flow correctly retrieves the signup token, sends it for validation, and handles the successful response by storing the auth token and user data.

Consider also clearing the signupToken from localStorage when the backend returns an "expired token" error, so users aren't stuck with a stale token:

🔎 Optional enhancement
      if (!response.ok) {
        const data = await response.json();
+       // Clear stale token if expired
+       if (data.error?.includes('expired')) {
+         localStorage.removeItem('signupToken');
+       }
        throw new Error(data.error || 'Verification failed');
      }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1f8db72 and e90ed39.

📒 Files selected for processing (5)
  • backend/controllers/auth.go
  • backend/structs/auth.go
  • backend/utils/email.go
  • frontend/src/Pages/Authentication/forms.tsx
  • frontend/src/context/authContext.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/src/context/authContext.tsx (2)
backend/models/user.go (1)
  • User (10-35)
frontend/src/types/user.ts (1)
  • User (1-21)
backend/controllers/auth.go (2)
backend/db/db.go (1)
  • MongoDatabase (18-18)
backend/utils/auth.go (2)
  • ExtractNameFromEmail (44-51)
  • Claims (68-73)
🔇 Additional comments (6)
backend/utils/email.go (1)

44-46: LGTM!

The updated email content with the welcome header and 24-hour expiration notice aligns correctly with the signup JWT expiration time defined in the backend.

backend/structs/auth.go (1)

8-11: LGTM!

The struct correctly reflects the new token-based verification flow. The email is now extracted from the JWT token on the backend, so only the token and confirmation code are needed from the client.

backend/controllers/auth.go (3)

160-178: LGTM!

The signup flow correctly defers user creation by generating a signed JWT containing the necessary user data. The token will be validated during email verification.


293-297: LGTM!

The simplified verification check is correct. With the new flow where users are only created after email verification, this serves as an appropriate safety check.


615-653: LGTM!

The validation function properly checks the token type to prevent token confusion attacks and correctly extracts all required claims with appropriate error handling.

frontend/src/context/authContext.tsx (1)

179-184: LGTM!

The signup function correctly stores the signup token for use during the email verification step.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/controllers/auth.go (1)

160-201: Critical: Implementation doesn't match PR objectives.

The PR objectives clearly state: "SignUp handler now generates a JWT token instead of inserting the user into the database" and "Opt1 (preferred): Do not save user to the database at signup."

However, the current implementation does insert the user into the database at signup (lines 182-188), contradicting the stated approach. This means:

  1. Unverified users are still persisted — the original issue (#143) where unverified users clutter the database is not resolved
  2. Unverified users can still appear in queries — any code that queries the users collection will see unverified accounts
  3. The JWT-based helper functions (lines 598-657) exist but are never used, creating confusion

The implementation appears to be a hybrid approach that wasn't fully completed. Either:

  • Complete the JWT-based flow by removing the DB insert here and calling generateSignupJWT instead, OR
  • Update the PR objectives to reflect that this is actually a DB-based approach with verification checks
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e90ed39 and ed99f6b.

📒 Files selected for processing (3)
  • backend/controllers/auth.go
  • frontend/src/Pages/Authentication/forms.tsx
  • frontend/src/context/authContext.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/Pages/Authentication/forms.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/src/context/authContext.tsx (2)
backend/models/user.go (1)
  • User (10-35)
frontend/src/types/user.ts (1)
  • User (1-21)
backend/controllers/auth.go (4)
backend/models/user.go (1)
  • User (10-35)
frontend/src/types/user.ts (1)
  • User (1-21)
backend/db/db.go (1)
  • MongoDatabase (18-18)
backend/utils/auth.go (1)
  • Claims (68-73)
🔇 Additional comments (8)
frontend/src/context/authContext.tsx (3)

197-198: Error field changed to align with backend response.

Good change to extract the error from data.error instead of data.message for consistency with the backend error response format.


200-232: Automatic login after verification implemented correctly.

The new flow appropriately handles successful email verification by:

  • Storing the access token
  • Building a fully normalized user object with isVerified: true
  • Persisting both token and user to localStorage
  • Navigating to the home page

This provides a smooth user experience by eliminating the need for a separate login step after verification.


25-25: AI summary appears incorrect.

The verifyEmail function signature in the interface at line 25 correctly matches its implementation and actual usage. The function is called with both email and code parameters at frontend/src/Pages/Authentication/forms.tsx:221 (await verifyEmail(email, otp)), which aligns with the interface definition (email: string, code: string) => Promise<void>. The AI summary claiming the signature should be (code: string) => Promise<void> does not reflect the actual requirements of the code.

backend/controllers/auth.go (5)

175-177: Gamification fields initialized correctly.

The initialization of Score, Badges, and CurrentStreak for new users is appropriate and prevents null/undefined issues.


215-226: User lookup changed to database query.

The implementation now finds the user in the database using email and verification code. This is a reasonable approach for a DB-based verification flow.

However, this contradicts the PR objectives which state: "Refactored VerifyEmail handler to decode the JWT token and create the verified user in the database." The current code doesn't decode any JWT from the request.


228-232: 24-hour verification expiry enforced.

Good addition to prevent stale verification codes from being used indefinitely. The check correctly compares user.CreatedAt to the current time.


249-266: Immediate login after verification implemented.

The flow correctly:

  • Updates the local user object after database update
  • Generates a JWT token for the verified user
  • Returns both the access token and user details

This provides a smooth UX by automatically logging in users after verification.


298-298: Login verification check simplified.

The condition is now straightforward: if !user.IsVerified. This correctly blocks all unverified users from logging in, which was the original issue.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/controllers/auth.go (1)

140-148: Unverified users with expired codes get locked out.

If a user signs up but never verifies within 24 hours, their verification code expires (line 229). However, since the user record still exists in the database, any subsequent signup attempt with the same email fails with "User already exists". The user cannot:

  1. Sign up again (blocked by this check)
  2. Verify (code expired)
  3. Log in (blocked by verification check)

Consider either:

  • Allowing re-signup for unverified users with expired codes (overwrite or delete the old record)
  • Adding a TTL index on MongoDB to auto-delete unverified users after 24 hours
  • Implementing a "resend verification code" flow
🔎 Suggested fix to handle expired unverified users
 err := db.MongoDatabase.Collection("users").FindOne(dbCtx, bson.M{"email": request.Email}).Decode(&existingUser)
 if err == nil {
+	// If user exists but is unverified and code expired, delete and allow re-signup
+	if !existingUser.IsVerified && time.Since(existingUser.CreatedAt) > 24*time.Hour {
+		_, delErr := db.MongoDatabase.Collection("users").DeleteOne(dbCtx, bson.M{"_id": existingUser.ID})
+		if delErr != nil {
+			ctx.JSON(500, gin.H{"error": "Database error", "message": delErr.Error()})
+			return
+		}
+		// Continue with signup
+	} else {
 		ctx.JSON(400, gin.H{"error": "User already exists"})
 		return
+	}
 }
🧹 Nitpick comments (1)
backend/controllers/auth.go (1)

190-195: Consider rollback if email sending fails.

If SendVerificationEmail fails after the user is inserted (line 183), the user record remains in the database without the user receiving their verification code. This creates an orphaned record. The user would need to wait 24 hours for the code to "expire" before re-signup works (assuming the previous suggestion is implemented).

Consider wrapping the insert and email send in a transaction-like pattern, or deleting the user if email fails.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ed99f6b and fe94017.

📒 Files selected for processing (1)
  • backend/controllers/auth.go
🔇 Additional comments (2)
backend/controllers/auth.go (2)

215-266: LGTM! Verification flow with immediate login is well-implemented.

The changes add proper verification logic:

  • Looking up by both email and verification code prevents enumeration attacks
  • The 24-hour expiry check provides reasonable security
  • Generating a JWT on successful verification improves UX by eliminating a separate login step

Note: If a "resend verification code" feature is added later, consider tracking verificationCodeCreatedAt separately from CreatedAt to accurately enforce expiry on the new code.


297-301: LGTM! Login verification check correctly blocks unverified users.

The simplified !user.IsVerified check properly addresses issue #143 by blocking all unverified users from logging in, regardless of other conditions. This is cleaner and more secure than the previous multi-condition check.

@ayush00git
Copy link
Contributor Author

@bhavik-mangla
I tried to store the data of user in jwt token temporarily but it was causing a security issue as mentioned by coderabbit , so i shifted my approach -> unverified users are now stored in DB with verification codes that gets expire after 24 hours, and only verified users can login. Still to prevent clutter in the db we can add a helper function which automatically erases the users with isVerified=false flag.
If you want me to implement that also do let me know.
Thanks : )

@ayush00git
Copy link
Contributor Author

Hey @bhavik-mangla
Could you pls review this PR, there was a bug in the site which was allowing the unverified users to enter, but i have solved it and alongwith that also added a solution for the unverified users in the db.
Please give it a look : )

@ayush00git
Copy link
Contributor Author

Hey @bhavik-mangla can you please review this PR.
waiting for your response : )

@bhavik-mangla
Copy link
Contributor

@ayush00git could you include testing evidence of new flow of auth

@bhavik-mangla
Copy link
Contributor

Looks good

@bhavik-mangla
Copy link
Contributor

good work @ayush00git

@bhavik-mangla bhavik-mangla merged commit 8bdc593 into AOSSIE-Org:main Jan 8, 2026
1 check passed
@ayush00git
Copy link
Contributor Author

good work @ayush00git

Thanks a lot @bhavik-mangla

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Missing logic in authentication

2 participants