sidebase / nuxt-auth

Authentication built for Nuxt 3! Easily add authentication via OAuth providers, credentials or Email Magic URLs!
https://auth.sidebase.io
MIT License
1.25k stars 162 forks source link

Role is only accessible from getServerSession on redirect and then the value is null #866

Closed adamcole123 closed 1 month ago

adamcole123 commented 1 month ago

Environment

Reproduction

/// middleware/auth.ts
import { getServerSession } from '#auth'
import pageRoles from '~/pageRoles';

export default eventHandler(async (event) => {
    const session = await getServerSession(event)
    if (session === undefined) {
        throw createError({ 
            statusMessage: 'Unauthenticated', 
            statusCode: 403 
        })
    }

    pageRoles.forEach(pageRole => {
        if(event.path === pageRole.page){
            if(!pageRole.role.includes(session!.user.role)){
                throw createError({ 
                    statusMessage: 'Must be admin', 
                    statusCode: 403
                })
            }
        }
    });
})
/// [...].ts
import { NuxtAuthHandler } from '#auth'
import { PrismaAdapter } from '@next-auth/prisma-adapter'
import GoogleProvider from 'next-auth/providers/google'
import prisma from '~/server/database/client'

export default NuxtAuthHandler({
    // A secret string you define, to ensure correct encryption
    secret: process.env.APPLICATION_SECRET,
    adapter: PrismaAdapter(prisma as any),
    providers: [
        // @ts-expect-error Use .default here for it to work during SSR.
        GoogleProvider.default({
            clientId: process.env.GOOGLE_CLIENT_ID,
            clientSecret: process.env.GOOGLE_CLIENT_SECRET,
            allowDangerousEmailAccountLinking: true,
        })
    ],
    // pages: {
    //  signIn: '/auth/signIn',
    //  signOut: '/auth/signOut',
    //  error: '/auth/error',
    //  verifyRequest: '/auth/verify-request',
    //  newUser: '/auth/new-user'
    // },
    callbacks: {
        jwt({ token, account, user }) {
            if (account) {
                token.accessToken = account.access_token
                token.sub = user.id
            }
            return token
        },
        async session({ session, token }) {
            // I skipped the line below coz it gave me a TypeError
            // session.accessToken = token.accessToken;
            session!.user!.id = token.sub;

            const additionalUserData = await $fetch(`/api/user/${token.email}`)

            return {
                ...session,
                role: additionalUserData.role
            }

        },
    },
    session: {
        strategy: 'jwt',
    },
})
/// pageRoles.ts
import type { PageRole } from "./types/PageRole";

export default [
    {
        page: '/admin/dashboard',
        role: 'admin'
    }
] as unknown as PageRole[]

You can see in the above that in my middleware im trying to test if the user has the right role to access the page that they want to access, then throwing an error if they don't have the right role.

Describe the bug

When I try to access /admin/dashboard using a button on the page then I get the expected behaviour. But then if i refresh, or type the URL from a fresh tab, i get the error. Even if the user has the right role.

It looks like it can get the data initially and then it just has null for the session data

Additional context

No response

Logs

Here's what I see when I refresh the page and console log the session in the middleware:

{ user:
   { name: [omitted,
     email: [omitted],
     image: [omitted],
  role: 'admin' }
null
null
null
null
null
null