Auth with Sidebase Nuxt Auth
@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.
1. Before you start
You need @sidebase/nuxt-auth working with its NuxtAuthHandler, and the JWT secret for the module:
# 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:
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
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:
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.expiresis when Auth.js considers the session to end, so the token follows it.