Skip to content

Admin page post-login redirect#33

Open
evan-taylor wants to merge 1 commit intomainfrom
cursor/admin-page-post-login-redirect-8997
Open

Admin page post-login redirect#33
evan-taylor wants to merge 1 commit intomainfrom
cursor/admin-page-post-login-redirect-8997

Conversation

@evan-taylor
Copy link
Copy Markdown
Owner

@evan-taylor evan-taylor commented Mar 7, 2026

Fix post-login redirect to return to the originally requested page instead of always going to home.

Previously, after successful authentication, users were always redirected to the home page (/) even if they had attempted to access a protected route like /admin. This PR ensures that after signing in, users are returned to the page they initially intended to visit.


Slack Thread

Open in Web Open in Cursor 

Greptile Summary

This PR fixes the post-login redirect so users are returned to their originally requested page rather than always landing on /. The app/admin/page.tsx client-side guard and app/signin/page.tsx sign-in handler are updated correctly, but proxy.ts has an incomplete implementation that leaves a gap for middleware-protected routes.

  • app/admin/page.tsx: Adds an authLoading guard to prevent premature redirects, builds the ?redirect= query param from window.location, and uses router.replace (correct choice to avoid polluting browser history).
  • app/signin/page.tsx: Reads and validates the redirect search param via getSafeRedirectPath before calling router.push after both sign-in and sign-up — correctly restores the intended destination.
  • proxy.ts ⚠️: When an authenticated user re-visits /signin the middleware correctly honors the redirect param. However, when the middleware itself redirects unauthenticated users away from routes like /board or /dashboard, the original path is discarded — those users still land on / after signing in, so the feature is effectively broken for all middleware-enforced routes.
  • Code duplication: getSafeRedirectPath is defined identically in both proxy.ts and app/signin/page.tsx; a shared utility would reduce maintenance risk.
  • Minor security gap: Both copies of getSafeRedirectPath block //-prefixed paths but do not guard against /\-prefixed paths, which some runtimes normalize to // and could enable an open-redirect bypass.

Confidence Score: 3/5

  • PR is safe to merge for the admin page flow, but the redirect feature is incomplete for all middleware-protected routes.
  • The admin-page redirect works end-to-end and there are no regressions. However, the core fix doesn't extend to routes guarded by the middleware (/board, /dashboard, /server), meaning the PR's stated goal is only partially achieved. The duplicated validation function and the minor /\ open-redirect gap add maintenance and security considerations that should be addressed before a full rollout.
  • proxy.ts — the unauthenticated redirect to /signin at line 41 needs the ?redirect= param added to complete the feature for middleware-protected routes.

Important Files Changed

Filename Overview
proxy.ts Adds getSafeRedirectPath helper and honours the redirect query param when an authenticated user re-visits /signin, but omits the redirect param when the middleware itself redirects unauthenticated users away from protected routes — making the feature incomplete for /board, /dashboard, and /server.
app/admin/page.tsx Adds an authLoading guard before the unauthenticated redirect and constructs the ?redirect= query param correctly using window.location.pathname + window.location.search; also switches to router.replace to avoid polluting browser history.
app/signin/page.tsx Reads the redirect search param and validates it through getSafeRedirectPath before using it in router.push after both sign-in and sign-up flows; function is duplicated from proxy.ts and has a minor /\ bypass gap.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User navigates to protected page] --> B{Middleware-protected route?}
    B -- Yes, e.g. /board --> C{Authenticated?}
    C -- No --> D[Redirect to /signin\nno redirect param added]
    D --> E[User signs in]
    E --> F[router.push to HOME\noriginal destination lost]
    C -- Yes --> G[Allow access]

    B -- No, e.g. /admin --> H[Page renders client-side]
    H --> I{authLoading done?}
    I -- No --> J[Show loader]
    I -- Yes --> K{currentUser null?}
    K -- Yes --> L[router.replace to /signin\nwith redirect param]
    L --> M[User signs in]
    M --> N[router.push to original page\ncorrect destination restored]
    K -- No --> O[Show page content]
Loading

