Skip to content

google authentication - #9

Merged
Niro0526 merged 1 commit into
masterfrom
niroja
Sep 9, 2026
Merged

Niro0526 merged 1 commit into
masterfrom
niroja

Conversation

@Niro0526

@Niro0526 Niro0526 commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@gitguardian

gitguardian Bot commented Sep 9, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
37115256 Triggered Generic Password 27e2c98 backend/src/routes/auth.ts View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@Niro0526
Niro0526 merged commit 1f26329 into master Sep 9, 2026
0 of 2 checks passed
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add Google authentication and persistent password changes

✨ Enhancement 🐞 Bug fix 🕐 40+ Minutes

Grey Divider

AI Description

• Add Google sign-in and automatic account provisioning across frontend and backend.
• Refresh localized authentication forms with password visibility and demo access.
• Persist authenticated password changes and surface Google account status in settings.
Diagram

sequenceDiagram
  actor U as User
  participant P as Auth Pages
  participant G as Google GIS
  participant A as Auth API
  participant V as Token Info
  participant D as Users DB
  U->>P: Choose authentication
  alt Google configured
    P->>G: Request identity
    G-->>P: Return credential
    P->>A: Submit credential
    A->>V: Validate token
    V-->>A: Return claims
  else Demo fallback
    P->>A: Submit demo identity
  end
  A->>D: Find or create user
  D-->>A: Return user
  A-->>P: Return app JWT
  P-->>U: Open authenticated area
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Verify tokens with Google Auth Library
  • ➕ Cryptographically verifies signatures, issuer, audience, and token expiry
  • ➕ Avoids accepting identities from unsigned JWT decoding or request fields
  • ➕ Removes a per-login dependency on the tokeninfo HTTP endpoint
  • ➖ Adds a backend dependency
  • ➖ Requires Google client configuration and key-cache handling
2. Authorization code flow with PKCE
  • ➕ Keeps token exchange and provider credentials under backend control
  • ➕ Supports refresh tokens and future Google API authorization
  • ➖ Requires redirect, state, PKCE, and callback management
  • ➖ More complex than authentication-only ID token verification
3. Persist linked identity records
  • ➕ Tracks provider and Google subject identifiers explicitly
  • ➕ Supports accurate linking status and multiple providers per user
  • ➕ Avoids inferring Google linkage from email text
  • ➖ Requires a schema migration and account-linking workflow
  • ➖ Adds conflict-resolution rules for existing email accounts

Recommendation: Use server-side Google ID-token verification, preferably through Google's supported library, and reject direct email identities or unsigned JWT decoding outside an explicitly isolated test fixture. Persist provider linkage using Google's stable subject identifier; the current email-based fallback permits impersonation, while the settings status and connect action do not represent a real account link.

Files changed (6) +670 / -61

Enhancement (4) +599 / -48
auth.tsAdd Google authentication and authenticated password updates +132/-0

Add Google authentication and authenticated password updates

• Adds a Google authentication endpoint that resolves token claims, finds or provisions a user, and issues an application JWT. Also adds a protected endpoint that verifies the current password before persisting a replacement hash.

backend/src/routes/auth.ts

google-auth-button.tsxIntroduce a reusable Google Identity Services button +231/-0

Introduce a reusable Google Identity Services button

• Adds a shared Google authentication component that loads Google Identity Services, exchanges credentials with the backend, and stores the resulting session. It also provides a direct demo-account fallback when no client ID is configured.

frontend/src/components/google-auth-button.tsx

login.tsxRedesign login with Google and demo authentication +126/-23

Redesign login with Google and demo authentication

• Integrates Google sign-in, a one-click student demo, password visibility, autocomplete metadata, and more detailed API errors. It also refreshes the login card's responsive styling and visual hierarchy.

frontend/src/pages/login.tsx

register.tsxAdd Google sign-up and improve registration usability +110/-25

Add Google sign-up and improve registration usability

• Integrates Google account registration and adds password visibility, autocomplete hints, improved validation messaging, and refreshed card styling.

frontend/src/pages/register.tsx

Bug fix (1) +44 / -13
settings.tsxPersist password changes and expose Google account status +44/-13

