Skip to content

Conversation

@ericallam
Copy link
Member

@ericallam ericallam commented Dec 4, 2025

CleanShot 2025-12-05 at 14 27 16

Note

Adds Google OAuth login and a cookie-based “last used” indicator on the login page, with supporting backend, routes, and schema updates.

  • Auth/Backend:
    • Google OAuth: Integrates remix-auth-google via new addGoogleStrategy and enables when AUTH_GOOGLE_CLIENT_ID/SECRET are set (services/googleAuth.server.ts, services/auth.server.ts).
    • User handling: Implements findOrCreateGoogleUser with linking/upsert logic and conflict logging (models/user.server.ts).
    • MFA + session: Google/GitHub/Magic callbacks now set session, handle MFA, and set a "last-auth-method" cookie (routes/auth.google*.tsx, routes/auth.github.callback.tsx, routes/magic.tsx, services/lastAuthMethod.server.ts).
    • GitHub strategy: Safer email check (services/gitHubAuth.server.ts).
  • Routes/UI:
    • Login page: Adds "Continue with Google" button and animated "Last used" badge based on cookie; keeps GitHub/Email options (routes/login._index/route.tsx).
    • Redirect safety: Sanitize redirect paths and persist redirect via cookies in auth actions (routes/auth.github.ts, routes/auth.google.ts).
    • Assets: Adds GoogleLogo SVG.
    • Avatar: Set referrerPolicy="no-referrer" on profile image.
  • Config/Schema:
    • Env: Adds AUTH_GOOGLE_CLIENT_ID/AUTH_GOOGLE_CLIENT_SECRET (env.server.ts).
    • DB: Extends AuthenticationMethod enum with GOOGLE (Prisma schema + migration).
  • Dependencies:
    • Adds remix-auth-google in package.json.

Written by Cursor Bugbot for commit 9f84f97. This will update automatically on new commits. Configure here.

@changeset-bot
Copy link

changeset-bot bot commented Dec 4, 2025

⚠️ No Changeset found

