Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ Upgrade to next-auth v5 #1547

Merged
merged 18 commits into from
Feb 8, 2025
Merged

♻️ Upgrade to next-auth v5 #1547

merged 18 commits into from
Feb 8, 2025

Conversation

lukevella
Copy link
Owner

@lukevella lukevella commented Feb 6, 2025

Summary by CodeRabbit

  • New Features

    • Introduced additional authentication options, including new sign-in methods for email, social, and guest access.
    • Added a new EmailProvider for enhanced email verification processes.
    • Integrated OIDCProvider and MicrosoftProvider for OpenID Connect and Microsoft authentication.
    • Implemented a RegistrationTokenProvider for user registration without email verification.
    • Added a new function to aggregate optional authentication providers.
  • Improvements

    • Enhanced redirection behavior during sign-in, account deletion, and login flows for a smoother user experience.
    • Streamlined session handling and middleware to ensure more consistent authentication processes.
    • Updated parameter handling for redirection URLs across various components.
    • Integrated improved analytics tracking for monitoring authentication events.
    • Upgraded external dependencies to leverage advanced capabilities and improved security.
    • Introduced a new method for handling user session retrieval.
    • Enhanced user information in session management with optional email property.
    • Required user ID property added to user management for improved session integrity.

Copy link

vercel bot commented Feb 6, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
app ✅ Ready (Inspect) Visit Preview 💬 Add feedback Feb 8, 2025 2:30am
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
landing ⬜️ Skipped (Inspect) Feb 8, 2025 2:30am

Copy link
Contributor

coderabbitai bot commented Feb 6, 2025

Walkthrough

This update revises the authentication flow across the application. It updates the NextAuth declarations by adding a required id field in the User interface and adjusts associated JWT and session types. Several UI components now pass redirectTo instead of callbackUrl for sign-in/out actions. Across API routes, middleware, and TRPC handlers, the session retrieval method has shifted from getServerSession() to auth(), with PostHog analytics now integrated into selected endpoints. Additionally, the legacy auth file was removed, new authentication providers were implemented, and package dependencies were updated.

Changes

File(s) Change Summary
apps/web/declarations/next-auth.d.ts, apps/web/src/next-auth.ts, apps/web/src/next-auth.config.ts Updated NextAuth configuration and TypeScript declarations: added required id to User, enriched JWT/session types, and introduced a new NextAuth config object.
apps/web/package.json, package.json Upgraded dependency versions (@auth/prisma-adapter, next-auth) and added an empty "dependencies" key with minor formatting adjustments.
apps/web/src/app/[locale]/(admin)/settings/profile/delete-account-dialog.tsx, apps/web/src/app/[locale]/(auth)/login/components/*.tsx, apps/web/src/app/[locale]/(auth)/login/page.tsx Renamed parameters from callbackUrl to redirectTo in signIn/signOut functions; updated provider name checks and refined OAuth provider retrieval.
apps/web/src/app/api/auth/[...nextauth]/route.ts, apps/web/src/app/api/notifications/unsubscribe/route.ts, apps/web/src/app/api/stripe/checkout/route.ts, apps/web/src/app/api/stripe/portal/route.ts, apps/web/src/app/api/trpc/[trpc]/route.ts, apps/web/src/app/api/user/verify-email-change/route.ts, apps/web/src/pages/api/auth/[...nextauth].ts, apps/web/src/trpc/server/create-ssr-helper.ts Replaced getServerSession() with auth() for session retrieval; integrated PostHog analytics in auth routes; removed the legacy API route file.
apps/web/src/middleware.ts Overhauled middleware to use NextAuth’s auth function with updated extraction of user email and locale.
apps/web/src/auth.ts (removed), apps/web/src/auth/adapters/prisma.ts, apps/web/src/auth/get-optional-providers.ts, apps/web/src/auth/is-email-blocked.ts, apps/web/src/auth/providers/* Removed the old auth file; refactored the Prisma adapter to use a direct prisma instance; added helper functions and new providers (Email, Google, Guest, Microsoft, OIDC, Registration Token).
apps/web/src/app/[locale]/(auth)/login/actions.ts, packages/posthog/src/server/index.ts Modified the email verification logic to use findUnique and relocated cookie-setting; introduced a new withPosthog function to wrap handlers for analytics.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant LC as Login Component
    participant NA as NextAuth (auth function)
    U->>LC: Enter credentials and submit
    LC->>NA: call signIn(redirectTo)
    NA->>LC: Return authentication result
    LC->>U: Redirect based on result
Loading
sequenceDiagram
    participant U as User
    participant AR as API Route
    participant PH as PostHog Wrapper
    U->>AR: Send authentication API request
    AR->>PH: withPosthog(handler) wraps auth()
    PH->>AR: Invoke handler (auth())
    AR->>U: Return response
    PH->>PH: Flush PostHog events
Loading

Possibly related PRs

  • ♻️ Move auth #1422: The changes in the main PR, which involve modifications to the next-auth module's TypeScript declarations, are related to the changes in the retrieved PR that also involve the auth.ts file, specifically in how user sessions and authentication logic are handled, including the integration of the isEmailBlocked function.
  • ♻️ Clean up login page code #1525: The changes in the main PR, specifically the updates to the signIn function calls across various components to replace callbackUrl with redirectTo, are directly related to the modifications in the retrieved PR, which also involves changes to the LoginWithOIDC component that affect how parameters are handled for sign-in.

Poem

I hop through code with joyful might,
New auth flows gleam in the night.
Tokens and redirects dance in tune,
Providers bloom like springtime June.
With each update, my heart feels light—
A rabbit’s code, pure delight!
🥕🐇


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@vercel vercel bot temporarily deployed to Preview – landing February 6, 2025 08:34 Inactive
Copy link
Contributor

@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: 15

🔭 Outside diff range comments (2)
apps/web/src/auth.ts (1)

198-200: Ensure compatibility of replaceAll method and fix regex in isEmailBlocked.

The use of replaceAll at line 200 may not be supported in all environments, as it was introduced in ES2021. Consider using replace instead. Additionally, the regex /[*]/g can be simplified to /\*/g.