Persist password changes and expose Google account status

• Replaces the simulated password-change delay with a protected backend request and error handling. It also presents Google connection status and actions inferred from the authenticated user's email.

frontend/src/pages/settings.tsx

Other (1) +27 / -0
i18n.tsLocalize new authentication controls and feedback +27/-0

Localize new authentication controls and feedback

• Adds English, Sinhala, and Tamil strings for Google sign-in, authentication status, password visibility, dividers, and demo account controls.

frontend/src/lib/i18n.ts

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (7) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Tokens for other apps grant access 🐞 Bug ⛨ Security
Description
Audience validation runs only when GOOGLE_CLIENT_ID is configured, so a missing backend variable
makes every Google OAuth client an accepted audience. The documented backend environment omits that
variable, allowing a valid token obtained for another application to establish a session here.
Code

backend/src/routes/auth.ts[R116-119]

+        if (process.env.GOOGLE_CLIENT_ID && payload.aud !== process.env.GOOGLE_CLIENT_ID) {
+          res.status(401).json({ error: "Google token audience mismatch" });
+          return;
+        }
Evidence
The condition explicitly skips comparison when the environment variable is absent, while neither the
backend environment example nor deployment instructions defines it. Google's validation requirements
state that aud must equal one of this application's client IDs to prevent cross-application token
replay.

backend/src/routes/auth.ts[109-119]
backend/.env.example[6-14]
README.md[103-109]
🌐 Google states that the audience must match the application's client ID to prevent tokens issued to a malicious app from being used against the backend.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The backend skips token audience validation when its Google client ID is missing, accepting tokens issued to unrelated applications.

## Issue Context
Google client configuration must be mandatory when Google authentication is enabled, and startup or authentication should fail closed if it is absent.

## Fix Focus Areas
- backend/src/routes/auth.ts[101-124]
- backend/.env.example[6-14]
- README.md[95-109]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Reassigned emails inherit accounts 🐞 Bug ⛨ Security
Description
The route associates a Google login with an existing local account solely through payload.email,
despite parsing but never checking email_verified, hosted-domain authority, or Google's stable
subject identifier. A Google account using a third-party email that is later reassigned can
therefore enter the new owner's matching local account because Google does not remain authoritative
for such addresses.
Code

backend/src/routes/auth.ts[R121-124]

+        if (payload.email) {
+          targetEmail = payload.email.toLowerCase();
+          if (payload.name) targetName = payload.name;
+        }
Evidence
The payload extraction omits sub, ignores email_verified, and uses only the email to locate an
existing user. The user schema has no provider identifier, while Google documents that it is not
authoritative for non-Gmail, non-Workspace addresses and that ownership of such an address may
change after initial verification.

backend/src/routes/auth.ts[109-124]
backend/src/routes/auth.ts[151-176]
backend/src/db/schema/users.ts[5-16]
🌐 Google explains that it is not authoritative for third-party email addresses and that ownership may have changed even when the email was initially verified.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Google identities are linked to local accounts solely by mutable email, permitting an old holder of a reassigned third-party address to enter the new holder's account.

## Issue Context
Persist Google's stable `sub` identifier and provider metadata. Do not automatically merge an existing password account based only on a non-authoritative email; require authenticated account linking or another ownership challenge.

## Fix Focus Areas
- backend/src/routes/auth.ts[109-176]
- backend/src/db/schema/users.ts[5-16]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Anyone can sign in as another user 🐞 Bug ⛨ Security
Description
/auth/google initializes targetEmail from the unauthenticated, caller-controlled email field
and later signs an application token for the matching user without requiring a verified Google
credential. Posting any existing account’s email, including an administrator’s, reaches lookup and
token issuance, and the frontend deliberately sends this credential-free request whenever Google
configuration or loading is unavailable.
Code

backend/src/routes/auth.ts[R96-99]