Latest commit: 9f84f97

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 4, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds Google OAuth support across the webapp: new optional env vars for Google client ID/secret; a Google strategy registration helper and integration into the authenticator; new routes to initiate and handle Google OAuth (with a redirect cookie and MFA branching); model changes to find/create/link Google-authenticated users and logging of auth conflicts; Prisma enum and migration adding AuthenticationMethod.GOOGLE; UI and route updates to surface Google login and persist last-used auth method via a new last-auth-method cookie service; replaces several redirect header objects with Headers to append multiple Set-Cookie values; minor avatar img change adding referrerPolicy="no-referrer"; and adds the remix-auth-google dependency.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas requiring extra attention:

  • apps/webapp/app/models/user.server.ts — findOrCreateGoogleUser: linking/upsert logic, email selection, authIdentifier format, and conflict-resolution logging.
  • internal-packages/database/prisma/migrations/* and internal-packages/database/prisma/schema.prisma — ALTER TYPE migration correctness and deployment ordering.
  • apps/webapp/app/services/googleAuth.server.ts — strategy callback flow, error logging, and interaction with postAuthentication.
  • apps/webapp/app/services/auth.server.ts — conditional Google strategy initialization and the exported isGoogleAuthSupported flag.
  • apps/webapp/app/routes/auth.google.ts and apps/webapp/app/routes/auth.google.callback.tsx — redirectCookie behavior, sanitizeRedirectPath usage, session commits, MFA branching, and composing multiple Set-Cookie headers.
  • apps/webapp/app/routes/auth.github.callback.tsx and apps/webapp/app/routes/magic.tsx — changed Set-Cookie handling to Headers with multiple cookies; verify cookie serialization and ordering.
  • apps/webapp/app/services/lastAuthMethod.server.ts and its consumers — cookie serialization/validation and correct use of setLastAuthMethodHeader.
  • apps/webapp/package.json — new dependency (remix-auth-google) and version compatibility.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description includes a comprehensive note with technical details about the changes, but is missing required template sections: issue closure, testing steps, changelog, and checklist completion. Add the missing required sections: issue closure (Closes #), testing steps, changelog summary, and mark the contribution checklist items as completed or incomplete.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately describes the main changes: adding Google OAuth login and a 'last used' authentication method indicator on the login page, which align with the primary objectives.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ea-branch-108

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6944207 and 9f84f97.

📒 Files selected for processing (3)
  • apps/webapp/app/models/user.server.ts (5 hunks)
  • apps/webapp/app/services/gitHubAuth.server.ts (1 hunks)
  • apps/webapp/app/services/googleAuth.server.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/webapp/app/services/googleAuth.server.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • apps/webapp/app/services/gitHubAuth.server.ts
  • apps/webapp/app/models/user.server.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/services/gitHubAuth.server.ts
  • apps/webapp/app/models/user.server.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • apps/webapp/app/services/gitHubAuth.server.ts
  • apps/webapp/app/models/user.server.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/services/gitHubAuth.server.ts
  • apps/webapp/app/models/user.server.ts
apps/webapp/app/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Separate testable services from configuration files; follow the pattern of realtimeClient.server.ts (testable service) and realtimeClientGlobal.server.ts (configuration) in the webapp

Files:

  • apps/webapp/app/services/gitHubAuth.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Files:

  • apps/webapp/app/services/gitHubAuth.server.ts
  • apps/webapp/app/models/user.server.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • apps/webapp/app/services/gitHubAuth.server.ts
  • apps/webapp/app/models/user.server.ts
🧠 Learnings (2)
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • apps/webapp/app/models/user.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Leverage the PostgreSQL database through the `trigger.dev/database` Prisma 6.14.0 client in the webapp for all data access patterns

Applied to files:

  • apps/webapp/app/models/user.server.ts
🧬 Code graph analysis (1)
apps/webapp/app/models/user.server.ts (1)
apps/webapp/app/utils/email.ts (1)
  • assertEmailAllowed (3-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (22)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (12)
apps/webapp/app/services/gitHubAuth.server.ts (1)

21-25: Stronger guard on profile.emails looks good

Tightening the check to if (!emails?.length) both enforces that at least one email is present (which findOrCreateUser relies on) and prevents a possible runtime error when accessing emails[0].value. This is a safe and clearer invariant for the GitHub strategy.

apps/webapp/app/models/user.server.ts (11)

3-3: LGTM: Imports and type definitions

The new imports and type definitions are correct and consistent with the existing GitHub OAuth pattern.

Also applies to: 12-12, 26-31, 33-33


48-50: LGTM: Switch case routing

The GOOGLE case correctly delegates to findOrCreateGoogleUser, consistent with the existing authentication flow pattern.


178-183: LGTM: Function signature and email validation

The function signature is consistent with the GitHub implementation, and assertEmailAllowed properly enforces email whitelisting.


185-196: LGTM: Profile data extraction

The profile extraction logic correctly handles GoogleProfile data and safely converts to Prisma types, consistent with the GitHub implementation.


198-198: LGTM: Auth identifier format

The google: prefix format is consistent with the GitHub implementation's identifier pattern.


200-210: LGTM: User lookup queries

The queries correctly fetch both auth-identifier-based and email-based users to handle account linking and conflict detection.


212-230: LGTM: Account linking preserves authentication method

This correctly links an existing email account to Google authentication while preserving the original authenticationMethod. This implementation properly addresses the past review feedback.


232-250: LGTM: Conflict detection and logging

The conflict detection properly handles the edge case where a Google account and email belong to different users. The detailed error logging enables monitoring of this scenario. Based on past review discussions, returning the existing Google user (rather than throwing an error) was an intentional design choice.


252-270: LGTM: Same-user profile updates

When the email and Google ID belong to the same user, all profile fields are correctly updated, including the email. This properly handles the scenario where a user changes their Google email and addresses past review feedback.


273-298: LGTM: Upsert with complete field updates

The upsert's update path now correctly includes authenticationProfile and authenticationExtraParams (lines 285-286), which properly addresses the past review feedback. The helpful comment explains the email update scenario, and the logic correctly handles all cases.


300-303: LGTM: Return value

The return value correctly indicates whether the user is new based on the existence of a user with the Google auth identifier.


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
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: 3

🧹 Nitpick comments (1)
apps/webapp/app/routes/login._index/route.tsx (1)

20-41: Consider extracting GoogleIcon to a shared component.

The inline GoogleIcon component works correctly. However, since @trigger.dev/companyicons is already used for GitHubLightIcon, consider adding the Google icon to that package for consistency and reusability across the codebase.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b01b874 and c95b0f5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • apps/webapp/app/components/UserProfilePhoto.tsx (1 hunks)
  • apps/webapp/app/env.server.ts (1 hunks)
  • apps/webapp/app/models/user.server.ts (4 hunks)
  • apps/webapp/app/routes/auth.github.callback.tsx (2 hunks)
  • apps/webapp/app/routes/auth.google.callback.tsx (1 hunks)
  • apps/webapp/app/routes/auth.google.ts (1 hunks)
  • apps/webapp/app/routes/login._index/route.tsx (6 hunks)
  • apps/webapp/app/routes/magic.tsx (2 hunks)
  • apps/webapp/app/services/auth.server.ts (2 hunks)
  • apps/webapp/app/services/googleAuth.server.ts (1 hunks)
  • apps/webapp/app/services/lastAuthMethod.server.ts (1 hunks)
  • apps/webapp/package.json (1 hunks)
  • internal-packages/database/prisma/migrations/20251204143136_add_google_auth_method/migration.sql (1 hunks)
  • internal-packages/database/prisma/schema.prisma (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • apps/webapp/app/services/googleAuth.server.ts
  • apps/webapp/app/services/auth.server.ts
  • apps/webapp/app/routes/auth.google.callback.tsx
  • apps/webapp/app/models/user.server.ts
  • apps/webapp/app/routes/auth.github.callback.tsx
  • apps/webapp/app/services/lastAuthMethod.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/routes/magic.tsx
  • apps/webapp/app/components/UserProfilePhoto.tsx
  • apps/webapp/app/routes/auth.google.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/services/googleAuth.server.ts
  • apps/webapp/app/services/auth.server.ts
  • apps/webapp/app/routes/auth.google.callback.tsx
  • apps/webapp/app/models/user.server.ts
  • apps/webapp/app/routes/auth.github.callback.tsx
  • apps/webapp/app/services/lastAuthMethod.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/routes/magic.tsx
  • apps/webapp/app/components/UserProfilePhoto.tsx
  • apps/webapp/app/routes/auth.google.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • apps/webapp/app/services/googleAuth.server.ts
  • apps/webapp/app/services/auth.server.ts
  • apps/webapp/app/routes/auth.google.callback.tsx
  • apps/webapp/app/models/user.server.ts
  • apps/webapp/app/routes/auth.github.callback.tsx
  • apps/webapp/app/services/lastAuthMethod.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/routes/magic.tsx
  • apps/webapp/app/components/UserProfilePhoto.tsx
  • apps/webapp/app/routes/auth.google.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/services/googleAuth.server.ts
  • apps/webapp/app/services/auth.server.ts
  • apps/webapp/app/routes/auth.google.callback.tsx
  • apps/webapp/app/models/user.server.ts
  • apps/webapp/app/routes/auth.github.callback.tsx
  • apps/webapp/app/services/lastAuthMethod.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/routes/magic.tsx
  • apps/webapp/app/components/UserProfilePhoto.tsx
  • apps/webapp/app/routes/auth.google.ts
apps/webapp/app/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Separate testable services from configuration files; follow the pattern of realtimeClient.server.ts (testable service) and realtimeClientGlobal.server.ts (configuration) in the webapp

Files:

  • apps/webapp/app/services/googleAuth.server.ts
  • apps/webapp/app/services/auth.server.ts
  • apps/webapp/app/services/lastAuthMethod.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Files:

  • apps/webapp/app/services/googleAuth.server.ts
  • apps/webapp/app/services/auth.server.ts
  • apps/webapp/app/routes/auth.google.callback.tsx
  • apps/webapp/app/models/user.server.ts
  • apps/webapp/app/routes/auth.github.callback.tsx
  • apps/webapp/app/services/lastAuthMethod.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/routes/magic.tsx
  • apps/webapp/app/components/UserProfilePhoto.tsx
  • apps/webapp/app/routes/auth.google.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • apps/webapp/app/services/googleAuth.server.ts
  • apps/webapp/app/services/auth.server.ts
  • apps/webapp/package.json
  • apps/webapp/app/routes/auth.google.callback.tsx
  • apps/webapp/app/models/user.server.ts
  • apps/webapp/app/routes/auth.github.callback.tsx
  • apps/webapp/app/services/lastAuthMethod.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/routes/magic.tsx
  • apps/webapp/app/components/UserProfilePhoto.tsx
  • apps/webapp/app/routes/auth.google.ts
🧠 Learnings (8)
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/services/**/*.server.{ts,tsx} : Separate testable services from configuration files; follow the pattern of `realtimeClient.server.ts` (testable service) and `realtimeClientGlobal.server.ts` (configuration) in the webapp

