···77</script>
8899<script>
1010- // Minimal: initialize Clerk so it can keep session tokens refreshed
1110 (async () => {
1212- // wait until Clerk is present
1111+ const serverSignedIn = {{.ServerSignedIn}};
1212+ {{/* https://chatgpt.com/share/698a36fe-0834-8009-8f5e-d7dfcccae7c0
1313+ // Without this, you can get stuck in:
1414+ // 1) SSR renders logged-out (expired/missing __session)
1515+ // 2) Clerk loads and reports signed-in (it can rehydrate from client state)
1616+ // 3) You reload to let SSR see the fresh session
1717+ // 4) SSR *still* renders logged-out (cookie timing/scope, caching, stricter validation, dev quirks)
1818+ // 5) Clerk still reports signed-in -> reload again -> forever
1919+ //
2020+ // sessionStorage is per-tab and clears when the tab closes, which is ideal here.
2121+ */}}
2222+ const key = `clerk-ssr-sync-reloaded:${location.pathname}${location.search}`;
2323+2424+ // Wait for the Clerk global to exist, then initialize it.
1325 while (!window.Clerk?.load) await new Promise(r => setTimeout(r, 10));
1426 await Clerk.load();
15271616- // Optional: if you want to be extra defensive, force-refresh occasionally
1717- // (Clerk docs describe forcing refresh via skipCache on getToken)
1818- // setInterval(async () => {
1919- // if (Clerk.session) await Clerk.session.getToken({ skipCache: true });
2020- // }, 45_000);
2828+ const clerkSignedIn = !!Clerk.isSignedIn;
2929+3030+ {{/* The core fix:
3131+ // If SSR thought we're signed-out, but Clerk says we're signed-in,
3232+ // then Clerk likely just re-established a valid browser session *after* SSR ran.
3333+ // Do ONE reload so the *next* SSR request includes the refreshed __session cookie.
3434+ */}}
3535+ if (!serverSignedIn && clerkSignedIn && !sessionStorage.getItem(key)) {
3636+ sessionStorage.setItem(key, "1");
3737+ location.reload();
3838+ return;
3939+ }
2140 })();
2241</script>
2342{{end}}
+5
internal/users/server.go
···106106 http.Error(w, "unable to load account", http.StatusInternalServerError)
107107 return
108108 }
109109+ // if session expires this is less than optimal. We want to give them just the
110110+ // clerk_refresh and seee if they are then logged in. But we only want to do that once?
111111+ // TODO stick just show a sign in button on user page if no session
109112 http.Redirect(w, r, "/", http.StatusSeeOther)
110113 return
111114 }
···163166 Success bool
164167 FavoriteStoreName string
165168 Style seasons.Style
169169+ ServerSignedIn bool
166170 }{
167171 ClarityScript: templates.ClarityScript(),
168172 User: currentUser,
169173 Success: success,
170174 FavoriteStoreName: favoriteStoreName,
171175 Style: seasons.GetCurrentStyle(),
176176+ ServerSignedIn: true,
172177 }
173178 if err := s.userTmpl.Execute(w, data); err != nil {
174179 slog.ErrorContext(ctx, "user template execute error", "error", err)