+  const { credential, email: directEmail, name: directName } = req.body || {};
+
+  let targetEmail = typeof directEmail === "string" ? directEmail.trim().toLowerCase() : "";
+  let targetName = typeof directName === "string" ? directName.trim() : "";
Evidence
The route accepts directEmail as targetEmail, validates it only with an @ check, looks up the
matching existing user, and signs a seven-day application JWT for that user ID, unlike normal login,
which requires a successful bcrypt comparison. The frontend demonstrates that this path is reachable
by submitting only a fixed email and name, with no Google credential, when no client ID is
configured or Google is otherwise unavailable.

backend/src/routes/auth.ts[54-79]
backend/src/routes/auth.ts[95-99]
backend/src/routes/auth.ts[142-176]
frontend/src/components/google-auth-button.tsx[153-169]
backend/src/middleware/auth.ts[28-46]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Reject direct email/name authentication in the Google authentication endpoint and derive account identity exclusively from a successfully verified Google ID token. The endpoint currently accepts a caller-provided email without proof of identity, allowing authentication as any matching existing account.

## Issue Context
The normal email/password route verifies a bcrypt password before issuing a token, whereas the Google route can issue one based only on an email from the request body. The frontend fallback intentionally invokes this endpoint with only an email and name when Google configuration or loading is unavailable; production authentication must never derive identity from these direct fields.

## Fix Focus Areas
- backend/src/routes/auth.ts[95-176]
- frontend/src/components/google-auth-button.tsx[153-169]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View high (1)
4. Forged credentials can access accounts 🐞 Bug ⛨ Security
Description
When Google's token endpoint returns a non-success response, /auth/google base64-decodes the
submitted credential and trusts its email without validating the signature, issuer, expiry,
audience, or verified-email status. An attacker can supply a fabricated three-part token containing
a victim's email, which then reaches the normal account lookup and application-session signing flow.
Code

backend/src/routes/auth.ts[R125-130]