Comments Outside Diff (1)

  1. proxy.ts, line 40-42 (link)

    Missing redirect param for middleware-protected routes

    The middleware correctly reads and forwards the redirect query param when an already-authenticated user visits /signin (lines 34–38). However, when it redirects unauthenticated users away from protected routes (/server, /board(.*), /dashboard(.*)), the destination path is not preserved. Users hitting those routes will still land on / after sign-in, making the feature incomplete for middleware-enforced pages.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: proxy.ts
    Line: 40-42
    
    Comment:
    **Missing `redirect` param for middleware-protected routes**
    
    The middleware correctly reads and forwards the `redirect` query param when an already-authenticated user visits `/signin` (lines 34–38). However, when it redirects *unauthenticated* users away from protected routes (`/server`, `/board(.*)`, `/dashboard(.*)`), the destination path is not preserved. Users hitting those routes will still land on `/` after sign-in, making the feature incomplete for middleware-enforced pages.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Cursor

Fix All in Cursor

Last reviewed commit: b5d9cd3

Greptile also left 2 inline comments on this PR.

Co-authored-by: Evan Taylor <evan-taylor@users.noreply.github.com>
@cursor
Copy link
Copy Markdown

cursor bot commented Mar 7, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cprcc Ready Ready Preview, Comment Mar 7, 2026 2:15am

@evan-taylor evan-taylor marked this pull request as ready for review March 7, 2026 02:16
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files

Comment on lines +10 to +24
const getSafeRedirectPath = (path: string | null) => {
if (!path?.startsWith("/")) {
return HOME_PATH;
}

if (path.startsWith("//")) {
return HOME_PATH;
}

if (path === SIGN_IN_PATH || path.startsWith(`${SIGN_IN_PATH}?`)) {
return HOME_PATH;
}

return path;
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Duplicated getSafeRedirectPath utility

getSafeRedirectPath is defined identically in both proxy.ts and app/signin/page.tsx. If the validation logic ever needs to change (e.g., to patch a security bypass), it must be updated in both places, which is easy to miss. Consider extracting it to a shared utility such as lib/redirect.ts and importing it from both call sites.

Prompt To Fix With AI
This is a comment left during a code review.
Path: proxy.ts
Line: 10-24

Comment:
**Duplicated `getSafeRedirectPath` utility**

`getSafeRedirectPath` is defined identically in both `proxy.ts` and `app/signin/page.tsx`. If the validation logic ever needs to change (e.g., to patch a security bypass), it must be updated in both places, which is easy to miss. Consider extracting it to a shared utility such as `lib/redirect.ts` and importing it from both call sites.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Cursor

Comment on lines +14 to +27
const getSafeRedirectPath = (path: string | null) => {
if (!path?.startsWith("/")) {
return HOME_PATH;
}

if (path.startsWith("//")) {
return HOME_PATH;
}

if (path === SIGN_IN_PATH || path.startsWith(`${SIGN_IN_PATH}?`)) {
return HOME_PATH;
}

return path;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Potential open redirect via /\ bypass

The guard blocks // (protocol-relative URLs) but does not catch /\ followed by a domain. Some browsers and HTTP clients normalize a backslash to a forward slash, so a crafted query param like ?redirect=%2F%5Cevil.com could decode to /\evil.com, pass all three checks, and potentially redirect to an external host depending on the runtime's URL normalization.

Adding an explicit check for path.startsWith("/\\") (or, more robustly, parsing the path with new URL(path, window.location.origin) and verifying the origin matches) would close this gap:

if (path.startsWith("/\\")) {
  return HOME_PATH;
}

The same applies to the identical function in proxy.ts.

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/signin/page.tsx
Line: 14-27

Comment:
**Potential open redirect via `/\` bypass**

The guard blocks `//` (protocol-relative URLs) but does not catch `/\` followed by a domain. Some browsers and HTTP clients normalize a backslash to a forward slash, so a crafted query param like `?redirect=%2F%5Cevil.com` could decode to `/\evil.com`, pass all three checks, and potentially redirect to an external host depending on the runtime's URL normalization.

Adding an explicit check for `path.startsWith("/\\")` (or, more robustly, parsing the path with `new URL(path, window.location.origin)` and verifying the `origin` matches) would close this gap:

```
if (path.startsWith("/\\")) {
  return HOME_PATH;
}
```

The same applies to the identical function in `proxy.ts`.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Cursor

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.

2 participants