Skip to content

Firebase does not authenticate when using next auth

I’m using next-auth with firebase adapter. Everything is working fine in terms of saving users in database, but something is not working in terms of authentication.

import NextAuth from "next-auth"

import GoogleProvider from "next-auth/providers/google"
import { FirebaseAdapter } from "@next-auth/firebase-adapter"

import { db } from "../../../utils/firebase/firebase"
import * as firestoreFunctions from 'firebase/firestore'

import { adminAuth } from "../../../utils/firebase/firebaseAdmin"

import { getAuth, signInWithCustomToken } from "firebase/auth"

const auth = getAuth()

export default NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_ID,
      clientSecret: process.env.GOOGLE_SECRET,
      state: false,
    }),
  ],
  adapter: FirebaseAdapter({
    db: db,
    ...firestoreFunctions,
  }),
  callbacks: {
    async signIn({ user, account, profile, email, credentials }) {
      console.log(user, 'user')
      const customToken = await adminAuth.createCustomToken(user.id)
      const customSignIn = await signInWithCustomToken(auth, customToken)
      console.log(customSignIn, 'customSignIn')
      console.log(customSignIn.user, 'customSignIn.user')
      user = customSignIn.user
      console.log(user, 'user 2')
      return true
    },
    async redirect({ url, baseUrl }) {
      return baseUrl
    },
    async session({ session, user, token }) {
      if (session?.user) {
        session.user.id = token.sub
      }
      return session
    },
    async jwt({ token, user, account, profile, isNewUser }) {
      if (isNewUser) {
        const additionalClaims = {
          isStudent: true,
          isTeacher: false,
          isStaff: false,
          isAdmin: false
        }
        const customToken = await adminAuth.createCustomToken(token.sub, additionalClaims)
        const customSignIn = await signInWithCustomToken(auth, customToken)
        user = customSignIn.user

      }
      return token
    }

  },

  session: {
    strategy: 'jwt',
  },
})

My users can log in, but are not authenticated.

const auth = getAuth()

onAuthStateChanged(auth, (user) => {
  if (user) {
    // User is signed in, see docs for a list of available properties
    // https://firebase.google.com/docs/reference/js/firebase.User
    console.log('user')
    console.log(user)
    // ...
  } else {
    console.log('no user')
    // User is signed out
    // ...
  }
})

The Observer returns ‘no user’, but I’m logged in.

Answer

You’re not seeing a logged in user because the firebase auth is being done on the server side, and not the client side.

You should try passing the customToken to the session, then use it on the client side to sign in the user to firebase auth.

You would also want to wrap the useSession hook in a custom hook like below and use that instead of useSession.

const useFirebaseSession = () => {
  const session = useSession();
  const [status, setStatus] = useState(session.status);

  useEffect(() => {
    if (session && session.status === 'authenticated') {
      signInWithCustomToken(auth, session.customToken).then(() => {
        setStatus('authenticated');
      });
    }
  }, [session]);

  useEffect(() => {
    if(session.status !== 'authenticated') {
      setStatus(session.status)
    }
  }, [session.status]);

  return { data: session.data, status };
}