Applied to files:

  • apps/webapp/app/services/auth.server.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: The webapp at apps/webapp is a Remix 2.1 application using Node.js v20

Applied to files:

  • apps/webapp/package.json
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Applied to files:

  • apps/webapp/package.json
  • apps/webapp/app/routes/auth.google.callback.tsx
  • apps/webapp/app/routes/auth.google.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • apps/webapp/app/models/user.server.ts
  • internal-packages/database/prisma/migrations/20251204143136_add_google_auth_method/migration.sql
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Leverage the PostgreSQL database through the `trigger.dev/database` Prisma 6.14.0 client in the webapp for all data access patterns

Applied to files:

  • apps/webapp/app/models/user.server.ts
📚 Learning: 2025-09-02T11:27:36.336Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2463
File: apps/webapp/app/routes/_app.github.callback/route.tsx:33-44
Timestamp: 2025-09-02T11:27:36.336Z
Learning: In the GitHub App installation callback flow in apps/webapp/app/routes/_app.github.callback/route.tsx, the install session cookie is not cleared after use due to interface limitations with redirectWithSuccessMessage/redirectWithErrorMessage not supporting custom headers. The maintainer accepts this design as the 1-hour cookie expiration provides sufficient protection against replay attacks.

Applied to files:

  • apps/webapp/app/routes/auth.github.callback.tsx
  • apps/webapp/app/services/lastAuthMethod.server.ts
  • apps/webapp/app/routes/magic.tsx