+      } else {
+        // In local/test mode if external Google call fails, fall back to decoding payload safely
+        const parts = credential.split(".");
+        if (parts.length === 3) {
+          const rawPayload = Buffer.from(parts[1], "base64").toString("utf-8");
+          const parsed = JSON.parse(rawPayload);
Evidence
The fallback base64-decodes attacker-controlled JWT content and assigns its email directly to
targetEmail; that value then drives local account lookup and session signing. Although
email_verified is included in the response type, no condition checks it, audience validation is
skipped entirely when the environment variable is absent, and the fallback is not restricted to
tests despite its comment; Google's backend authentication guidance requires signature, audience,
issuer, and expiry verification before using an ID token.

backend/src/routes/auth.ts[109-135]
backend/src/routes/auth.ts[137-176]
backend/src/routes/auth.ts[125-135]
backend/src/routes/auth.ts[151-176]
🌐 Google requires backend ID tokens to have a valid signature, matching audience, Google issuer, and unexpired timestamp before establishing a session.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description

Remove the behavior that decodes and trusts a credential after Google verification fails. Reject failed verification attempts, and require validation of the token's signature, expected audience, issuer, expiry, and verified-email status before using any identity claims.

## Issue Context

The fallback is not restricted to tests despite its comment. It converts an attacker-supplied token segment into `targetEmail`, which is then used to select an existing local user and issue an application session; every authentication attempt must fail closed when Google validation fails.

## Fix Focus Areas

- backend/src/routes/auth.ts[101-140]
- backend/src/routes/auth.ts[151-176]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Google users cannot change passwords 🐞 Bug ≡ Correctness
Description
New Google accounts receive a generated random password that is never returned or otherwise made
available to the account holder. The new change-password route requires that undisclosed current
password, so these users cannot complete the Settings form to establish a password.
Code

backend/src/routes/auth.ts[R157-160]

+  if (!user) {
+    // Generate a random secure hash for Google users who don't log in via traditional password
+    const randomPassword = `G-${Math.random().toString(36).slice(2)}-${Date.now()}`;
+    const passwordHash = await bcrypt.hash(randomPassword, 10);
Evidence
The Google registration flow hashes a random value and does not expose it, while the new update
route always bcrypt-compares a user-supplied current password before updating. Settings renders and
submits that current-password form for authenticated users, including accounts created by Google
sign-in.

backend/src/routes/auth.ts[157-170]
backend/src/routes/auth.ts[193-223]
frontend/src/pages/settings.tsx[149-203]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Provide a password-establishment flow for Google-created accounts that is authorized by an appropriate recent Google authentication, rather than requiring the generated password.

## Issue Context
The account creation path stores an unknowable random password, but the password update endpoint only permits changes after matching the current hash.

## Fix Focus Areas
- backend/src/routes/auth.ts[157-170]
- backend/src/routes/auth.ts[193-223]
- frontend/src/pages/settings.tsx[154-203]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Google connection status is fictitious 🐞 Bug ≡ Correctness
Description
The Settings “Connect Google” handler only emits a success toast without invoking Google Identity
Services, calling an account-linking endpoint, or persisting provider state, while connection status
is inferred by checking whether the email contains google or ends in @gmail.com. Clicking the
control therefore leaves the account unchanged but claims success, and ordinary Gmail addresses
appear linked even though the backend only finds or creates users by email and stores no provider
identity.
Code

frontend/src/pages/settings.tsx[R949-954]

+                        onClick={() => {
+                          toast({
+                            title: "Google Account Connected",
+                            description: `Primary email ${authUser?.email} is linked to Google sign-in.`,
+                          });
+                        }}
Evidence
The click handler contains only a toast call, while the displayed connection status is derived from
email string matching. The backend authentication route only identifies a user by email and creates
one when absent, and neither the user schema nor the authentication response contains persisted
Google provider state that the UI could update or inspect.

frontend/src/pages/settings.tsx[934-961]
backend/src/routes/auth.ts[151-176]
backend/src/db/schema/users.ts[5-16]
backend/src/routes/auth.ts[151-190]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Replace the no-op success action and email-address heuristic with a verified Google account-linking flow and persisted provider-link state. The settings control must not report a successful connection unless authentication and account linking have completed and been stored.

## Issue Context
There is currently no backend linking operation: the existing Google route only finds or creates a user by email, and the user model exposes no persisted Google provider identity. Connection status must come from stored provider metadata rather than checking whether an email contains `google` or ends in `@gmail.com`. Until a secure linking flow exists, keep the control disabled and avoid success messaging.

## Fix Focus Areas
- frontend/src/pages/settings.tsx[934-961]
- backend/src/routes/auth.ts[95-191]
- backend/src/db/schema/users.ts[5-16]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Concurrent first sign-ins can fail 🐞 Bug ☼ Reliability
Description
/auth/google performs a separate lookup followed by an unconditional insert for a missing user,
without atomic creation or duplicate-key recovery around the unique email column. Two concurrent
first sign-ins for the same email can both observe no row, after which the losing insert raises an
unhandled database error that reaches the generic application error handler.
Code

backend/src/routes/auth.ts[R152-155]

+  let [user] = await db
+    .select()
+    .from(usersTable)
+    .where(eq(usersTable.email, targetEmail));
Evidence
The route selects the user and inserts a missing account in separate operations, while the database
schema enforces email uniqueness. Because the route has no transaction, upsert, ON CONFLICT
strategy, or duplicate-key recovery, simultaneous requests can race and one insert can fail; the
application’s generic error middleware converts that unhandled database exception into an HTTP 500
response.

backend/src/routes/auth.ts[151-173]
backend/src/db/schema/users.ts[5-16]
backend/src/app.ts[47-64]
backend/src/routes/auth.ts[151-174]
backend/src/db/schema/users.ts[5-8]
backend/src/app.ts[47-63]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Make Google user provisioning safe for concurrent first-time sign-ins. Use atomic account creation or recover from a duplicate-email insert by loading the canonical user before issuing the session.

## Issue Context
Email is a unique database key, but the route currently checks for a user and inserts one in separate operations without conflict handling. Two requests for the same new email can both observe no account and race to insert it, causing one request to reach the generic error handler with a database exception. Use an atomic upsert or `ON CONFLICT` strategy and then retrieve the canonical user; do not overwrite an existing account’s identity data during conflict recovery.

## Fix Focus Areas
- backend/src/routes/auth.ts[151-174]
- backend/src/db/schema/users.ts[5-16]
- backend/src/app.ts[47-64]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Web pages:
  +2 more
Review mode: 🧠 Deep: This authentication and password-management change introduces security-sensitive backend logic plus multiple independent frontend flows, with a high density of plausible authentication and authorization defects.

Grey Divider

Tip of the day
💡 Did you know, you can commit Qodo's fix in one click with committable suggestions (GitHub & GitLab)

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines +116 to +119
if (process.env.GOOGLE_CLIENT_ID && payload.aud !== process.env.GOOGLE_CLIENT_ID) {
res.status(401).json({ error: "Google token audience mismatch" });
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Tokens for other apps grant access 🐞 Bug ⛨ Security

Audience validation runs only when GOOGLE_CLIENT_ID is configured, so a missing backend variable
makes every Google OAuth client an accepted audience. The documented backend environment omits that
variable, allowing a valid token obtained for another application to establish a session here.
Agent Prompt
## Issue description
The backend skips token audience validation when its Google client ID is missing, accepting tokens issued to unrelated applications.

## Issue Context
Google client configuration must be mandatory when Google authentication is enabled, and startup or authentication should fail closed if it is absent.

## Fix Focus Areas
- backend/src/routes/auth.ts[101-124]
- backend/.env.example[6-14]
- README.md[95-109]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +121 to +124
if (payload.email) {
targetEmail = payload.email.toLowerCase();
if (payload.name) targetName = payload.name;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Reassigned emails inherit accounts 🐞 Bug ⛨ Security

The route associates a Google login with an existing local account solely through payload.email,
despite parsing but never checking email_verified, hosted-domain authority, or Google's stable
subject identifier. A Google account using a third-party email that is later reassigned can
therefore enter the new owner's matching local account because Google does not remain authoritative
for such addresses.
Agent Prompt
## Issue description
Google identities are linked to local accounts solely by mutable email, permitting an old holder of a reassigned third-party address to enter the new holder's account.

## Issue Context
Persist Google's stable `sub` identifier and provider metadata. Do not automatically merge an existing password account based only on a non-authoritative email; require authenticated account linking or another ownership challenge.

## Fix Focus Areas
- backend/src/routes/auth.ts[109-176]
- backend/src/db/schema/users.ts[5-16]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +96 to +99
const { credential, email: directEmail, name: directName } = req.body || {};

let targetEmail = typeof directEmail === "string" ? directEmail.trim().toLowerCase() : "";
let targetName = typeof directName === "string" ? directName.trim() : "";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. Anyone can sign in as another user 🐞 Bug ⛨ Security

/auth/google initializes targetEmail from the unauthenticated, caller-controlled email field
and later signs an application token for the matching user without requiring a verified Google
credential. Posting any existing account’s email, including an administrator’s, reaches lookup and
token issuance, and the frontend deliberately sends this credential-free request whenever Google
configuration or loading is unavailable.
Agent Prompt
## Issue description
Reject direct email/name authentication in the Google authentication endpoint and derive account identity exclusively from a successfully verified Google ID token. The endpoint currently accepts a caller-provided email without proof of identity, allowing authentication as any matching existing account.

## Issue Context
The normal email/password route verifies a bcrypt password before issuing a token, whereas the Google route can issue one based only on an email from the request body. The frontend fallback intentionally invokes this endpoint with only an email and name when Google configuration or loading is unavailable; production authentication must never derive identity from these direct fields.

## Fix Focus Areas
- backend/src/routes/auth.ts[95-176]
- frontend/src/components/google-auth-button.tsx[153-169]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +125 to +130
} else {
// In local/test mode if external Google call fails, fall back to decoding payload safely
const parts = credential.split(".");
if (parts.length === 3) {
const rawPayload = Buffer.from(parts[1], "base64").toString("utf-8");
const parsed = JSON.parse(rawPayload);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

4. Forged credentials can access accounts 🐞 Bug ⛨ Security

When Google's token endpoint returns a non-success response, /auth/google base64-decodes the
submitted credential and trusts its email without validating the signature, issuer, expiry,
audience, or verified-email status. An attacker can supply a fabricated three-part token containing
a victim's email, which then reaches the normal account lookup and application-session signing flow.
Agent Prompt
## Issue description

Remove the behavior that decodes and trusts a credential after Google verification fails. Reject failed verification attempts, and require validation of the token's signature, expected audience, issuer, expiry, and verified-email status before using any identity claims.

## Issue Context

The fallback is not restricted to tests despite its comment. It converts an attacker-supplied token segment into `targetEmail`, which is then used to select an existing local user and issue an application session; every authentication attempt must fail closed when Google validation fails.

## Fix Focus Areas

- backend/src/routes/auth.ts[101-140]
- backend/src/routes/auth.ts[151-176]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +157 to +160
if (!user) {
// Generate a random secure hash for Google users who don't log in via traditional password
const randomPassword = `G-${Math.random().toString(36).slice(2)}-${Date.now()}`;
const passwordHash = await bcrypt.hash(randomPassword, 10);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

5. Google users cannot change passwords 🐞 Bug ≡ Correctness

New Google accounts receive a generated random password that is never returned or otherwise made
available to the account holder. The new change-password route requires that undisclosed current
password, so these users cannot complete the Settings form to establish a password.
Agent Prompt
## Issue description
Provide a password-establishment flow for Google-created accounts that is authorized by an appropriate recent Google authentication, rather than requiring the generated password.

## Issue Context
The account creation path stores an unknowable random password, but the password update endpoint only permits changes after matching the current hash.

## Fix Focus Areas
- backend/src/routes/auth.ts[157-170]
- backend/src/routes/auth.ts[193-223]
- frontend/src/pages/settings.tsx[154-203]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +949 to +954
onClick={() => {
toast({
title: "Google Account Connected",
description: `Primary email ${authUser?.email} is linked to Google sign-in.`,
});
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

6. Google connection status is fictitious 🐞 Bug ≡ Correctness

The Settings “Connect Google” handler only emits a success toast without invoking Google Identity
Services, calling an account-linking endpoint, or persisting provider state, while connection status
is inferred by checking whether the email contains google or ends in @gmail.com. Clicking the
control therefore leaves the account unchanged but claims success, and ordinary Gmail addresses
appear linked even though the backend only finds or creates users by email and stores no provider
identity.
Agent Prompt
## Issue description
Replace the no-op success action and email-address heuristic with a verified Google account-linking flow and persisted provider-link state. The settings control must not report a successful connection unless authentication and account linking have completed and been stored.

## Issue Context
There is currently no backend linking operation: the existing Google route only finds or creates a user by email, and the user model exposes no persisted Google provider identity. Connection status must come from stored provider metadata rather than checking whether an email contains `google` or ends in `@gmail.com`. Until a secure linking flow exists, keep the control disabled and avoid success messaging.

## Fix Focus Areas
- frontend/src/pages/settings.tsx[934-961]
- backend/src/routes/auth.ts[95-191]
- backend/src/db/schema/users.ts[5-16]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +152 to +155
let [user] = await db
.select()
.from(usersTable)
.where(eq(usersTable.email, targetEmail));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

7. Concurrent first sign-ins can fail 🐞 Bug ☼ Reliability

/auth/google performs a separate lookup followed by an unconditional insert for a missing user,
without atomic creation or duplicate-key recovery around the unique email column. Two concurrent
first sign-ins for the same email can both observe no row, after which the losing insert raises an
unhandled database error that reaches the generic application error handler.
Agent Prompt
## Issue description
Make Google user provisioning safe for concurrent first-time sign-ins. Use atomic account creation or recover from a duplicate-email insert by loading the canonical user before issuing the session.

## Issue Context
Email is a unique database key, but the route currently checks for a user and inserts one in separate operations without conflict handling. Two requests for the same new email can both observe no account and race to insert it, causing one request to reach the generic error handler with a database exception. Use an atomic upsert or `ON CONFLICT` strategy and then retrieve the canonical user; do not overwrite an existing account’s identity data during conflict recovery.

## Fix Focus Areas
- backend/src/routes/auth.ts[151-174]
- backend/src/db/schema/users.ts[5-16]
- backend/src/app.ts[47-64]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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