fix(frontend): require confirmation before URL login session#1688
fix(frontend): require confirmation before URL login session#1688
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughA single-file change adds session-passing via URL tokens to the login page. The implementation introduces a deferred two-step authentication flow: tokens are extracted from the URL and stored temporarily, displaying a prompt to the user; accepting the prompt triggers session setup via Supabase; declining clears stored tokens and returns to the original login form. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant LoginComponent as Login Component
participant SupabaseAuth as Supabase Auth
User->>LoginComponent: Arrive with token in URL
activate LoginComponent
LoginComponent->>LoginComponent: Parse & store tokens<br/>(querySessionAccessToken,<br/>querySessionRefreshToken)<br/>Set hasQuerySession=true
LoginComponent->>LoginComponent: Remove tokens from URL
deactivate LoginComponent
LoginComponent->>User: Display "Accept/Cancel" prompt
alt User Accepts
User->>LoginComponent: Click Accept
activate LoginComponent
LoginComponent->>SupabaseAuth: setSession(stored tokens)
activate SupabaseAuth
SupabaseAuth-->>LoginComponent: Success
deactivate SupabaseAuth
LoginComponent->>LoginComponent: Clear stored tokens<br/>Set hasQuerySession=false
deactivate LoginComponent
LoginComponent->>User: Proceed to next login step
else User Declines
User->>LoginComponent: Click Cancel
activate LoginComponent
LoginComponent->>LoginComponent: Clear tokens & flags<br/>Hide loader
deactivate LoginComponent
LoginComponent->>User: Show original login form
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fa82fb8143
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
src/pages/login.vue
Outdated
| hasQuerySession.value = false | ||
| querySessionAccessToken.value = '' | ||
| querySessionRefreshToken.value = '' | ||
| if (res.error) { |
There was a problem hiding this comment.
Preserve query session tokens until setSession succeeds
Clearing hasQuerySession and both stored tokens before checking res.error makes transient setSession failures unrecoverable in this tab. Because the URL tokens were already removed in checkLogin, any temporary network/backend error after clicking Continue drops the only remaining credentials and forces the user to request a brand-new login link instead of retrying. Keep these values until setSession succeeds (or the user explicitly cancels) so a retry is possible.
Useful? React with 👍 / 👎.
* fix(build): handle tus HEAD upload route * fix(build): chain HEAD middleware correctly
* fix(security): protect replication endpoint * fix(api): require replication endpoint internal api secret * fix(api): allow admin JWT access to replication endpoint * fix(frontend): use admin session only when no replication secret
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/pages/login.vue (1)
370-379: Use DaisyUI button styles for the new interactive controls.For consistency with project UI conventions, switch these new actions to DaisyUI button classes/components.
As per coding guidelines,
src/**/*.vueshould "Use DaisyUI components (d-btn,d-input,d-card) for interactive elements in Vue components".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/login.vue` around lines 370 - 379, Replace the raw <button> elements for the Continue and decline actions with DaisyUI button components (use d-btn) so they follow project conventions; locate the elements that call acceptQuerySession and declineQuerySession and swap them to <d-btn> instances, transferring attributes like type and click handlers (`@click`="acceptQuerySession" / `@click`="declineQuerySession"), mapping visual styles to appropriate DaisyUI props/classes (e.g., primary/outline or variant props) and ensuring v-if="!isLoading" and any accessibility attributes remain; keep any custom classes that are still needed only if they don’t conflict with d-btn styling and ensure the dark-mode/hover states are expressed via DaisyUI variants rather than raw utility classes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/pages/login.vue`:
- Around line 300-309: In acceptQuerySession(), when supabase.auth.setSession
returns res.error, stop only logging to console and show a user-facing error
notification (e.g., use your app's toast/notify helper) that includes
res.error.message (or res.error) so the user knows Continue failed; ensure you
still set isLoading.value = false and return after showing the toast. Target the
error handling block that currently does console.error('Cannot set auth',
res.error) and replace/augment it with a call to the app's toast function
(passing a clear message and the error text) before returning.
- Around line 365-381: The confirmation prompt and button labels inside the
hasQuerySession block are hardcoded English; replace them with localized strings
using the app's i18n method (e.g., this.$t or useI18n/t) so the prompt text and
the three button labels ("Continue", "Cancel", and the paragraph) use
translation keys; update the template where hasQuerySession is rendered and
ensure acceptQuerySession and declineQuerySession still handle clicks while
referencing the new translation keys (and keep the isLoading condition
unchanged).
---
Nitpick comments:
In `@src/pages/login.vue`:
- Around line 370-379: Replace the raw <button> elements for the Continue and
decline actions with DaisyUI button components (use d-btn) so they follow
project conventions; locate the elements that call acceptQuerySession and
declineQuerySession and swap them to <d-btn> instances, transferring attributes
like type and click handlers (`@click`="acceptQuerySession" /
`@click`="declineQuerySession"), mapping visual styles to appropriate DaisyUI
props/classes (e.g., primary/outline or variant props) and ensuring
v-if="!isLoading" and any accessibility attributes remain; keep any custom
classes that are still needed only if they don’t conflict with d-btn styling and
ensure the dark-mode/hover states are expressed via DaisyUI variants rather than
raw utility classes.
| async function acceptQuerySession() { | ||
| isLoading.value = true | ||
| const res = await supabase.auth.setSession({ | ||
| access_token: querySessionAccessToken.value, | ||
| refresh_token: querySessionRefreshToken.value, | ||
| }) | ||
| if (res.error) { | ||
| console.error('Cannot set auth', res.error) | ||
| isLoading.value = false | ||
| return |
There was a problem hiding this comment.
Show a user-facing error when query-session setup fails.
On setSession failure, the flow only logs to console. Please surface a toast/error so users know why Continue did not work.
💡 Suggested patch
async function acceptQuerySession() {
isLoading.value = true
const res = await supabase.auth.setSession({
access_token: querySessionAccessToken.value,
refresh_token: querySessionRefreshToken.value,
})
if (res.error) {
console.error('Cannot set auth', res.error)
+ toast.error(t('invalid-auth'))
isLoading.value = false
return
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async function acceptQuerySession() { | |
| isLoading.value = true | |
| const res = await supabase.auth.setSession({ | |
| access_token: querySessionAccessToken.value, | |
| refresh_token: querySessionRefreshToken.value, | |
| }) | |
| if (res.error) { | |
| console.error('Cannot set auth', res.error) | |
| isLoading.value = false | |
| return | |
| async function acceptQuerySession() { | |
| isLoading.value = true | |
| const res = await supabase.auth.setSession({ | |
| access_token: querySessionAccessToken.value, | |
| refresh_token: querySessionRefreshToken.value, | |
| }) | |
| if (res.error) { | |
| console.error('Cannot set auth', res.error) | |
| toast.error(t('invalid-auth')) | |
| isLoading.value = false | |
| return |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/pages/login.vue` around lines 300 - 309, In acceptQuerySession(), when
supabase.auth.setSession returns res.error, stop only logging to console and
show a user-facing error notification (e.g., use your app's toast/notify helper)
that includes res.error.message (or res.error) so the user knows Continue
failed; ensure you still set isLoading.value = false and return after showing
the toast. Target the error handling block that currently does
console.error('Cannot set auth', res.error) and replace/augment it with a call
to the app's toast function (passing a clear message and the error text) before
returning.
| <div v-if="hasQuerySession" class="overflow-hidden bg-white rounded-md shadow-md dark:bg-slate-800"> | ||
| <div class="py-6 px-4 space-y-4 text-gray-500 sm:py-7 sm:px-8"> | ||
| <p class="text-sm"> | ||
| This link contains a login session. Continue to sign in with this session? | ||
| </p> | ||
| <button | ||
| v-if="!isLoading" type="button" data-test="accept-query-session" | ||
| class="inline-flex justify-center items-center py-4 px-4 w-full text-base font-semibold text-white rounded-md transition-all duration-200 hover:bg-blue-700 focus:bg-blue-700 bg-muted-blue-700 focus:outline-hidden" | ||
| @click="acceptQuerySession" | ||
| > | ||
| Continue | ||
| </button> | ||
| <button | ||
| v-if="!isLoading" type="button" class="inline-flex justify-center items-center py-4 px-4 w-full text-base font-semibold text-slate-700 rounded-md border border-slate-300 transition-all duration-200 hover:bg-slate-50 dark:text-slate-200 dark:border-slate-600 dark:hover:bg-slate-700" | ||
| @click="declineQuerySession" | ||
| > | ||
| Cancel |
There was a problem hiding this comment.
Localize the new confirmation copy.
The prompt and button labels are hardcoded English, which bypasses locale support in this page.
🌐 Suggested patch
- <p class="text-sm">
- This link contains a login session. Continue to sign in with this session?
- </p>
+ <p class="text-sm">
+ {{ t('query-session-confirmation') }}
+ </p>
...
- Continue
+ {{ t('continue') }}
...
- Cancel
+ {{ t('cancel') }}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div v-if="hasQuerySession" class="overflow-hidden bg-white rounded-md shadow-md dark:bg-slate-800"> | |
| <div class="py-6 px-4 space-y-4 text-gray-500 sm:py-7 sm:px-8"> | |
| <p class="text-sm"> | |
| This link contains a login session. Continue to sign in with this session? | |
| </p> | |
| <button | |
| v-if="!isLoading" type="button" data-test="accept-query-session" | |
| class="inline-flex justify-center items-center py-4 px-4 w-full text-base font-semibold text-white rounded-md transition-all duration-200 hover:bg-blue-700 focus:bg-blue-700 bg-muted-blue-700 focus:outline-hidden" | |
| @click="acceptQuerySession" | |
| > | |
| Continue | |
| </button> | |
| <button | |
| v-if="!isLoading" type="button" class="inline-flex justify-center items-center py-4 px-4 w-full text-base font-semibold text-slate-700 rounded-md border border-slate-300 transition-all duration-200 hover:bg-slate-50 dark:text-slate-200 dark:border-slate-600 dark:hover:bg-slate-700" | |
| @click="declineQuerySession" | |
| > | |
| Cancel | |
| <div v-if="hasQuerySession" class="overflow-hidden bg-white rounded-md shadow-md dark:bg-slate-800"> | |
| <div class="py-6 px-4 space-y-4 text-gray-500 sm:py-7 sm:px-8"> | |
| <p class="text-sm"> | |
| {{ t('query-session-confirmation') }} | |
| </p> | |
| <button | |
| v-if="!isLoading" type="button" data-test="accept-query-session" | |
| class="inline-flex justify-center items-center py-4 px-4 w-full text-base font-semibold text-white rounded-md transition-all duration-200 hover:bg-blue-700 focus:bg-blue-700 bg-muted-blue-700 focus:outline-hidden" | |
| `@click`="acceptQuerySession" | |
| > | |
| {{ t('continue') }} | |
| </button> | |
| <button | |
| v-if="!isLoading" type="button" class="inline-flex justify-center items-center py-4 px-4 w-full text-base font-semibold text-slate-700 rounded-md border border-slate-300 transition-all duration-200 hover:bg-slate-50 dark:text-slate-200 dark:border-slate-600 dark:hover:bg-slate-700" | |
| `@click`="declineQuerySession" | |
| > | |
| {{ t('cancel') }} | |
| </button> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/pages/login.vue` around lines 365 - 381, The confirmation prompt and
button labels inside the hasQuerySession block are hardcoded English; replace
them with localized strings using the app's i18n method (e.g., this.$t or
useI18n/t) so the prompt text and the three button labels ("Continue", "Cancel",
and the paragraph) use translation keys; update the template where
hasQuerySession is rendered and ensure acceptQuerySession and
declineQuerySession still handle clicks while referencing the new translation
keys (and keep the isLoading condition unchanged).
* fix(backend): use exact app_id match for preview lookup * fix(backend): preserve case-insensitive preview app lookup
…go/capgo into riderx/fix-login-url-tokens
|
* fix(security): revoke anon access to exist_app_v2 rpc * fix(build): restore TUS HEAD upload routing (#1664) * fix(build): handle tus HEAD upload route * fix(build): chain HEAD middleware correctly * chore(release): 12.116.2 * fix(security): protect replication endpoint (#1686) * fix(security): protect replication endpoint * fix(api): require replication endpoint internal api secret * fix(api): allow admin JWT access to replication endpoint * fix(frontend): use admin session only when no replication secret * fix(security): revoke PUBLIC execute on exist_app_v2 rpc * fix(security): revoke anon execute on exist_app_v2 rpc * fix(database): enforce org-scoped webhook rls (#1676) * fix: use exact app_id match for preview lookup (#1674) * fix(backend): use exact app_id match for preview lookup * fix(backend): preserve case-insensitive preview app lookup * chore(release): 12.116.3 * fix(security): revoke anon access to exist_app_v2 rpc * fix(security): revoke PUBLIC execute on exist_app_v2 rpc * fix(security): revoke anon execute on exist_app_v2 rpc * fix(frontend): require confirmation before URL login session (#1688) * fix(frontend): require confirmation for URL session login * fix(build): restore TUS HEAD upload routing (#1664) * fix(build): handle tus HEAD upload route * fix(build): chain HEAD middleware correctly * chore(release): 12.116.2 * fix(security): protect replication endpoint (#1686) * fix(security): protect replication endpoint * fix(api): require replication endpoint internal api secret * fix(api): allow admin JWT access to replication endpoint * fix(frontend): use admin session only when no replication secret * fix(frontend): retain tokens until query login succeeds * fix(database): enforce org-scoped webhook rls (#1676) * fix: use exact app_id match for preview lookup (#1674) * fix(backend): use exact app_id match for preview lookup * fix(backend): preserve case-insensitive preview app lookup * chore(release): 12.116.3 * fix(frontend): require confirmation for URL session login * fix(frontend): retain tokens until query login succeeds --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * chore(release): 12.116.4 * Riderx/fix email otp rpc reopen (#1693) * fix(security): restrict email otp verification rpc path * fix(security): also revoke otp rpc execute from public * fix(security): record email otp verification via service-side rpc * fix(security): harden email otp verification RPC usage * fix(db): drop legacy record_email_otp_verified overload * fix(frontend): delete replaced profile images from storage (#1683) * fix(frontend): delete replaced profile images from storage * fix(backend): clean stale unlinked user avatars * fix(build): restore TUS HEAD upload routing (#1664) * fix(build): handle tus HEAD upload route * fix(build): chain HEAD middleware correctly * chore(release): 12.116.2 * fix(security): protect replication endpoint (#1686) * fix(security): protect replication endpoint * fix(api): require replication endpoint internal api secret * fix(api): allow admin JWT access to replication endpoint * fix(frontend): use admin session only when no replication secret * fix: address sonar regex exec suggestions * fix(database): enforce org-scoped webhook rls (#1676) * fix: use exact app_id match for preview lookup (#1674) * fix(backend): use exact app_id match for preview lookup * fix(backend): preserve case-insensitive preview app lookup * chore(release): 12.116.3 * fix(frontend): delete replaced profile images from storage * fix(backend): clean stale unlinked user avatars * fix: address sonar regex exec suggestions --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: restrict find_apikey_by_value RPC to service role (#1672) * fix(security): restrict find_apikey_by_value to service role * fix(build): restore TUS HEAD upload routing (#1664) * fix(build): handle tus HEAD upload route * fix(build): chain HEAD middleware correctly * chore(release): 12.116.2 * fix(security): protect replication endpoint (#1686) * fix(security): protect replication endpoint * fix(api): require replication endpoint internal api secret * fix(api): allow admin JWT access to replication endpoint * fix(frontend): use admin session only when no replication secret * fix(database): enforce org-scoped webhook rls (#1676) * fix: use exact app_id match for preview lookup (#1674) * fix(backend): use exact app_id match for preview lookup * fix(backend): preserve case-insensitive preview app lookup * chore(release): 12.116.3 * fix(security): restrict find_apikey_by_value to service role --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: secure get_total_metrics rpc (#1671) * fix(db): harden get_total_metrics rpc auth * fix(db): qualify org_id and harden rpc role checks * fix(db): align get_total_metrics auth overloads * fix(db): harden get_total_metrics rpc auth * fix(db): qualify org_id and harden rpc role checks * fix(db): align get_total_metrics auth overloads * fix(db): harden get_total_metrics rpc auth * fix(db): qualify org_id and harden rpc role checks * fix(db): align get_total_metrics auth overloads * fix(backend): validate stripe redirect URLs (#1681) * fix(backend): validate stripe redirect URLs * fix(build): restore TUS HEAD upload routing (#1664) * fix(build): handle tus HEAD upload route * fix(build): chain HEAD middleware correctly * chore(release): 12.116.2 * fix(security): protect replication endpoint (#1686) * fix(security): protect replication endpoint * fix(api): require replication endpoint internal api secret * fix(api): allow admin JWT access to replication endpoint * fix(frontend): use admin session only when no replication secret * test(backend): add stripe redirect validation tests * test(backend): fix stripe redirect unit test env setup * fix(database): enforce org-scoped webhook rls (#1676) * fix: use exact app_id match for preview lookup (#1674) * fix(backend): use exact app_id match for preview lookup * fix(backend): preserve case-insensitive preview app lookup * chore(release): 12.116.3 * fix(backend): validate stripe redirect URLs * test(backend): add stripe redirect validation tests * test(backend): fix stripe redirect unit test env setup --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * feat(api): auto cleanup EXIF image metadata (#1673) * feat(api): auto cleanup image metadata on updates * fix: preserve content type when stripping image metadata * fix(security): restrict get_orgs_v6(userid uuid) access (#1677) * fix(security): restrict get_orgs_v6(uuid) execution to private roles * fix(build): restore TUS HEAD upload routing (#1664) * fix(build): handle tus HEAD upload route * fix(build): chain HEAD middleware correctly * chore(release): 12.116.2 * fix(security): protect replication endpoint (#1686) * fix(security): protect replication endpoint * fix(api): require replication endpoint internal api secret * fix(api): allow admin JWT access to replication endpoint * fix(frontend): use admin session only when no replication secret * fix(database): enforce org-scoped webhook rls (#1676) * fix: use exact app_id match for preview lookup (#1674) * fix(backend): use exact app_id match for preview lookup * fix(backend): preserve case-insensitive preview app lookup * chore(release): 12.116.3 * fix(security): restrict get_orgs_v6(uuid) execution to private roles --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix(security): revoke anon access to apikey oracle RPCs (#1670) * fix(security): restrict apikey oracle rpc execution * fix(build): restore TUS HEAD upload routing (#1664) * fix(build): handle tus HEAD upload route * fix(build): chain HEAD middleware correctly * chore(release): 12.116.2 * fix(security): protect replication endpoint (#1686) * fix(security): protect replication endpoint * fix(api): require replication endpoint internal api secret * fix(api): allow admin JWT access to replication endpoint * fix(frontend): use admin session only when no replication secret * fix: remove anon-backed get_user_id calls in private apikey flows * fix(database): enforce org-scoped webhook rls (#1676) * fix: use exact app_id match for preview lookup (#1674) * fix(backend): use exact app_id match for preview lookup * fix(backend): preserve case-insensitive preview app lookup * chore(release): 12.116.3 * fix(security): restrict apikey oracle rpc execution * fix: remove anon-backed get_user_id calls in private apikey flows --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix(security): require capgkey auth in exist_app_v2 * fix(api): block scoped apikey key creation (#1685) * fix(api): block scoped apikeys from creating keys * fix(build): restore TUS HEAD upload routing (#1664) * fix(build): handle tus HEAD upload route * fix(build): chain HEAD middleware correctly * chore(release): 12.116.2 * fix(security): protect replication endpoint (#1686) * fix(security): protect replication endpoint * fix(api): require replication endpoint internal api secret * fix(api): allow admin JWT access to replication endpoint * fix(frontend): use admin session only when no replication secret * fix(database): enforce org-scoped webhook rls (#1676) * test: fix apikey test lint violations * fix: use exact app_id match for preview lookup (#1674) * fix(backend): use exact app_id match for preview lookup * fix(backend): preserve case-insensitive preview app lookup * chore(release): 12.116.3 * fix(api): block scoped apikeys from creating keys * test: fix apikey test lint violations --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: restrict webhook secret access to admin-only (#1692) * fix(security): restrict webhook secret read access * fix(rls): restrict webhook reads to admins * fix(security): keep only apikey-based exist_app_v2 check * fix(security): require capgkey auth in exist_app_v2 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>



Summary (AI generated)
/loginquery tokens by requiring explicit user confirmation before setting a session.access_tokenandrefresh_tokenfrom the query string after they are detected.src/pages/login.vuefor query-token session sign-in.Motivation (AI generated)
The previous behavior authenticated automatically when
access_tokenandrefresh_tokenwere present in/loginURL query parameters, enabling login CSRF/session-fixation and accidental forced sign-ins from crafted links.Business Impact (AI generated)
Test Plan (AI generated)
bun lint src/pages/login.vue/login?access_token=...&refresh_token=...and verify the confirmation prompt appears before sign-in.access_tokenandrefresh_tokenafter page load./loginpath is unchanged when no query session tokens are present.Generated with AI
Summary by CodeRabbit