Apply this diff to fix the method and regex:

- .replace(/[.+?^${}()|[\]\\]/g, "\\$&")
- .replaceAll(/[*]/g, ".*")
+ .replace(/[.+?^${}()|[\]\\]/g, "\\$&")
+ .replace(/\*/g, ".*")
apps/web/src/app/api/user/verify-email-change/route.ts (1)

57-57: Update URL parameter from callbackUrl to redirectTo.

Next-auth v5 uses redirectTo instead of callbackUrl for redirection parameters.

-      new URL(`/login?callbackUrl=${request.url}`, request.url),
+      new URL(`/login?redirectTo=${request.url}`, request.url),
🧹 Nitpick comments (16)
apps/web/src/auth.ts (1)

192-210: Avoid code duplication by importing isEmailBlocked from a shared module.

The isEmailBlocked function is defined here but is also imported in other files (e.g., in next-auth.ts). To maintain consistency and reduce duplication, consider moving isEmailBlocked to a shared module and importing it where needed.

apps/web/src/auth/providers/guest.ts (1)

8-13: Consider adding rate limiting for guest authentication.

While the implementation is functional, it could benefit from rate limiting to prevent abuse.

Consider implementing rate limiting using a library like express-rate-limit or similar:

  async authorize() {
+   // Add rate limiting logic here
+   const rateLimit = await checkRateLimit(req.ip);
+   if (!rateLimit.success) {
+     throw new Error('Too many guest accounts created. Please try again later.');
+   }
    return {
      id: `user-${randomid()}`,
      email: null,
    };
  },
apps/web/src/auth/get-optional-providers.ts (1)

7-11: LGTM! Consider documenting provider order.

The implementation effectively aggregates optional providers and filters out undefined ones. Consider adding a comment explaining if the order of providers is significant for UI presentation.

 export function getOptionalProviders() {
+  // Note: Provider order determines the order of login buttons in the UI
   return [OIDCProvider(), GoogleProvider(), MicrosoftProvider()].filter(
     Boolean,
   ) as Provider[];
 }
apps/web/src/auth/providers/microsoft.ts (1)

3-17: Consider adding error logging for missing configuration.