📚 Learning: 2025-09-02T11:18:06.602Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2463
File: apps/webapp/app/services/gitHubSession.server.ts:31-36
Timestamp: 2025-09-02T11:18:06.602Z
Learning: In the GitHub App installation flow in apps/webapp/app/services/gitHubSession.server.ts, the redirectTo parameter stored in httpOnly session cookies is considered acceptable without additional validation by the maintainer, as the httpOnly cookie provides sufficient security for this use case.

Applied to files:

  • apps/webapp/app/routes/auth.github.callback.tsx
  • apps/webapp/app/routes/magic.tsx
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp

Applied to files:

  • apps/webapp/app/env.server.ts
🧬 Code graph analysis (8)
apps/webapp/app/services/googleAuth.server.ts (3)
apps/webapp/app/services/auth.server.ts (1)
  • authenticator (31-31)
apps/webapp/app/env.server.ts (1)
  • env (1261-1261)
apps/webapp/app/models/user.server.ts (1)
  • findOrCreateUser (38-50)
apps/webapp/app/services/auth.server.ts (4)
apps/webapp/app/env.server.ts (1)
  • env (1261-1261)
apps/webapp/app/services/gitHubAuth.server.ts (1)
  • addGitHubStrategy (9-54)
apps/webapp/app/services/googleAuth.server.ts (1)
  • addGoogleStrategy (9-54)
apps/webapp/app/services/emailAuth.server.tsx (1)
  • addEmailLinkStrategy (48-50)
apps/webapp/app/routes/auth.google.callback.tsx (8)
apps/webapp/app/routes/auth.github.callback.tsx (1)
  • loader (11-60)
apps/webapp/app/routes/auth.google.ts (2)
  • loader (4-4)
  • redirectCookie (29-32)
apps/webapp/app/routes/login._index/route.tsx (1)
  • loader (74-120)
apps/webapp/app/routes/magic.tsx (1)
  • loader (10-57)
apps/webapp/app/utils.ts (1)
  • sanitizeRedirectPath (13-42)
apps/webapp/app/services/auth.server.ts (1)
  • authenticator (31-31)
apps/webapp/app/models/message.server.ts (1)
  • redirectWithErrorMessage (201-218)
apps/webapp/app/services/lastAuthMethod.server.ts (1)
  • setLastAuthMethodHeader (22-24)
apps/webapp/app/models/user.server.ts (1)
apps/webapp/app/utils/email.ts (1)
  • assertEmailAllowed (3-13)
apps/webapp/app/routes/auth.github.callback.tsx (1)
apps/webapp/app/services/lastAuthMethod.server.ts (1)
  • setLastAuthMethodHeader (22-24)
apps/webapp/app/routes/login._index/route.tsx (2)
apps/webapp/app/services/lastAuthMethod.server.ts (1)
  • getLastAuthMethod (13-20)
apps/webapp/app/services/auth.server.ts (1)
  • isGoogleAuthSupported (31-31)
apps/webapp/app/routes/magic.tsx (1)
apps/webapp/app/services/lastAuthMethod.server.ts (1)
  • setLastAuthMethodHeader (22-24)
apps/webapp/app/routes/auth.google.ts (2)
apps/webapp/app/routes/auth.google.callback.tsx (1)
  • loader (11-60)
apps/webapp/app/routes/login._index/route.tsx (1)
  • loader (74-120)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (17)
apps/webapp/app/components/UserProfilePhoto.tsx (1)

25-25: LGTM! Good privacy practice.

Adding referrerPolicy="no-referrer" prevents the Referer header from being sent when fetching avatar images. This is particularly important for OAuth providers like Google, as it prevents leaking the user's current page URL to external servers when loading avatars.

apps/webapp/app/env.server.ts (1)

97-98: LGTM! Consistent with existing OAuth pattern.

The Google OAuth environment variables follow the same optional pattern as the GitHub credentials, allowing the feature to be conditionally enabled based on configuration.

internal-packages/database/prisma/migrations/20251204143136_add_google_auth_method/migration.sql (1)

1-2: LGTM! Correct enum extension.

The migration correctly adds the GOOGLE value to the AuthenticationMethod enum. Note that PostgreSQL's ALTER TYPE ... ADD VALUE cannot run inside a transaction, but since this is the only statement in the migration, it should execute safely.

apps/webapp/app/routes/magic.tsx (1)

42-46: LGTM! Consistent header management pattern.

The implementation correctly uses the Headers API to append multiple Set-Cookie headers (session and last-auth-method). This pattern is consistently applied in both the MFA redirect path and the final redirect path.

