-
Notifications
You must be signed in to change notification settings - Fork 155
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Version
@nuxtjs/supabase: 2.0.3
nuxt: 4.2.1
Description
In v2, useSupabaseUser() now returns JWT claims via client.auth.getClaims(). The initialization happens in the page:start hook in supabase.client.ts, which causes the composable to return null in route middlewares on page refresh when using SPA mode (ssr: false).
This happens because Nuxt middlewares execute before page:start.
flowchart TD
subgraph timeline["⏱️ Execution Timeline"]
direction TB
A["1️⃣ Page Refresh"] --> B["2️⃣ supabase.client.ts setup"]
B --> C["3️⃣ Route Middleware runs"]
C --> D["4️⃣ useSupabaseUser() = null"]
D --> E["5️⃣ Redirect to /login 🚫"]
end
subgraph late["❌ Runs after middleware"]
F["6️⃣ page:start hook"]
F --> G["getClaims()"]
G --> H["User available ✅"]
end
E -.->|"too late"| F
Reproduction
nuxt.config.ts:
export default defineNuxtConfig({
ssr: false,
modules: ['@nuxtjs/supabase'],
supabase: { redirect: false }
})middleware/auth.ts:
export default defineNuxtRouteMiddleware(() => {
const user = useSupabaseUser()
console.log(user.value) // null on refresh, even if logged in
if (!user.value) return navigateTo('/login')
})Steps:
- Login successfully
- Navigate to a protected page (works ✅)
- Refresh the page → redirected to login ❌
Root cause
In supabase.client.js:
nuxtApp.hook("page:start", async () => {
const { data } = await client.auth.getClaims();
currentUser.value = data?.claims ?? null;
});Nuxt execution order: plugins → middlewares → page:start
So useSupabaseUser() is still null when middlewares run.
Suggested fix
Initialize claims directly in setup() instead of page:start:
async setup({ provide }) {
// ... client creation ...
const currentUser = useSupabaseUser();
// Initialize immediately (plugin has enforce: "pre")
const { data } = await client.auth.getClaims();
currentUser.value = data?.claims ?? null;
// Keep onAuthStateChange for subsequent updates
client.auth.onAuthStateChange(/* ... */);
}Current workaround
Use supabase.auth.getClaims() directly in middlewares:
export default defineNuxtRouteMiddleware(async () => {
const supabase = useSupabaseClient()
const { data } = await supabase.auth.getClaims()
if (!data?.claims) return navigateTo('/login')
})Shooteger, aaaaahaaaaa and yan-yanishevskymandalornl
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working