最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Firebase does not authenticate when using next auth - Stack Overflow

programmeradmin0浏览0评论

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
    // .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.

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./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.

Share Improve this question edited Mar 28, 2022 at 22:07 jonrsharpe 122k30 gold badges267 silver badges474 bronze badges asked Mar 28, 2022 at 22:04 Diego González CruzDiego González Cruz 1681 silver badge10 bronze badges 6
  • I don't understand, if you're using next-auth why are you using firebase auth sdk? – mocherfaoui Commented Mar 28, 2022 at 23:35
  • Because I need to write firestore rules, as I'm setting custom claims and also, use other firebase services such as Storage. Does it make sense? How would you do it? – Diego González Cruz Commented Mar 29, 2022 at 0:48
  • does auth have a value before you pass it on? did you try to put onAuthStateChanged inside useEffect and see if it works? – mocherfaoui Commented Mar 29, 2022 at 1:41
  • nop, it does not have a value. I copied both inside useEffect (client) and outside it, (server), and my user is not recognized. – Diego González Cruz Commented Mar 29, 2022 at 16:23
  • @DiegoGonzálezCruz Hi. I've faced the same problem. To solve the problem, I made a customToken issue api that can be used after sign in from next-auth, and the frontend kept requesting customToken after 1 hour. I also added a rule that invalidates the issued customToken when sign out of next-auth, creating an example of linking next-auth and firebase authentication. I think this example has secured a similar level of security to the session, and I wonder what you think. I will organize it more neatly and leave an answer. – lowfront Commented May 6, 2022 at 15:31
 |  Show 1 more ment

2 Answers 2

Reset to default 5

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 };
}

Ok, so what I finally did is: as @esi're said, pass the customToken created with firebase auth, to the session:

async jwt({
  token,
  user,
  account,
  profile,
  isNewUser
}) {
  if (isNewUser || user) {
    const additionalClaims = {
      isStudent: true,
      isTeacher: false,
      isStaff: false,
      isAdmin: false
    }
    const customToken = await adminAuth.createCustomToken(token.sub, additionalClaims)
    console.log(customToken, '***customToken')
    token.customToken = customToken
  }
  return token
}

Then, in the session callback:

async session({
  session,
  token,
  user
}) {
  if (session ? .user) {
    session.user.id = token.sub
    session.customToken = token.customToken
  }
  return session
},

And finally, in the page where users are first redirected:

  const [user, setUser] = useState()

  useEffect(() => {

    if (status === "authenticated") {
      const loggedInUser = {
        userName: session.user.name,
        userEmail: session.user.email,
        userPhoto: session.user.image,
        userUID: session.user.id,
      }

      signInWithCustomToken(auth, session.customToken)


      dispatch(setActiveUser(loggedInUser))

    }
  }, [status])

  const handleLogOut = () => {
    dispatch(setUserLogOutState())
    logout()
    signOut({
      callbackUrl: '/'
    }) //TODO: goodbye page
  
  
  // Rest of jsx code when session is true

And that's it. Hope it works for someone else too.

Thanks !

发布评论

评论列表(0)

  1. 暂无评论