internal-packages/database/prisma/schema.prisma (1)

94-94: LGTM! Enum updated consistently.

The GOOGLE authentication method is correctly added to the AuthenticationMethod enum, aligning with the database migration.

apps/webapp/app/services/auth.server.ts (1)

5-5: LGTM! Consistent with existing OAuth pattern.

The Google authentication integration follows the same pattern as the existing GitHub authentication:

  • Runtime check for credential availability
  • Conditional strategy registration
  • Exported support flag for UI conditional rendering

This maintains consistency across OAuth providers.

Also applies to: 17-19, 25-27, 31-31

apps/webapp/app/services/googleAuth.server.ts (1)

9-54: LGTM! Consistent OAuth strategy implementation.

The Google authentication strategy follows the established pattern from the GitHub strategy:

  • Email validation with clear error messages
  • Proper user creation/lookup flow
  • Post-authentication processing
  • Error logging before re-throwing

The implementation correctly integrates with the existing authentication infrastructure.

apps/webapp/package.json (1)

194-194: No action needed—remix-auth-google v2.0.0 is the latest stable version with no known security vulnerabilities.

Version 2.0.0 is the latest available release on npm, and no CVEs are reported for this package. The caret constraint (^2.0.0) is appropriate and will allow patch and minor version updates. Monitor related Remix auth libraries (e.g., authkit-remix) for vulnerabilities.

apps/webapp/app/routes/auth.github.callback.tsx (1)

45-49: LGTM!

The refactoring to use Headers with multiple append calls for setting both the session and last-auth-method cookies is correct and follows the proper pattern for multiple Set-Cookie headers in Remix.

Also applies to: 55-59

apps/webapp/app/routes/login._index/route.tsx (2)

74-120: LGTM!

The loader correctly fetches lastAuthMethod from the request cookie and includes both showGoogleAuth and lastAuthMethod in both response paths. The data flow is consistent.


136-188: LGTM!

The login UI correctly renders provider buttons conditionally and displays the "Last used" badge based on the lastAuthMethod value. The form actions properly include the redirectTo query parameter.

apps/webapp/app/routes/auth.google.callback.tsx (1)

1-60: LGTM!

The Google OAuth callback follows the established pattern from the GitHub callback. The implementation correctly handles:

  • Redirect cookie parsing and sanitization
  • Authentication with the "google" strategy
  • MFA flow detection and redirect
  • Multiple Set-Cookie headers for session and last-auth-method
apps/webapp/app/services/lastAuthMethod.server.ts (1)

13-24: LGTM!

The getLastAuthMethod and setLastAuthMethodHeader functions are well-implemented with proper type safety and explicit validation of cookie values.

apps/webapp/app/models/user.server.ts (4)

24-31: LGTM!

The FindOrCreateGoogle type follows the established pattern from FindOrCreateGithub and correctly uses a type instead of an interface per coding guidelines. The union type is properly extended.


210-229: Inconsistent behavior with GitHub user linking.

When linking an existing email user to Google auth, this code updates authenticationMethod to "GOOGLE". However, findOrCreateGithubUser (lines 120-137) does not update authenticationMethod when linking. This inconsistency could cause confusion about the user's primary auth method.

Is this intentional? If so, consider adding a comment explaining why the behavior differs. If not, align the behavior:

     // Link existing email account to Google auth
     const user = await prisma.user.update({
       where: {
         email,
       },
       data: {
-        authenticationMethod: "GOOGLE",
         authenticationProfile: authProfile,
         authenticationExtraParams: authExtraParams,
         avatarUrl,
         authIdentifier,
       },
     });

250-270: LGTM!

The upsert logic for new Google users correctly sets up the user with Google authentication method and profile data. The pattern is consistent with the GitHub implementation.


183-188: All accessed fields exist on GoogleProfile type and are correctly typed.

The web search confirms that GoogleProfile from remix-auth-google includes all accessed fields:

  • _json.name: string ✓
  • photos: array of objects with value property ✓
  • displayName: string ✓
  • id: string ✓

The code safely accesses these fields. The if (authenticationProfile.photos[0]) guard on line 185 prevents null/undefined access issues.

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 (4)
apps/webapp/app/assets/logos/GoogleLogo.tsx (1)

1-22: LGTM! Consider adding accessibility attributes.

The GoogleLogo component is well-implemented with proper SVG structure and styling. The named export follows the coding guidelines.

For improved accessibility, consider adding an aria-label or wrapping the SVG in a way that provides context for screen reader users, especially if this logo is used in interactive elements like buttons.

Example enhancement:

