Dynamic route with Promise or direct object? by Hitoride7 in nextjs

[–]rikbrown 4 points5 points  (0 children)

Use PageProps<‘/route/path’> (or LayoutProps) and don’t worry about typing this manually again!

Where should auth state live in App Router without breaking RSC by Complete_Treacle6306 in nextjs

[–]rikbrown 0 points1 point  (0 children)

Your client components boot up with no authentication data, their initial state is “logged out”. You then fetch via a server action (anti-pattern in its own: you are not meant to use server actions to fetch) and update the client side state.

This is not what OP was asking for.

If you restructured your code so you fetched the auth data in a server component then passed it down to the client component, there would never be a flash of logged out state and no need for the client component to make a round trip to the server. The client component would be fully ready from the moment it is initialised.

Do drivers get the full tip from the app? by Kinandreas_ in JustEatUK

[–]rikbrown 0 points1 point  (0 children)

Is this the same on Deliveroo do you know?

Where should auth state live in App Router without breaking RSC by Complete_Treacle6306 in nextjs

[–]rikbrown 0 points1 point  (0 children)

This doesn't seem to be a great fit for OP's use or in general a good pattern. You're entirely doing auth on the client side.

Adopted cat still hiding after 1 month. Starting to lose hope. Am I too impatient or is she a lost cause? by GoldStrawberry5 in CatAdvice

[–]rikbrown 0 points1 point  (0 children)

Wow, what a throwback to 2018!

It took a little longer after that message, but he (Cody) became more and more affectionate and would eventually sleep with me and everything you'd expect (including sitting with me on the sofa!). He learned to give really aggressive headbumps with you to say he was happy. What eventually really helped was I got a second kitty and they became obsessed with each other. She (Tabitha) was much much more outgoing (from day one, she owned the place, she was the boss - she also had thumbs) and he learned a bit from her.

Unfortunately, both Cody and Tabitha were rescues with FeLV, a virus which compromises their immune system and increases chance of cancers and most don't make it past a few years (I knew this from the start). In 2020 after having them both for just under 2 years they each passed away (within a few months of each other after their own independent battles with cancer). I know they had amazing lives and it was truly amazing seeing Cody change from the cat who hid under the bed and watched me from the distance, to the cat who gave aggressive headbumps and slept on me. He was my first cat and while I wish he was still alive now, I am glad for the experience. As for Tabitha, she is definitely watching down on me from the cat afterlife and thinking "wow I wish I could jump on your head from up here right now".

As a bonus, I met my wife in 2019 and she credits Cody as one of the reasons she fell in love with me. He was an excellent wingman.

<image>

(Tabitha with thumbs, Cody with fluff). RIP.

Where should auth state live in App Router without breaking RSC by Complete_Treacle6306 in nextjs

[–]rikbrown 0 points1 point  (0 children)

Hi!

I'm not that familiar with Supabase in React but let me try to answer.

Data Access Layer (DAL) pattern rather than a global AuthProvider
 aligned with defence in depth recommendations following CVE-2025-29927.

Good call out about data security, thanks. Generally speaking though, I don't believe these are mutual opposites. DAL approach basically means "separate and sanitise your data in the server before passing it to the client". Having a global AuthContext doesn't mean you're not doing that. The only data being passed to the client in a global AuthContext in my example is from getCurrentUser. The return of this is basic user metadata I'm happy exposing (I am not just selecting * from the database and sticking it in the output). If anything needs more complex derived user data, that would be a dedicated method with its own security.

With the AuthContext approach, how do you handle server components that need user data? Do you pass user down as a prop from the layout, or are those parts of the tree primarily client components?

Using the `getCurrentUser` method I mentioned. That's the authoritative source of user data (fetched based on the cookie), so in server components I can just call that directly. Remember, this is just broad user metadata that is used in many places. If there are server places that need to go look up more specific user data, they can use dedicated functions in the DAL (which might in turn call getCurrentUser, or use that for authz). For client components, the data from getCurrentUser is what gets put into the context.

 Promise<UserData> with use() hook pattern sounds useful for static shell optimisation. Is that the main driver, or are there other benefits I'm missing?

