Playbooks

Auth with Sidebase Nuxt Auth

Keep a PostgREST token in step with your Auth.js session.

@sidebase/nuxt-auth wraps Auth.js, which owns the sign-in endpoints. So you derive the PostgREST token from the session: a server utility does it, a middleware keeps it fresh on every request, and a route lets the browser sync when it signs in without a redirect.

This guide was checked against the package's published types, not run end to end. Set up the library itself with its docs.

1. Before you start

You need @sidebase/nuxt-auth working with its NuxtAuthHandler, and the JWT secret for the module:

.env
# Must equal PostgREST's jwt-secret (PGRST_JWT_SECRET)
NUXT_POSTGREST_JWT_SECRET=replace-with-a-secret-of-at-least-32-characters

2. Turn the session into a token

The session's user has no id by default, so read the user id from the decoded Auth.js token (sub) and the expiry from the session:

server/utils/postgrest-token.ts
import type { H3Event } from 'h3'
import { getServerSession, getToken } from '#auth'

/** Make the PostgREST token cookie match the current Auth.js session. */
export async function syncPostgrestToken(event: H3Event) {
  const session = await getServerSession(event)
  const token = await getToken({ event })

  if (!session || !token?.sub) {
    clearPostgrestToken(event)
    return
  }

  setPostgrestToken(
    event,
    await mintJwt(
      { role: 'authenticated', sub: token.sub },
      { expiresAt: new Date(session.expires) },
    ),
  )
}

getServerSession returns the session or null, and session.expires is an ISO date string.

3. Run it on every request

server/middleware/postgrest-token.ts
export default defineEventHandler(async (event) => {
  // Auth.js's own endpoints don't need a token
  if (event.path.startsWith('/api/auth')) return

  await syncPostgrestToken(event)
})

The cookie follows the session on every page and API request, including when Auth.js extends it, and it clears when the session ends.

4. After a sign-in that doesn't redirect

The default sign-in flow redirects, which loads a page from your server, so the middleware already sets the token. If you sign in without a redirect, the browser has to ask for the token:

server/api/postgrest-token.post.ts
export default defineEventHandler(async (event) => {
  await syncPostgrestToken(event)
  return { ok: true }
})
await $fetch('/api/postgrest-token', { method: 'POST' })
await refreshNuxtData() // re-run queries, now as the user

Call it after signing out as well: it finds no session and clears the cookie.

5. Query as the user

const { data } = await usePostgrest().from('todos').select('*')

Your RLS policies can read the sub claim, which is the Auth.js user id.

Things to know

  • Revocation. A token already in the browser keeps working until its exp, even after the session is gone. The middleware removes it on that user's next request.
  • Session strategy. With the default JWT strategy, session.expires is when Auth.js considers the session to end, so the token follows it.
Copyright © 2026