-export function GoogleLogo({ className }: { className?: string }) {
+export function GoogleLogo({ className, ariaLabel }: { className?: string; ariaLabel?: string }) {
   return (
-    <svg className={className} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <svg 
+      className={className} 
+      viewBox="0 0 24 24" 
+      fill="none" 
+      xmlns="http://www.w3.org/2000/svg"
+      aria-label={ariaLabel}
+      role={ariaLabel ? "img" : undefined}
+    >
       <path
apps/webapp/app/routes/login._index/route.tsx (3)

22-40: LastUsedBadge implementation looks solid; consider minor a11y / UX tweaks

The motion + useReducedMotion usage is clean and respects reduced-motion preferences, and the visual treatment is clear.

Two small optional refinements:

  • To avoid screen readers announcing a detached “Last used” label without context, consider either:
    • Marking the badge container as decorative: aria-hidden="true", or
    • Wiring it via aria-describedby from the corresponding button, so it’s semantically tied to that control.
  • If you find the badge sometimes intercepts clicks near the right edge of the button, you could add pointer-events-none on the outer wrapper (and re-enable pointer events only on the button if needed).

These are polish-level changes; current behavior is acceptable if you’re okay with the existing semantics.


118-181: Multi‑provider login UI and “last used” badge behavior look coherent

The new layout with stacked GitHub, Google, and Email options is consistent:

  • Conditional rendering via data.showGithubAuth / data.showGoogleAuth is straightforward.
  • Action URLs correctly preserve redirectTo where present.
  • LastUsedBadge is correctly scoped via data.lastAuthMethod === "<provider>" and only displayed when the provider is visible.
  • data.authError && <FormError> continues to behave as expected across loader branches.

If this grows further (e.g., more providers), you might eventually want a small <AuthProviderButton> abstraction to avoid duplicating the container + Form + Button pattern, but for the current three providers the duplication is manageable.


183-191: Add rel attribute to external links that use target="_blank"

Both legal links open in a new tab via target="_blank", but lack a rel attribute. To avoid reverse‑tabnabbing and follow common security best practices, consider:

- <TextLink href="https://trigger.dev/legal" target="_blank">
+ <TextLink href="https://trigger.dev/legal" target="_blank" rel="noreferrer noopener">- <TextLink href="https://trigger.dev/legal/privacy" target="_blank">
+ <TextLink href="https://trigger.dev/legal/privacy" target="_blank" rel="noreferrer noopener">

Even though these are same‑origin links, using rel="noopener noreferrer" on all target="_blank" links is a good default.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5523569 and 9fc1dd8.

📒 Files selected for processing (2)
  • apps/webapp/app/assets/logos/GoogleLogo.tsx (1 hunks)
  • apps/webapp/app/routes/login._index/route.tsx (6 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/assets/logos/GoogleLogo.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/assets/logos/GoogleLogo.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/assets/logos/GoogleLogo.tsx
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/assets/logos/GoogleLogo.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Files:

  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/assets/logos/GoogleLogo.tsx
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • apps/webapp/app/routes/login._index/route.tsx
  • apps/webapp/app/assets/logos/GoogleLogo.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
apps/webapp/app/routes/login._index/route.tsx (1)

71-82: Loader wiring for lastAuthMethod and Google support looks correct; verify value domain

The loader changes cleanly plumb lastAuthMethod and showGoogleAuth through both branches of the response, and the UI only branches on strict string matches ("github" | "google" | "email"), so unknown values gracefully result in no badge.

One thing to double‑check: ensure getLastAuthMethod(request) is constrained to a narrow union (e.g. "github" | "google" | "email" | null) and safely handles missing/invalid cookies, ideally with validation at the helper level (e.g. zod narrowing). That keeps the loader and useTypedLoaderData types tight and prevents accidental propagation of arbitrary values.

Also applies to: 103-108

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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fc1dd8 and ddecae4.

📒 Files selected for processing (1)
  • apps/webapp/app/models/user.server.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • apps/webapp/app/models/user.server.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/models/user.server.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • apps/webapp/app/models/user.server.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/models/user.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Files:

  • apps/webapp/app/models/user.server.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • apps/webapp/app/models/user.server.ts
🧠 Learnings (2)
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • apps/webapp/app/models/user.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Leverage the PostgreSQL database through the `trigger.dev/database` Prisma 6.14.0 client in the webapp for all data access patterns

Applied to files:

  • apps/webapp/app/models/user.server.ts
🧬 Code graph analysis (1)
apps/webapp/app/models/user.server.ts (1)
apps/webapp/app/utils/email.ts (1)
  • assertEmailAllowed (3-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
apps/webapp/app/models/user.server.ts (3)

3-3: LGTM! Type definitions follow existing patterns.

The GoogleProfile import and FindOrCreateGoogle type definition are consistent with the existing GitHub authentication implementation.

Also applies to: 24-31


46-48: LGTM! Switch case properly integrated.

The Google authentication case correctly delegates to the new handler function, maintaining consistency with existing authentication methods.


176-196: LGTM! Profile extraction and validation are correct.

The email validation and profile data extraction follow the same pattern as the GitHub authentication implementation.

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/webapp/app/routes/login._index/route.tsx (1)

22-40: Consider adding an accessible label for screen readers.

The LastUsedBadge component respects motion preferences (good!), but it lacks semantic information for assistive technologies. Screen reader users won't know which authentication method was last used.

Consider adding an aria-label to the motion.div:

      <motion.div
        className="relative rounded border border-charcoal-700 bg-charcoal-800 px-2 py-1 text-center text-xxs font-medium uppercase text-blue-500"
+       aria-label="Last used authentication method"
        initial={shouldReduceMotion ? undefined : { opacity: 0, x: 4 }}
        animate={shouldReduceMotion ? undefined : { opacity: 1, x: 0 }}
        transition={shouldReduceMotion ? undefined : { duration: 0.8, ease: "easeOut" }}
      >
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ddecae4 and 7e50b54.

📒 Files selected for processing (1)
  • apps/webapp/app/routes/login._index/route.tsx (6 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • apps/webapp/app/routes/login._index/route.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/routes/login._index/route.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • apps/webapp/app/routes/login._index/route.tsx
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/routes/login._index/route.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Files:

  • apps/webapp/app/routes/login._index/route.tsx
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • apps/webapp/app/routes/login._index/route.tsx
🧬 Code graph analysis (1)
apps/webapp/app/routes/login._index/route.tsx (6)
apps/webapp/app/services/lastAuthMethod.server.ts (1)
  • getLastAuthMethod (14-21)
apps/webapp/app/services/auth.server.ts (1)
  • isGoogleAuthSupported (31-31)
apps/webapp/app/components/primitives/Headers.tsx (1)
  • Header1 (32-50)
apps/webapp/app/components/primitives/Paragraph.tsx (1)
  • Paragraph (88-107)
apps/webapp/app/components/primitives/Buttons.tsx (1)
  • Button (296-329)
apps/webapp/app/assets/logos/GoogleLogo.tsx (1)
  • GoogleLogo (1-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
apps/webapp/app/routes/login._index/route.tsx (4)

5-5: LGTM!

The new imports correctly support Google authentication and the last-used indicator feature. The framer-motion library is appropriately used for the animated badge component.

Also applies to: 7-7, 15-16


71-71: LGTM!

The loader correctly fetches the last-used authentication method and Google auth support flag, passing them consistently to the UI in both conditional branches.

Also applies to: 80-81, 106-107


127-179: Well-structured multi-provider authentication UI.

The conditional rendering of LastUsedBadge for each authentication method is correctly implemented. Each provider is properly wrapped in a relative container, and the form actions correctly include the redirectTo parameter.


118-194: Clean and well-organized layout structure.

The login page structure is logically organized with clear sections for the header, authentication options, error display, and legal notices. The terms and privacy links properly open in new tabs.

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/webapp/app/models/user.server.ts (1)

14-23: AuthConflictError is defined but never used.

This error class is exported but never thrown anywhere in the file. The conflict case at lines 247-260 logs the error and returns existingUser instead of throwing AuthConflictError. Either:

  1. Throw this error in the conflict case so callers can handle it appropriately (e.g., show a user-friendly message), or
  2. Remove the unused class if silent handling is intentional.

If the intent is to surface this conflict to the user, consider:

       logger.error(
         `Google auth conflict: Google ID ${authenticationProfile.id} belongs to user ${existingUser.id} but email ${email} is taken by user ${existingEmailUser.id}`,
         {
           email,
           existingEmailUserId: existingEmailUser.id,
           existingAuthUserId: existingUser.id,
           authIdentifier,
         }
       );

-      return {
-        user: existingUser,
-        isNewUser: false,
-      };
+      throw new AuthConflictError(
+        `Email ${email} is already associated with a different account`,
+        existingEmailUser.id,
+        existingUser.id
+      );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7e50b54 and 3e1b5e0.

📒 Files selected for processing (1)
  • apps/webapp/app/models/user.server.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • apps/webapp/app/models/user.server.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/models/user.server.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • apps/webapp/app/models/user.server.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/models/user.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Files:

  • apps/webapp/app/models/user.server.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • apps/webapp/app/models/user.server.ts
🧠 Learnings (2)
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • apps/webapp/app/models/user.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Leverage the PostgreSQL database through the `trigger.dev/database` Prisma 6.14.0 client in the webapp for all data access patterns

Applied to files:

  • apps/webapp/app/models/user.server.ts
🧬 Code graph analysis (1)
apps/webapp/app/models/user.server.ts (1)
apps/webapp/app/utils/email.ts (1)
  • assertEmailAllowed (3-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (24)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
apps/webapp/app/models/user.server.ts (4)

37-42: LGTM!

The type definition follows the established pattern from FindOrCreateGithub and uses type instead of interface per coding guidelines.


44-44: LGTM!

Union type correctly extended to include FindOrCreateGoogle.


59-61: LGTM!

Correctly dispatches to the new findOrCreateGoogleUser function.


243-261: Verify intended behavior when Google email conflicts with existing user.

When a conflict is detected (Google auth belongs to user A, but the current Google email is already taken by user B), the code:

  1. Logs the conflict
  2. Returns user A (the Google-authenticated user)
  3. Does not update user A's email to match their current Google email

This means user A continues to have their old email in the system while authenticating with a different Google email. Is this the intended behavior? Consider whether:

  • User A should be prompted to resolve the conflict
  • The AuthConflictError should be thrown to allow the caller to handle this case (e.g., show an error page)

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

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/webapp/app/models/user.server.ts (1)

189-315: Consider refactoring to reduce duplication with GitHub authentication.

The findOrCreateGoogleUser function has significant overlap with findOrCreateGithubUser (lines 99-187). Common patterns include:

  • Profile extraction (name, avatarUrl, displayName)
  • Prisma.JsonObject casting
  • Three-branch logic (link, conflict/update, upsert)

While acceptable for feature delivery, future refactoring could extract shared logic into helper functions to improve maintainability.

Example refactoring approach:

function extractOAuthProfile(profile: GitHubProfile | GoogleProfile, authenticationExtraParams: Record<string, unknown>) {
  const name = profile._json.name;
  const avatarUrl = profile.photos[0]?.value;
  const displayName = profile.displayName;
  const authProfile = profile as unknown as Prisma.JsonObject;
  const authExtraParams = authenticationExtraParams as unknown as Prisma.JsonObject;
  
  return { name, avatarUrl, displayName, authProfile, authExtraParams };
}

This refactoring can be deferred to a future PR focused on code quality improvements.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e1b5e0 and 6944207.

📒 Files selected for processing (1)
  • apps/webapp/app/models/user.server.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

Files:

  • apps/webapp/app/models/user.server.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/models/user.server.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • apps/webapp/app/models/user.server.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/models/user.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Files:

  • apps/webapp/app/models/user.server.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • apps/webapp/app/models/user.server.ts
🧠 Learnings (2)
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • apps/webapp/app/models/user.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Leverage the PostgreSQL database through the `trigger.dev/database` Prisma 6.14.0 client in the webapp for all data access patterns

Applied to files:

  • apps/webapp/app/models/user.server.ts
🧬 Code graph analysis (1)
apps/webapp/app/models/user.server.ts (2)
apps/webapp/app/utils/email.ts (1)
  • assertEmailAllowed (3-13)
apps/webapp/app/db.server.ts (1)
  • Prisma (99-99)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Cursor Bugbot
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (5)
apps/webapp/app/models/user.server.ts (5)

3-3: LGTM!

The GoogleProfile and logger imports are necessary for the new Google authentication flow and conflict logging.

Also applies to: 12-12


37-44: LGTM!

The FindOrCreateGoogle type and union extension follow the existing pattern for GitHub authentication and properly type the Google OAuth flow.


59-61: LGTM!

The switch case correctly routes Google authentication requests to the new handler function.


245-261: Verify conflict handling aligns with product requirements.

When a Google ID belongs to one user but the associated email belongs to a different user (e.g., user A changed their Google email to user B's email), the code logs the conflict and returns user A (the Google-authenticated user) without updating their email.

Behavior:

  • User A successfully logs in with Google
  • User A's email remains unchanged (not updated to the conflicting email)
  • User A can continue using the app normally
  • Conflict is logged for investigation

Consideration: Should users be prevented from logging in when this conflict occurs, or is silent logging with successful login acceptable? If users should be blocked, throw AuthConflictError instead (see previous comment).

Confirm with product/design that this conflict resolution strategy meets requirements. If users should be notified or blocked, update the error handling accordingly.


189-315: Excellent implementation addressing past review concerns.

The findOrCreateGoogleUser function correctly handles the key scenarios:

  1. Linking email accounts (lines 223-241): Preserves the original authenticationMethod when linking an existing email user to Google ✓
  2. Conflict detection (lines 245-261): Detects when email and Google ID belong to different users and logs the conflict ✓
  3. Profile updates (lines 263-281): Updates all fields (email, displayName, name, avatarUrl, authenticationProfile, authenticationExtraParams) for returning users ✓
  4. Upsert completeness (lines 291-297): Includes authenticationProfile and authenticationExtraParams in the update path ✓

The control flow ensures email availability before upserting, preventing database constraint violations.

@ericallam ericallam merged commit f62cdfe into main Dec 9, 2025
32 checks passed
@ericallam ericallam deleted the ea-branch-108 branch December 9, 2025 09:51
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.

5 participants