The function correctly checks for required environment variables but silently returns undefined when configuration is missing. Consider adding error logging to help with debugging configuration issues.

 export function MicrosoftProvider() {
+  const missingVars = [
+    ["MICROSOFT_TENANT_ID", process.env.MICROSOFT_TENANT_ID],
+    ["MICROSOFT_CLIENT_ID", process.env.MICROSOFT_CLIENT_ID],
+    ["MICROSOFT_CLIENT_SECRET", process.env.MICROSOFT_CLIENT_SECRET],
+  ].filter(([_, value]) => !value).map(([name]) => name);
+
+  if (missingVars.length > 0) {
+    console.warn(
+      `Microsoft provider disabled due to missing environment variables: ${missingVars.join(", ")}`,
+    );
+    return;
+  }
+
   if (
     process.env.MICROSOFT_TENANT_ID &&
     process.env.MICROSOFT_CLIENT_ID &&
     process.env.MICROSOFT_CLIENT_SECRET
   ) {
apps/web/src/auth/is-email-blocked.ts (1)

1-19: Add input validation and optimize performance.

The implementation correctly handles email patterns but could benefit from the following improvements:

  1. Input validation for the email parameter
  2. Caching of compiled regex patterns
  3. Memoization of environment variable parsing
+const getAllowedEmailPatterns = (() => {
+  let patterns: RegExp[] | undefined;
+  return () => {
+    if (!patterns && process.env.ALLOWED_EMAILS) {
+      patterns = process.env.ALLOWED_EMAILS.split(",").map(
+        (allowedEmail) =>
+          new RegExp(
+            `^${allowedEmail
+              .replace(/[.+?^${}()|[\]\\]/g, "\\$&")
+              .replaceAll(/[*]/g, ".*")}$`,
+          ),
+      );
+    }
+    return patterns;
+  };
+})();
+
 export const isEmailBlocked = (email: string) => {
+  if (!email || typeof email !== "string") {
+    return true;
+  }
+
   if (process.env.ALLOWED_EMAILS) {
-    const allowedEmails = process.env.ALLOWED_EMAILS.split(",");
-    // Check whether the email matches enough of the patterns specified in ALLOWED_EMAILS
-    const isAllowed = allowedEmails.some((allowedEmail) => {
-      const regex = new RegExp(
-        `^${allowedEmail
-          .replace(/[.+?^${}()|[\]\\]/g, "\\$&")
-          .replaceAll(/[*]/g, ".*")}$`,
-      );
-      return regex.test(email);
-    });
+    const patterns = getAllowedEmailPatterns();
+    const isAllowed = patterns?.some((pattern) => pattern.test(email)) ?? false;

     if (!isAllowed) {
       return true;
     }
   }
   return false;
 };
apps/web/src/app/[locale]/(auth)/login/components/login-with-oidc.tsx (1)

8-12: Consider renaming the prop for consistency.

The prop name callbackUrl is inconsistent with the new redirectTo parameter used in the signIn options. Consider renaming the prop to match the new parameter name for better maintainability.

 export async function LoginWithOIDC({
   name,
-  callbackUrl,
+  redirectTo,
 }: {
   name: string;
-  callbackUrl?: string;
+  redirectTo?: string;
 }) {
   return (
     <Button
       onClick={() => {
         signIn("oidc", {
-          redirectTo: callbackUrl,
+          redirectTo,
         });

Also applies to: 18-18

packages/posthog/src/server/index.ts (1)

18-24: Consider handling null posthog client explicitly.

The posthogApiHandler function should handle the case where posthog is null more explicitly to avoid unnecessary waitUntil calls.

 export function posthogApiHandler() {
+  if (!posthog) return;
   try {
-    waitUntil(Promise.all([posthog?.shutdown()]));
+    waitUntil(Promise.all([posthog.shutdown()]));
   } catch (error) {
     console.error("Failed to flush PostHog events:", error);
   }
 }
apps/web/src/auth/providers/email.ts (2)

12-14: Add return type to generateVerificationToken.

For better type safety and documentation, consider adding an explicit return type to the function.

-  generateVerificationToken() {
+  generateVerificationToken(): string {
     return generateOtp();
   },

8-10: Document the "none" server value.

The comment about the required "none" value could be more descriptive to explain why it's needed and what it does.

 export const EmailProvider = NodemailerProvider({
-  server: "none", // This value is required even though we don't need it
+  server: "none", // Required by NodemailerProvider but not used since we handle email sending ourselves
apps/web/src/trpc/server/create-ssr-helper.ts (1)

39-41: Consider adding error logging before redirect.

Error information might be useful for debugging authentication issues.

 } catch (error) {
+  console.error("SSR helper creation failed:", error);
   return redirect("/login");
 }
apps/web/src/app/[locale]/layout.tsx (1)

33-33: Consider adding error boundary for auth failures.

While the migration to auth() is correct, adding error handling would improve reliability.

-  const session = await auth();
+  try {
+    const session = await auth();
+  } catch (error) {
+    console.error("Authentication failed:", error);
+    // Return a minimal session state or redirect as needed
+  }
apps/web/src/auth/providers/registration-token.ts (1)

39-42: Add logging for failed registration attempts.

For security monitoring, consider logging failed registration attempts.

 if (user) {
   return user;
+} else {
+  console.warn(`Failed registration attempt for email: ${payload.email}`);
 }
apps/web/src/auth/adapters/prisma.ts (2)

13-13: Consider keeping the client parameter for better flexibility.

While using a direct prisma import simplifies the code, it reduces flexibility for testing and dependency injection. Consider keeping the client parameter or using a dependency injection pattern.

-import { prisma } from "@rallly/database";
+import type { ExtendedPrismaClient } from "@rallly/database";

-export function CustomPrismaAdapter(options: {
+export function CustomPrismaAdapter(
+  client: ExtendedPrismaClient,
+  options: {
   migrateData: (userId: string) => Promise<void>;
-}) {
+}) {
-  const adapter = PrismaAdapter(prisma);
+  const adapter = PrismaAdapter(client);

Also applies to: 14-14, 16-20


40-40: Use satisfies instead of as type assertion.

Using satisfies provides better type safety than as by validating the object shape at compile time.

-  } as Adapter;
+  } satisfies Adapter;
apps/web/src/app/[locale]/(auth)/login/page.tsx (1)

72-73: Add fallback for provider name.

Consider adding a more robust fallback for provider name to handle undefined options.

-  name={provider.options?.name || provider.name}
+  name={provider.options?.name ?? provider.name ?? provider.id}
apps/web/src/app/[locale]/(admin)/settings/profile/delete-account-dialog.tsx (1)

41-41: Consider making the redirect path configurable.

While the parameter rename from callbackUrl to redirectTo is correct for next-auth v5, consider making the redirect path configurable rather than hardcoding it to "/login". This would make the component more reusable and maintainable.

-        redirectTo: "/login",
+        redirectTo: process.env.NEXT_PUBLIC_AUTH_REDIRECT_PATH ?? "/login",
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 480f1a0 and 88b9de5.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (31)
  • apps/web/declarations/next-auth.d.ts (1 hunks)
  • apps/web/package.json (2 hunks)
  • apps/web/src/app/[locale]/(admin)/settings/profile/delete-account-dialog.tsx (1 hunks)
  • apps/web/src/app/[locale]/(auth)/login/components/login-email-form.tsx (1 hunks)
  • apps/web/src/app/[locale]/(auth)/login/components/login-with-oidc.tsx (1 hunks)
  • apps/web/src/app/[locale]/(auth)/login/components/sso-provider.tsx (2 hunks)
  • apps/web/src/app/[locale]/(auth)/login/page.tsx (3 hunks)
  • apps/web/src/app/[locale]/layout.tsx (2 hunks)
  • apps/web/src/app/api/auth/[...nextauth]/route.ts (1 hunks)
  • apps/web/src/app/api/notifications/unsubscribe/route.ts (2 hunks)
  • apps/web/src/app/api/stripe/checkout/route.ts (2 hunks)
  • apps/web/src/app/api/stripe/portal/route.ts (2 hunks)
  • apps/web/src/app/api/trpc/[trpc]/route.ts (2 hunks)
  • apps/web/src/app/api/user/verify-email-change/route.ts (2 hunks)
  • apps/web/src/auth.ts (3 hunks)
  • apps/web/src/auth/adapters/prisma.ts (2 hunks)
  • apps/web/src/auth/get-optional-providers.ts (1 hunks)
  • apps/web/src/auth/is-email-blocked.ts (1 hunks)
  • apps/web/src/auth/providers/email.ts (1 hunks)
  • apps/web/src/auth/providers/google.ts (1 hunks)
  • apps/web/src/auth/providers/guest.ts (1 hunks)
  • apps/web/src/auth/providers/microsoft.ts (1 hunks)
  • apps/web/src/auth/providers/oidc.ts (1 hunks)
  • apps/web/src/auth/providers/registration-token.ts (1 hunks)
  • apps/web/src/features/quick-create/lib/get-guest-polls.ts (1 hunks)
  • apps/web/src/middleware.ts (2 hunks)
  • apps/web/src/next-auth.confg.ts (1 hunks)
  • apps/web/src/next-auth.ts (1 hunks)
  • apps/web/src/pages/api/auth/[...nextauth].ts (0 hunks)
  • apps/web/src/trpc/server/create-ssr-helper.ts (1 hunks)
  • packages/posthog/src/server/index.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/src/pages/api/auth/[...nextauth].ts
🧰 Additional context used
📓 Learnings (1)
apps/web/src/auth/is-email-blocked.ts (1)
Learnt from: lukevella
PR: lukevella/rallly#1189
File: apps/web/src/utils/auth.ts:202-202
Timestamp: 2024-11-12T09:08:14.221Z
Learning: The `isEmailBlocked()` function in `apps/web/src/utils/auth.ts` is not asynchronous.
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Unit tests
  • GitHub Check: Integration tests
  • GitHub Check: Type check
  • GitHub Check: Linting
🔇 Additional comments (14)
apps/web/src/middleware.ts (1)

25-68: Middleware logic correctly updated to use auth from NextAuth v5.

The middleware function has been appropriately updated to use auth instead of withAuth, aligning with NextAuth v5 changes. The authentication flow and user data handling are correctly implemented.

apps/web/src/app/api/auth/[...nextauth]/route.ts (1)

1-6: LGTM! Good integration of analytics with auth handlers.

The implementation correctly wraps the NextAuth handlers with PostHog analytics while maintaining the core authentication functionality.

apps/web/src/features/quick-create/lib/get-guest-polls.ts (1)

3-3: LGTM! Correctly updated to next-auth v5.

The changes correctly update the session retrieval method to use the new auth() function from next-auth v5.

Also applies to: 6-6

apps/web/declarations/next-auth.d.ts (1)

22-24: LGTM!

The addition of the required id field to the User interface is correct and aligns with next-auth v5 requirements. The change maintains consistency with the existing Session interface which already includes the id field.

apps/web/src/auth/providers/oidc.ts (1)

23-23: ⚠️ Potential issue

Review security implications of allowDangerousEmailAccountLinking.

Setting allowDangerousEmailAccountLinking: true could potentially lead to account hijacking if the OIDC provider's email verification process is not robust.

Consider implementing additional safeguards or documenting the security implications in the codebase.

apps/web/src/trpc/server/create-ssr-helper.ts (1)

12-12: LGTM! Correct usage of next-auth v5's auth() function.

The migration from getServerSession() to auth() is implemented correctly.

apps/web/src/app/api/trpc/[trpc]/route.ts (1)

7-7: LGTM! Correctly migrated to next-auth v5.

The changes follow the next-auth v5 upgrade guide by replacing getServerSession with the new auth() function.

Let's verify that we're using the latest version of next-auth:

Also applies to: 18-18

✅ Verification successful

🌐 Web query:

What is the latest version of next-auth/auth.js?

💡 Result:

NextAuth.js (now part of Auth.js) has two relevant versions as of February 2025:

1. **Latest stable release**:  
   `v4.24.11` - Published December 6, 2024[9][10]

2. **Upcoming major release**:  
   `v5.x-beta` - Currently in public beta testing with features like:
   - App Router-first architecture[4][6]
   - Edge compatibility[4]
   - Simplified environment variable handling (`AUTH_*` prefix)[6]
   - Unified `auth()` method replacing older APIs[4][6]

To install the beta:  
```bash
npm install next-auth@beta
```

The Auth.js project (encompassing NextAuth.js) now uses semantic versioning where:
- `next-auth` refers specifically to Next.js integrations[2][8]
- All framework integrations share a common `@auth/core` library[2][8]

Key changes in v5 include stricter OAuth compliance and dropping support for Next.js <14[4]. Database schemas remain compatible with v4[4].

Citations:

- 1: https://next-auth.js.org/getting-started/upgrade-v4
- 2: https://authjs.dev/contributors
- 3: https://www.npmjs.com/package/next-auth/v/5.0.0-beta.19
- 4: https://authjs.dev/getting-started/migrating-to-v5
- 5: https://www.npmjs.com/package/next-auth?activeTab=versions
- 6: https://authjs.dev/reference/nextjs
- 7: https://next-auth.js.org/v3/contributors
- 8: https://next-auth.js.org
- 9: https://www.npmjs.com/package/next-auth
- 10: https://github.com/nextauthjs/next-auth/actions/runs/9997732960

Verified: Migration to Next-Auth v5 is Correct
The web query confirms that next-auth has released a v5.x-beta version featuring the unified auth() function in place of getServerSession. The code's import of auth from "@/next-auth" aligns with the migration guidelines for next-auth v5. Make sure the dependency in your package.json is set to next-auth@beta as required.

apps/web/src/app/api/user/verify-email-change/route.ts (1)

6-6: LGTM! Correctly migrated to next-auth v5.

The changes follow the next-auth v5 upgrade guide by replacing getServerSession with the new auth() function.

Also applies to: 53-53

apps/web/src/app/api/notifications/unsubscribe/route.ts (1)

6-6: LGTM! Correctly migrated to next-auth v5.

The changes follow the next-auth v5 upgrade guide by replacing getServerSession with the new auth() function.

Also applies to: 17-17

apps/web/src/app/[locale]/(auth)/login/components/sso-provider.tsx (2)

18-18: LGTM! Provider name updated to reflect Microsoft's rebranding.

The change from "azure-ad" to "microsoft-entra-id" aligns with Microsoft's rebranding of Azure Active Directory to Microsoft Entra ID.


61-61: Verify the parameter rename across the codebase.

The change from callbackUrl to redirectTo is part of the next-auth v5 upgrade. Let's verify this change is consistently applied across the codebase.

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Search for any remaining instances of callbackUrl in authentication flows
rg -g '*.{ts,tsx}' 'callbackUrl.*signIn'

Length of output: 42


Let's run an additional search for any remaining uses of the string "callbackUrl" in our TypeScript/TSX files, not just in connection with signIn. This helps us ensure that the parameter rename to "redirectTo" is consistently applied. For example, we can search for occurrences with object notation (using "callbackUrl:") and also any loose occurrences.

Once we have the results from the above search, we can confirm if any instances remain or if the rename is consistently applied.


🏁 Script executed:

#!/bin/bash
echo "Searching for 'callbackUrl:' usage:"
rg -g '*.{ts,tsx}' 'callbackUrl:'
echo "-----------------------------"
echo "Searching for any occurrence of 'callbackUrl':"
rg -g '*.{ts,tsx}' 'callbackUrl'

Length of output: 2521


Parameter rename verified across signIn flows.
The search results confirm that all areas where the next-auth parameter is passed to signIn now use the new redirectTo property (e.g., in sso-provider.tsx, login-email-form.tsx, and login-with-oidc.tsx). Remaining instances of "callbackUrl" are used to read query parameters or construct URLs, which is the expected behavior.

apps/web/src/app/api/stripe/portal/route.ts (1)

8-8: LGTM! Updated to next-auth v5's session handling.

The change from getServerSession to auth() aligns with next-auth v5's new session handling approach. Error handling remains robust.

Also applies to: 35-35

apps/web/src/app/api/stripe/checkout/route.ts (1)

8-8: LGTM! Consistent update to next-auth v5's session handling.

The change from getServerSession to auth() maintains consistency with next-auth v5's new session handling approach.

Also applies to: 17-17

apps/web/src/app/[locale]/(auth)/login/components/login-email-form.tsx (1)

56-56: LGTM: Parameter renamed to match next-auth v5 API.

The change from callbackUrl to redirectTo aligns with the next-auth v5 API changes.

apps/web/src/middleware.ts Outdated Show resolved Hide resolved
apps/web/src/middleware.ts Outdated Show resolved Hide resolved
apps/web/src/next-auth.ts Outdated Show resolved Hide resolved
apps/web/src/next-auth.confg.ts Outdated Show resolved Hide resolved
apps/web/src/auth/providers/google.ts Show resolved Hide resolved
apps/web/src/app/[locale]/(auth)/login/page.tsx Outdated Show resolved Hide resolved
apps/web/package.json Show resolved Hide resolved
Copy link
Contributor

@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

🧹 Nitpick comments (1)
apps/web/src/app/[locale]/(auth)/login/actions.ts (1)

7-14: Simplify the database query by removing unnecessary select clause.

Since the email is already known from the input parameter, selecting it again from the database is redundant.

  const user = await prisma.user.findUnique({
    where: {
      email,
    },
-    select: {
-      email: true,
-    },
  });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc85b0b and 11a361f.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (8)
  • apps/web/src/app/[locale]/(auth)/login/actions.ts (1 hunks)
  • apps/web/src/auth.ts (0 hunks)
  • apps/web/src/auth/providers/registration-token.ts (1 hunks)
  • apps/web/src/middleware.ts (2 hunks)
  • apps/web/src/next-auth.config.ts (1 hunks)
  • apps/web/src/next-auth.ts (1 hunks)
  • apps/web/src/trpc/routers/auth.ts (1 hunks)
  • package.json (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/src/auth.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/web/src/trpc/routers/auth.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/auth/providers/registration-token.ts
  • apps/web/src/next-auth.ts
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Linting
  • GitHub Check: Integration tests
  • GitHub Check: Type check
🔇 Additional comments (13)
apps/web/src/middleware.ts (6)

4-9: LGTM! But fix the typo in the import path.

The initialization follows the next-auth v5 pattern correctly.

Apply this diff to correct the import statement:

- import { nextAuthConfig } from "@/next-auth.confg";
+ import { nextAuthConfig } from "@/next-auth.config";

25-28: LGTM! Correctly updated to next-auth v5 middleware pattern.

The middleware function signature has been properly updated to use the new next-auth v5 pattern.


29-35: LGTM! Correctly updated session access pattern.

The session access has been properly updated to use req.auth?.user?.email instead of the deprecated req.nextauth.token?.email.


37-47: Update redirection parameter to redirectTo.

According to the PR objectives, redirection parameters are being renamed from callbackUrl to redirectTo in sign-in/sign-out flows.

Apply this diff to update the parameter:

- newUrl.searchParams.set("callbackUrl", newUrl.pathname);
+ newUrl.searchParams.set("redirectTo", newUrl.pathname);

49-58: LGTM! Correctly updated locale access pattern.

The locale access has been properly updated to use req.auth?.user?.locale instead of the deprecated req.nextauth.token?.locale.


63-65: LGTM! Correctly updated user ID access pattern for PostHog.

The user ID access has been properly updated to use req.auth?.user?.id for PostHog analytics integration.

apps/web/src/app/[locale]/(auth)/login/actions.ts (1)

16-24: LGTM! Secure cookie configuration.

The cookie configuration is secure with:

  • httpOnly to prevent XSS
  • secure in production
  • sameSite: "lax" to prevent CSRF
  • 15-minute expiration for verification window
package.json (1)

61-62: Verify the empty dependencies object.

Since this PR upgrades to next-auth v5, consider whether the dependencies should be defined here or if they are already defined in workspace-specific package.json files.

Let's check the workspace-specific package.json files for the next-auth dependency:

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Description: Check for next-auth dependency in workspace package.json files

# Search for next-auth in package.json files
fd 'package.json' apps packages -x grep -l 'next-auth'

# For each found file, show the next-auth version
fd 'package.json' apps packages -x jq -r '.dependencies["next-auth"] // .devDependencies["next-auth"]'

Length of output: 257


Workspace packages provide the next-auth dependency.

The shell script output shows that in at least one workspace (e.g., apps/web/package.json), the next-auth dependency is defined with version ^5.0.0-beta.25. This indicates that the empty "dependencies": {} entry in the root package.json is intentional and correct for managing dependencies in a monorepo setup.

apps/web/src/next-auth.config.ts (5)

1-3: LGTM! Proper type imports and environment configuration.

The imports are well-structured, ensuring type safety with NextAuthConfig and proper environment variable handling.


9-9: Verify SECRET_PASSWORD environment variable.

Ensure that SECRET_PASSWORD is properly configured in your environment variables and has sufficient entropy for production use.

Let me help you verify the environment variable configuration:

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Check for environment variable validation
rg "SECRET_PASSWORD" --type ts

Length of output: 461


SECRET_PASSWORD environment variable configuration is verified.

  • The schema in apps/web/src/env.ts enforces a minimum length of 32 characters using z.string().min(32), ensuring adequate entropy.
  • The variable is consistently referenced across the project (e.g., next-auth.config.ts and session configuration).

5-11: Verify the empty providers array implementation.

The providers array is currently empty. According to the PR summary, various providers (email, Google, OIDC, Microsoft) should be configured.

Let me help you verify if the providers are defined elsewhere:

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Search for auth provider configurations
rg -l "(?i)(email|google|oidc|microsoft)provider" --type ts

Length of output: 424


Providers Configuration Verification

The search results confirm that provider configurations (Email, Google, OIDC, Microsoft) are defined separately in files under apps/web/src/auth/providers/ and managed via the get-optional-providers.ts module. The empty providers array in next-auth.config.ts appears intentional—likely to delegate provider loading dynamically rather than hardcoding them in the configuration object.

  • Providers are defined in separate files (providers/email.ts, providers/google.ts, providers/oidc.ts, providers/microsoft.ts).
  • The presence of apps/web/src/auth/get-optional-providers.ts suggests that providers are incorporated at runtime.
  • This design aligns with a modular and conditional configuration approach.

6-8: Verify NextAuth v5 session configuration.

Let's confirm that the JWT strategy configuration is correct for NextAuth v5.

✅ Verification successful

🌐 Web query:

What are the session strategy options in NextAuth v5? Is JWT the default strategy?

💡 Result:

NextAuth.js v5 offers two session strategies: **JSON Web Token (JWT)** and **database sessions**. The default strategy depends on whether you've configured a database adapter:

1. **JWT (default without an adapter)**  
   - Stores session data in an encrypted JWT within a secure `HttpOnly` cookie[1][3][7].  
   - Automatically selected if no database adapter is configured[1][3][7].  
   - Supports serverless/edge environments without direct database access[3][7].

2. **Database sessions (default with an adapter)**  
   - Stores session data in your database and uses a session ID cookie[3][7].  
   - Requires a configured database adapter (e.g., Prisma, TypeORM)[3][7].  
   - Automatically enabled when using any database adapter[1][3][7].

### Key Differences
| Feature              | JWT Strategy                          | Database Strategy                    |
|----------------------|---------------------------------------|---------------------------------------|
| Session Storage      | Encrypted token in cookie             | Database record + session ID cookie  |
| Server Requirements  | Stateless (no DB queries)             | Requires database connection         |
| Session Updates      | Requires token regeneration           | Direct DB updates                    |
| Default Trigger      | No adapter configured                 | Adapter configured                   |

To explicitly set your strategy regardless of adapter configuration:
```javascript
// auth.ts
export const { auth } = NextAuth({
  session: { strategy: "jwt" }, // Force JWT
  // OR
  session: { strategy: "database" }, // Force DB
  // ...other config
})
```

The encrypted JWT approach provides better performance for serverless architectures[3][7], while database sessions offer more control over session management[3][7].

Citations:

- 1: https://next-auth.js.org/configuration/options
- 2: https://github.com/nextauthjs/next-auth/issues/9122
- 3: https://authjs.dev/concepts/session-strategies
- 4: https://github.com/nextauthjs/next-auth/discussions/8487
- 5: https://next-auth.js.org/deployment
- 6: https://next-auth.js.org/configuration/nextjs
- 7: https://authjs.dev/getting-started/migrating-to-v5
- 8: https://javascript.plainenglish.io/complete-authentication-guide-using-next-auth-v5-in-next-js-14-70e7630ab1c2?gi=f11fac1c6ffd
- 9: https://www.youtube.com/watch?v=1MTyCvS05V4
- 10: https://github.com/joe-jngigi/next_auth_V5

JWT session strategy configuration for NextAuth v5 verified.

  • NextAuth v5 supports both JWT and database session strategies.
  • When no database adapter is configured, JWT is the default.
  • Explicitly setting session: { strategy: "jwt" } ensures the JWT strategy is used.

5-11: Consider additional NextAuth v5 configuration options.

The current configuration might be missing some important NextAuth v5 options. Let's verify the required configuration.

@vercel vercel bot temporarily deployed to Preview – landing February 6, 2025 09:14 Inactive
@vercel vercel bot temporarily deployed to Preview – landing February 6, 2025 09:16 Inactive
@lukevella
Copy link
Owner Author

@coderabbitai review

Copy link
Contributor

coderabbitai bot commented Feb 6, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7b0acd9 and 80209d7.

📒 Files selected for processing (3)
  • apps/web/src/components/poll/language-selector.tsx (1 hunks)
  • apps/web/src/next-auth.config.ts (1 hunks)
  • apps/web/src/next-auth.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/src/next-auth.ts
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Unit tests
  • GitHub Check: Integration tests
  • GitHub Check: Linting
  • GitHub Check: Type check
🔇 Additional comments (5)
apps/web/src/components/poll/language-selector.tsx (1)

21-21: Verify the button styling change.

The removal of variant="ghost" will change the button's appearance to use the default variant. Please ensure this aligns with the intended UI design.

Let me help you verify if this change is consistent with other similar components:

apps/web/src/next-auth.config.ts (4)

7-9: LGTM! JWT strategy is appropriate.

Using JWT as the session strategy is a good choice for Next.js applications, especially when dealing with serverless functions.


6-12: Verify provider configuration location.

The providers array is empty. This is likely intentional if providers are configured elsewhere, but we should verify this to ensure authentication will work correctly.

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Search for auth provider configurations
fd -t f "provider" apps/web/src/auth

Length of output: 119


🏁 Script executed:

#!/bin/bash
# Display the content of the get-optional-providers file to inspect how providers are configured.
cat apps/web/src/auth/get-optional-providers.ts

Length of output: 419


Provider configuration verified.

The empty providers array in apps/web/src/next-auth.config.ts is intentional. The authentication providers are defined in apps/web/src/auth/get-optional-providers.ts, which aggregates OIDC, Google, and Microsoft providers. This confirms that the NextAuth configuration is correctly delegating provider setup elsewhere.


1-4: Verify next-auth package version and environment configuration.

Let's ensure we're using the correct next-auth v5 package and that the environment variables are properly configured.

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Check package.json for next-auth version
jq '.dependencies["next-auth"]' package.json

# Check environment variable configuration
cat apps/web/src/env.ts | grep -A 5 "SECRET_PASSWORD"

Length of output: 601


🏁 Script executed:

#!/bin/bash
# Check apps/web/package.json for next-auth dependency/version in both dependencies and devDependencies.
jq '.dependencies["next-auth"] // .devDependencies["next-auth"]' apps/web/package.json

Length of output: 105


NextAuth v5 Dependency and Environment Configuration Verified

  • The next-auth dependency in apps/web/package.json is correctly set to "^5.0.0-beta.25", confirming it's using NextAuth v5.
  • The SECRET_PASSWORD environment variable is properly defined and type-checked, ensuring it meets the minimum string length requirement.

1-23: Verify NextAuth v5 migration requirements.

Let's ensure all required changes for the v5 upgrade are implemented correctly.

apps/web/src/next-auth.config.ts Outdated Show resolved Hide resolved
@vercel vercel bot temporarily deployed to Preview – landing February 7, 2025 02:54 Inactive
@vercel vercel bot temporarily deployed to Preview – landing February 7, 2025 05:10 Inactive
Copy link
Contributor

@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

♻️ Duplicate comments (1)
apps/web/src/next-auth.config.ts (1)

30-38: ⚠️ Potential issue

Add type safety and validation to session callback.

The current implementation uses unsafe type assertions without validation.

 async session({ session, token }) {
-      session.user.id = token.sub as string;
-      session.user.email = token.email as string;
-      session.user.locale = token.locale;
-      session.user.timeFormat = token.timeFormat;
-      session.user.timeZone = token.timeZone;
-      session.user.weekStart = token.weekStart;
+      if (!token.sub) {
+        throw new Error("Missing required token.sub");
+      }
+      session.user = {
+        ...session.user,
+        id: token.sub,
+        email: token.email ?? null,
+        locale: typeof token.locale === "string" ? token.locale : "en",
+        timeFormat: isTimeFormat(token.timeFormat) ? token.timeFormat : "12h",
+        timeZone: typeof token.timeZone === "string" ? token.timeZone : "UTC",
+        weekStart: typeof token.weekStart === "number" ? token.weekStart : 0,
+      };
       return session;
     },

Add this helper function at the top of the file:

function isTimeFormat(value: unknown): value is TimeFormat {
  return value === "12h" || value === "24h";
}
🧹 Nitpick comments (2)
apps/web/src/next-auth.config.ts (2)

7-17: Add type safety to public routes array.

Consider adding a type definition for the routes array to ensure type safety and maintainability.

+type PublicRoute = '/login' | '/register' | '/invite/' | '/poll/' | '/auth/login' | '/quick-create' | '/new';
-const publicRoutes = [
+const publicRoutes: PublicRoute[] = [
   "/login",
   "/register",
   "/invite/",
   "/poll/",
   "/auth/login",
];

39-54: Simplify redirect logic in authorized callback.

The redirect URL construction could be simplified and made more maintainable.

 async authorized({ request, auth }) {
   const { nextUrl } = request;
   const isLoggedIn = !!auth?.user?.email;
   const isPublicRoute = publicRoutes.some((route) =>
     nextUrl.pathname.startsWith(route),
   );
   if (isLoggedIn || isPublicRoute) {
     return true;
   }
-  const redirectUrl = new URL("/login", request.url);
-  if (nextUrl.pathname !== "/") {
-    const redirectPath = nextUrl.pathname + nextUrl.search;
-    redirectUrl.searchParams.set("redirectTo", redirectPath);
-  }
+  const redirectUrl = new URL("/login", request.url);
+  const redirectPath = nextUrl.pathname === "/" ? "" : nextUrl.pathname + nextUrl.search;
+  if (redirectPath) {
+    redirectUrl.searchParams.set("redirectTo", redirectPath);
+  }
   return NextResponse.redirect(redirectUrl);
 },
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0375ec1 and 40e71cb.

📒 Files selected for processing (3)
  • apps/web/.env.test (1 hunks)
  • apps/web/declarations/next-auth.d.ts (1 hunks)
  • apps/web/src/next-auth.config.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/declarations/next-auth.d.ts
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Unit tests
  • GitHub Check: Linting
  • GitHub Check: Type check
  • GitHub Check: Integration tests
🔇 Additional comments (3)
apps/web/.env.test (1)

7-7: Update SMTP_HOST for Broader Interface Binding
The change from "localhost" to "0.0.0.0" allows the SMTP service in the test environment to accept connections from any network interface. This is appropriate for testing scenarios where services may run in containerized or multi-host setups. However, please ensure that this setting remains restricted to test environments and is not inadvertently used in production.

apps/web/src/next-auth.config.ts (2)

1-6: LGTM!

The imports are appropriate and well-organized for the NextAuth v5 configuration.


28-28: Verify authentication providers configuration.

The providers array is empty. Ensure this is intentional and that providers are configured elsewhere.

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Search for NextAuth providers configuration
rg -l "(?i)auth.*provider" --type ts

Length of output: 550


Authentication Providers Configuration Confirmed

The empty providers array in apps/web/src/next-auth.config.ts is intentional. A search of the codebase shows that several NextAuth providers (Google, Microsoft, email, guest, OIDC, etc.) are defined separately under apps/web/src/auth/providers. These modules are likely imported and composed dynamically in the authentication flow (for example via apps/web/src/auth/get-optional-providers.ts or similar mechanisms), so maintaining an empty providers array in the NextAuth configuration is by design.

@vercel vercel bot temporarily deployed to Preview – landing February 8, 2025 02:24 Inactive
Copy link
Contributor

@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 (1)
apps/web/src/app/[locale]/(auth)/auth/login/components/login-page.tsx (1)

29-47: Consider providing more specific error messages.

While the error handling is good, consider differentiating between invalid and expired links to help users better understand the issue.

-        setError(
-          t("loginMagicLinkError", {
-            defaultValue:
-              "This link is invalid or expired. Please request a new link.",
-          }),
-        );
+        const errorType = data.url.includes("expired") ? "expired" : "invalid";
+        setError(
+          t(`loginMagicLink${errorType}Error`, {
+            defaultValue:
+              errorType === "expired"
+                ? "This link has expired. Please request a new link."
+                : "This link is invalid. Please request a new link.",
+          }),
+        );
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5fb2085 and 7876b9c.

📒 Files selected for processing (3)
  • apps/web/i18next-scanner.config.js (1 hunks)
  • apps/web/public/locales/en/app.json (1 hunks)
  • apps/web/src/app/[locale]/(auth)/auth/login/components/login-page.tsx (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Unit tests
  • GitHub Check: Integration tests
  • GitHub Check: Linting
  • GitHub Check: Type check
🔇 Additional comments (4)
apps/web/i18next-scanner.config.js (1)

4-4: LGTM! Verify the scope of excluded files.

The updated exclusion pattern aligns with the next-auth v5 upgrade. However, let's verify that the wildcard pattern !src/next-auth*.ts doesn't accidentally exclude files that should be included in translation.

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Description: List all files that match the next-auth*.ts pattern to ensure we're not excluding files that need translation

echo "Files that will be excluded from translation scanning:"
fd -t f "next-auth.*\.ts$" src/

echo -e "\nAll TypeScript files in src/ for comparison:"
fd -t f ".*\.ts$" src/

Length of output: 466


I'll re-run the verification shell script using the correct relative path (apps/web/src) to accurately gather the necessary file information. This will help confirm that the wildcard exclusion ("!src/next-auth*.ts") is correctly scoped.


🏁 Script executed:

#!/bin/bash
echo "Searching for files matching 'next-auth*.ts' pattern in apps/web/src:"
fd -t f "next-auth.*\.ts$" apps/web/src

echo -e "\nListing all TypeScript files in apps/web/src for comparison:"
fd -t f ".*\.ts$" apps/web/src

Length of output: 4298


LGTM! Wildcard exclusion correctly targets next-auth files.

The updated exclusion pattern excludes only the two next-auth files (apps/web/src/next-auth.config.ts and apps/web/src/next-auth.ts) as expected, ensuring that no additional files are inadvertently omitted from translation scanning.

apps/web/src/app/[locale]/(auth)/auth/login/components/login-page.tsx (2)

7-7: LGTM! Good error handling setup.

The addition of error state management and i18n support enhances the user experience by providing localized error messages.

Also applies to: 12-12, 20-21


86-86: LGTM! Good error message styling.

The error message follows the design system's conventions using the text-destructive class.

apps/web/public/locales/en/app.json (1)

304-305: LGTM! Good localization support.

The added keys support the enhanced error handling in the login page and maintain consistency in the localization system.

const magicLinkFetch = useMutation({
mutationFn: async () => {
const res = await fetch(magicLink);
const res = await fetch(magicLink + "test");
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove debugging code.

The "test" suffix appears to be debugging code that shouldn't be in production.

-      const res = await fetch(magicLink + "test");
+      const res = await fetch(magicLink);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const res = await fetch(magicLink + "test");
const res = await fetch(magicLink);

Copy link
Contributor

@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

🧹 Nitpick comments (2)
apps/web/src/app/[locale]/(auth)/auth/login/components/login-page.tsx (2)

28-47: Consider handling navigation and errors sequentially.

The current implementation might lead to a race condition where the error state is set but not displayed due to immediate navigation. Consider restructuring the flow:

    onSuccess: async (data) => {
-      if (!data.url.includes("auth/error")) {
+      if (data.url.includes("auth/error")) {
+        setError(
+          t("loginMagicLinkError", {
+            defaultValue:
+              "This link is invalid or expired. Please request a new link.",
+          }),
+        );
+        return;
+      }
+
        // if login was successful, update the session
        const updatedSession = await session.update();
        if (updatedSession?.user) {
          // identify the user in posthog
          posthog?.identify(updatedSession.user.id, {
            email: updatedSession.user.email,
            name: updatedSession.user.name,
          });
        }
        router.push(data.url);
-      } else {
-        setError(
-          t("loginMagicLinkError", {
-            defaultValue:
-              "This link is invalid or expired. Please request a new link.",
-          }),
-        );
-      }
    },

86-86: Enhance error message accessibility.

Consider adding proper ARIA attributes to improve screen reader support for the error message.

-        {error && <p className="text-destructive text-sm">{error}</p>}
+        {error && (
+          <p 
+            className="text-destructive text-sm" 
+            role="alert" 
+            aria-live="polite"
+          >
+            {error}
+          </p>
+        )}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7876b9c and 7d57138.

📒 Files selected for processing (1)
  • apps/web/src/app/[locale]/(auth)/auth/login/components/login-page.tsx (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Unit tests
  • GitHub Check: Type check
  • GitHub Check: Integration tests
  • GitHub Check: Linting
🔇 Additional comments (2)
apps/web/src/app/[locale]/(auth)/auth/login/components/login-page.tsx (2)

7-7: LGTM! Well-structured initialization of error handling.

The addition of error state management and internationalization support is well implemented.

Also applies to: 12-12, 20-21


25-26: Verify URL redirection security.

Ensure that the magic link URL and subsequent redirections are properly validated to prevent open redirect vulnerabilities.

✅ Verification successful

🏁 Script executed:

#!/bin/bash
# Search for URL validation in auth-related files
rg -A 5 "magicLink|redirectTo|callbackUrl" --type ts

Length of output: 15855


Security Verification: Magic Link URL Handling

After reviewing the code snippets along with the search results, here are our findings:

• The magic link is required to pass through a zod validation—ensuring it is a valid URL. In addition, upstream components (e.g. in apps/web/src/app/[locale]/(auth)/auth/login/page.tsx) parse and validate the magic link parameters before passing the URL into the LoginPage component.

• The LoginPage component itself merely uses the already‑validated magic link by fetching it and then checking backend response details (e.g. verifying the absence of “auth/error” in data.url). Any redirection behavior appears to be handled by upstream flows using safe construction (for example, with encodeURIComponent for any “redirectTo” parameters).

Based on these observations, the current implementation appears to validate and restrict the magic link URL sufficiently against open redirect vulnerabilities.

@lukevella lukevella merged commit a9c29a1 into main Feb 8, 2025
10 checks passed
@lukevella lukevella deleted the authjs branch February 8, 2025 02:41
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.

1 participant