blitz-js / blitz

⚡️ The Missing Fullstack Toolkit for Next.js
https://Blitzjs.com
MIT License
13.68k stars 798 forks source link

App Router: `useAuthenticatedBlitzContext` with `redirectAuthenticatedTo` results in infinite loop #4246

Closed tordans closed 11 months ago

tordans commented 1 year ago

What is the problem?

I am trying to use useAuthenticatedBlitzContext to guard an admin area so only user.role==="ADMIN" is allowed to see the pages.

  await useAuthenticatedBlitzContext({
    role: ["ADMIN"],
    redirectTo: "/login",
    redirectAuthenticatedTo: "/admin",
  })

I have a test case in this app: https://github.com/FixMyBerlin/blitz-test/commit/b9c723e7f2d9bed18e838c34a618b0f240aa561f

Paste all your error logs here:

-

Paste all relevant code snippets here:

See https://github.com/FixMyBerlin/blitz-test

  1. Checkout
  2. npx blitz db seed

Test A:

  1. Create user on home page, user as ROLE=USER
  2. => http://localhost:3000/regions => Redirects to login, which makes sense

Test B:

  1. Create user on home page, user as ROLE=ADMIN
  2. => http://localhost:3000/regions => Stays on /regions but with infinite loop

What are detailed steps to reproduce this?

-

Run blitz -v and paste the output here:

% npx blitz -v
Blitz version: 2.0.0-beta.35 (local)
macOS Ventura | darwin-arm64 | Node: v19.2.0

 Package manager: npm

  System:
    OS: macOS 13.6
    CPU: (8) arm64 Apple M1
    Memory: 49.58 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 19.2.0 - ~/.nvm/versions/node/v19.2.0/bin/node
    Yarn: Not Found
    npm: 8.19.3 - ~/.nvm/versions/node/v19.2.0/bin/npm
  npmPackages:
    @blitzjs/auth: 2.0.0-beta.35 => 2.0.0-beta.35
    @blitzjs/next: 2.0.0-beta.35 => 2.0.0-beta.35
    @blitzjs/rpc: 2.0.0-beta.35 => 2.0.0-beta.35
    @prisma/client: 5.4.2 => 5.4.2
    blitz: 2.0.0-beta.35 => 2.0.0-beta.35
    next: 13.5.4 => 13.5.4
    prisma: 5.4.2 => 5.4.2
    react: 18.2.0 => 18.2.0
    react-dom: 18.2.0 => 18.2.0
    typescript: ^5.2.2 => 5.2.2

Please include below any other applicable logs and screenshots that show your problem:

No response

siddhsuresh commented 11 months ago

Hey @tordans that's weird, I will take a look today

chartgerink commented 11 months ago

Thanks for reporting this issue @tordans!

I'm having a similar issue, which is causing problems in production wherever we use Page.authenticate = { role: ["ROLE"] }. It ends up looping and redirecting (if a redirect is present). It worked fine before, and I'm not sure which version introduced this regression.

tordans commented 11 months ago

@chartgerink this issue is specifically for the app router and server components.

The solution Page.authenticate = { role: "ROLE" } does not work in the server components, which is why the new hook useAuthenticatedBlitzContext was introduced (which is what this issue is about). For client components in the app router the Page.authenticate should still work – at least since https://github.com/blitz-js/blitz/pull/4225 was fixed.

siddhsuresh commented 11 months ago

Hey @tordans I finally took a look today, I have opened a PR to use authorise the session that we would expect when we define the roles.

Regarding the infinite loop, I feel this is an error in the code you provided.

image

So what happens here is the following:

  1. You are logged in as ADMIN
  2. The auth utility checks whether a session user exists (a rudimentary check I now agree) and redirects to the url you provides, which is the same url you are on /regions.
  3. You are continuously redirected back to /regions.

So I would think if the page is to be protected only to ADMIN users, we can do it in the following way,

await useAuthenticatedBlitzContext({
    role: ["user"],
    redirectTo: "/auth/login",
    redirectAuthenticatedTo: (ctx) => {
      const role = ctx.session.$publicData.role
      if (role === "admin") {
        return "/admin"
      }
      return "/user"
    }
  })

Adding logic to automatically handle the session role in https://github.com/blitz-js/blitz/pull/4257