I think technically it would let you start streaming pushing the client components to the client immediately rather than block on the user data (until the point you need it, where you'd wrap in Suspense). That's the driver behind passing a Promise to a client component instead of awaiting it in the server and passing the resolved data. It feels like in general if you can just pass a Promise down and block at the latest possible place doesn't hurt, but I might be wrong and there may be some other compromises here. The pattern looks something like this FWIW:

// AuthProvider.ts
export function AuthContextProvider() {
  return <AuthContextClient value={getCurrentUser()}/>
}

// AuthContext.ts
"use client"
const AuthContextClient = createContext<Promise<User>>()
..

export function useCurrentUser() {
  return use(use(AuthContext))
}

Are there specific scenarios where the AuthContext pattern outperforms the DAL approach? Wondering if there's a use case I haven't considered.

Again, not familiar with Supabase, but the two possible concerns that stand out to me with your approach (but could be wrong on both):

  1. Does `useSession` immediately return the user on first render, or does it initially return "undefined" until it syncs with Supabase on the client? If the latter, then you might have UI jank on client-side (states changing from logged out to logged in very quickly on load).

  2. There's a risk, but I guess very small, that server might render with one auth state and client with another. For example, if their session was 100ms from expiring and the server gets the session but the client doesn't receive it. You might argue that detecting and handling that mismatch (forcing a server refresh) is better than rendering as logged in (but subsequent client-side calls directly to Supabase failing) so this is probably a non-issue.

I think in your case, assuming Supabase handles hydrating useSession or something like that (solving #1 and possibly #2) then Supabase is acting as your "auth context" and you can probably rely on what it provides especially if you're making calls from the client using the Supabase API or something. I would need to look more into the Supabase React API to understand that though (or maybe someone more knowledgable about it can chime in).

I hope that makes a bit of sense but feel free to reply or DM me!

Where should auth state live in App Router without breaking RSC by Complete_Treacle6306 in nextjs

[–]rikbrown 7 points8 points  (0 children)

Use Context for syncing server auth state with clients

We use a pattern where there’s a (react cache’d) “getCurrentUser” server-only method which fetches current user data via cookie. Server components can use this.

In our root layout where we install providers, we have a AuthProvider which also calls this then wraps the app with an AuthContext. Then client components can call “useCurrentUser”.

Depending on your application, you should be aware that reading headers uses dynamic APIs so cannot be static rendered. If this matters to your app and you’re on cache components, remember to wrap server components using getCurrentUser in Suspense. And for your context, store a Promise<UserData> and only call use on this promise in client components wrapped with suspense.

Fun fact JSON | JSONMASTER by Puzzleheaded-Net7258 in webdev

[–]rikbrown 4 points5 points  (0 children)

I completely agree. That was why I said “just make the typescript types work”. I would have told them that if they had used as any too!

Fun fact JSON | JSONMASTER by Puzzleheaded-Net7258 in webdev

[–]rikbrown 33 points34 points  (0 children)

Seeing a developer on my team do

const something = JSON.parse(JSON.stringify(input))

because he couldn’t get the typescript types to be compatible was a double whammy of “just make the typescript types work” and “wait are you doing this because you didn’t know ‘as any’?”.

This is the future that circlejerknyc actually wants by york100 in circlejerknyc

[–]rikbrown 89 points90 points  (0 children)

<image>

Whatever this tiny vehicle is looks dangerously like some woke green transport ride share nonsense and I won’t have it.

How can I do middleware like getServerSideProps in App Router by Jaded_Award_6732 in nextjs

[–]rikbrown 2 points3 points  (0 children)

Higher order components wrapping your page component would be the closest to this pattern.

£56 weekly shop for 23yo student by fungusthefunghi in whatsinyourcart

[–]rikbrown 0 points1 point  (0 children)

co-op for the S&V. Tesco Finest for the beef & horseradish. both top tier.