nextauthjs / next-auth

Authentication for the Web.
https://authjs.dev
ISC License
25.12k stars 3.56k forks source link

My NextAuth auth system does not create users in firebase(Authentication as Firestore). #10280

Open GroophyLifefor opened 8 months ago

GroophyLifefor commented 8 months ago

Adapter type

@auth/firebase-adapter

Environment

System:
OS: Windows 11 10.0.22621
CPU: (12) x64 11th Gen Intel(R) Core(TM) i5-11400H @ 2.70GHz
Memory: 1.04 GB / 7.75 GB
Binaries:
Node: 21.6.1 - C:\Program Files\
odejs\
ode.EXE
npm: 10.4.0 - C:\Program Files\
odejs\
pm.CMD
Browsers:
Edge: Chromium (122.0.2365.80)
Internet Explorer: 11.0.22621.1
npmPackages:
@auth/firebase-adapter: ^1.5.0 => 1.5.0
next: 14.1.3 => 14.1.3
next-auth: ^4.24.7 => 4.24.7
react: ^18 => 18.2.0

Reproduction URL

https://github.com/GroophyLifefor/reproduction

Describe the issue

Please READ HERE

Scenario: I am a developer, I wanted to use NextAuth, I tried to connect Firebase, "it was working on my computer" :D. I realized that it was not working in production, I tried to solve it in different ways but I could not solve it

First stage - traditional

the auth part of my project is divided into two parts.

/src/app/api/auth/[...nextauth]/route.ts  
/src/app/options.ts  
route.ts ```ts import { authOptions } from '@/app/options'; import NextAuth from 'next-auth'; const handler = NextAuth(authOptions); export { handler as GET, handler as POST }; ```
options.ts ```ts import { NextAuthOptions } from "next-auth"; import GoogleProvider from "next-auth/providers/google"; import FirebaseAdapter from "@next-auth/firebase-adapter"; import { Adapter } from "next-auth/adapters"; export const authOptions: NextAuthOptions = { providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }), ], adapter: FirebaseAdapter as Adapter, secret: "http://127.0.0.1:3000/api/auth", }; ```

The problem I'm having here is, first of all, I get an error like this when compiling.

⚠ ./src/app/options.ts
Attempted import error: '@next-auth/firebase-adapter' does not contain a default export (imported as 'FirebaseAdapter').

This is like a warning but it says error in Vercel deployment and CI/CD stops.


and when I log in, it doesn't register in firebase.

image
image

But it's the only one I can log in, so it's a huge plus. that's is why this way first stage

Second Stage - Carriage

route.ts ```ts import { authOptions } from '@/app/options'; import NextAuth from 'next-auth'; const handler = NextAuth(authOptions); export { handler as GET, handler as POST }; ```
options.ts - (M)odified ```ts import { NextAuthOptions } from "next-auth"; import GoogleProvider from "next-auth/providers/google"; import { FirebaseAdapterConfig, FirestoreAdapter } from "@next-auth/firebase-adapter"; import { Adapter } from "next-auth/adapters"; import { connectToDatabaseNotAsync } from "@/lib/firestore"; const { db } = connectToDatabaseNotAsync(); import { getFirestore, collection, query, getDocs, where, limit, doc, getDoc, addDoc, updateDoc, deleteDoc, } from "firebase/firestore"; const firebaseClient = { db, collection, query, getDocs, where, limit, doc, getDoc, addDoc, updateDoc, deleteDoc, }; export const authOptions: NextAuthOptions = { providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }), ], adapter: FirestoreAdapter(firebaseClient as FirebaseAdapterConfig) as Adapter, secret: "http://127.0.0.1:3000/api/auth", }; ```

At this stage I no longer get the import error in the build phase, but I get another error that runtime error.

error ```ts bla bla 'Cause'... 14538 more characters, name: 'Error' } [next-auth][error][SESSION_ERROR] https://next-auth.js.org/errors#session_error Unable to detect a Project Id in the current environment. To learn more about authentication and Google APIs, visit: https://cloud.google.com/docs/authentication/getting-started Error: Unable to detect a Project Id in the current environment. bla bla (very long) (THIS THREE TIMES COMES) at async Server.requestListener (C:\\Users\\Groop\\Desktop\\Desktop\\Code\\javascript\\commentinV2\\commentin\ ode_modules\ ext\\dist\\server\\lib\\start-server.js:140:13) { name: 'GetSessionAndUserError', code: undefined } [next-auth][error][SESSION_ERROR] https://next-auth.js.org/errors#session_error Unable to detect a Project Id in the current environment. bla bla at async Server.requestListener (C:\\Users\\Groop\\Desktop\\Desktop\\Code\\javascript\\commentinV2\\commentin\ ode_modules\ ext\\dist\\server\\lib\\start-server.js:140:13) { name: 'GetUserByAccountError', code: undefined } ```

also auth too not working!

image

Third Stage - With over-research and deep found ways

route.ts ```ts import { authOptions } from '@/app/options'; import NextAuth from 'next-auth'; const handler = NextAuth(authOptions); export { handler as GET, handler as POST }; ```
options.ts - (M)odified ```ts import { FirestoreAdapter } from "@auth/firebase-adapter"; import { cert } from "firebase-admin/app"; import { NextAuthOptions } from "next-auth" import { Adapter } from "next-auth/adapters"; import GoogleProvider from "next-auth/providers/google"; import * as admin from 'firebase-admin' export const authOptions: NextAuthOptions = { // Configure one or more authentication providers // https://next-auth.js.org/providers providers: [ GoogleProvider({ clientId: process.env.GOOGLE_ID as string, clientSecret: process.env.GOOGLE_SECRET as string, }), ], // see https://authjs.dev/reference/adapter/firebase#usage // adapter: FirestoreAdapter({}), adapter: FirestoreAdapter({ credential: cert({ projectId: process.env.FIREBASE_PROJECT_ID, clientEmail: process.env.FIREBASE_CLIENT_EMAIL, privateKey: process.env.FIREBASE_PRIVATE_KEY, }), }) as Adapter, callbacks: { async session({ session, token }) { // ... if (token && token.uid) { const firebaseToken = await admin.auth().createCustomToken(token.uid as string) // @ts-ignore session.firebaseToken = firebaseToken } return session }, }, session: { strategy: 'jwt', }, } ```

Previously I was only initializing firebase, I was doing it in a file called firestore.ts, I didn't feel the need to add it because there is nothing magical, it just initializes plain.

I imported firebase-admin as import * as admin from 'firebase-admin'
in this case take care as admin so It's not confict with firebase-app initialize

admin.initializeApp({  
    credential: admin.credential.cert({  
    projectId: process.env.FIREBASE_PROJECT_ID,  
    clientEmail: process.env.FIREBASE_CLIENT_EMAIL,  
    privateKey: process.env.FIREBASE_PRIVATE_KEY,  
  }),  
})  

and finally I have made some changes to my home page,

page.tsx

import { getAuth, signInWithCustomToken } from "firebase/auth";  
import { connectToDatabase } from "@/lib/firestore";  
import { FirebaseApp } from "firebase/app";  

export default function Home() {  
  const { data: session } = useSession();  
  const [auth, setAuth] = useState<FirebaseApp | null>(null);  

  async function initAuth() {  
    const { app } = await connectToDatabase();  
    // @ts-ignore  
    setAuth(getAuth(app));  
  }  

  async function syncFirebaseAuth() {  
      // @ts-ignore  
      if (session && session.firebaseToken) {  
    try {  
      // @ts-ignore  
      await signInWithCustomToken(auth, session.firebaseToken);  
    } catch (error) {  
      console.error("Error signing in with custom token:", error);  
    }  
    } else {  
      // @ts-ignore  
      auth.signOut();  
    }  
  }  

  useEffect(() => {D  
  syncFirebaseAuth();  
  }, [session]);  

  ...  
}  

also mine env was
image

so provider and adapter values was okey, but still error

error ```ts bla bla [next-auth][error][adapter_error_getUserByAccount] https://next-auth.js.org/errors#adapter_error_getuserbyaccount Unable to detect a Project Id in the current environment. To learn more about authentication and Google APIs, visit: https://cloud.google.com/docs/authentication/getting-started { message: 'Unable to detect a Project Id in the current environment. \ ' + 'To learn more about authentication and Google APIs, visit: \ ' + 'https://cloud.google.com/docs/authentication/getting-started', stack: 'Error: Unable to detect a Project Id in the current environment. \ ' + 'To learn more about authentication and Google APIs, visit: \ ' + 'https://cloud.google.com/docs/authentication/getting-started\ ' + ' at GoogleAuth.findAndCacheProjectId (C:\\\\Users\\\\Groop\\\\Desktop\\\\Desktop\\\\Code\\\\javascript\\\\commentinV2\\\\commentin\\\ ode_modules\\\\google-auth-library\\\\build\\\\src\\\\auth\\\\googleauth.js:124:19)\ ' + ' at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\ ' + bla bla (very long) 'Cause'... 24114 more characters, name: 'Error' } [next-auth][error][OAUTH_CALLBACK_HANDLER_ERROR] bla bla 2\\commentin\ ode_modules\ ext\\dist\\server\\lib\\router-server.js:377:13) at async Server.requestListener (C:\\Users\\Groop\\Desktop\\Desktop\\Code\\javascript\\commentinV2\\commentin\ ode_modules\ ext\\dist\\server\\lib\\start-server.js:140:13) { name: 'GetUserByAccountError', code: undefined } ```

How to reproduce

Actually I couldn't get rid of these errors no matter what I did, if you try to setup it in a normal way you may get these errors.

Expected behavior

error-free, bug-free life

erenkulaksiz commented 8 months ago

Don't use NextAuth on App router. Atleast that is what i came to conclusion via my experience.

GroophyLifefor commented 8 months ago

Don't use NextAuth on App router. Atleast that is what i came to conclusion via my experience.

Is it fixing when I just don't use App Router? Really?

GroophyLifefor commented 8 months ago

Not even a return for how many days, great team, excellent project, The last praises I said is not serious.

erenkulaksiz commented 8 months ago

next-auth has 250 active issues and nearly 90 pr's. Just dont use next-auth @GroophyLifefor

NickFoden commented 7 months ago

Hi GroophyLifefor,

(First > I am not a maintainer just am browsing the adapter implementations and saw your issue here)

I think you need to change how you import your env vars.

These packages are for 2 different environments here.

firebase more for the client side firebase-admin only for the server side

To use the client side library you have to follow next.js rules for environment variables.

const firebaseConfig = JSON.parse(process.env.FIREBASE_CONFIG || "");

-https://github.com/GroophyLifefor/reproduction/blob/5846491bbf84dc504f9eacb1412b3469826e2998/src/lib/firestore.ts#L12

Suggest for your client side file and firebase import /initialization to change to a config more similar to

const config = {
  apiKey: process.env.NEXT_PUBLIC_FB_API_KEY,
  appId: process.env.NEXT_PUBLIC_FB_APP_ID,
  authDomain: process.env.NEXT_PUBLIC_FB_AUTH_DOMAIN,
  databaseURL: process.env.NEXT_PUBLIC_FB_DATABASE_URL,
  projectId: process.env.NEXT_PUBLIC_FB_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FB_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FB_MESSAGING_SENDER_ID,
  measurementId: process.env.NEXT_PUBLIC_FB_MEASUREMENT_ID,
};

const app = initializeApp(config);

See the next.js repo for their examples and how they explicitly differentiate the client side firebase in its own file etc

And then I understand can be frustrating when coding, but also can consider this project is open source and lot of adapters and surface area to maintain. We can all try and be more considerate of people giving their valuable free time to help the web run smoothly.

If still stuck send me a message and I can help you. I use and have been using the firebase adapter with firebase-admin 11 in next.js projects and working well.

GroophyLifefor commented 7 months ago

@NickFoden Thank you for your reply and I remember trying this, unfortunately I can't make new attempts to fix because I have removed next-auth from the project and never to use this curse again.

I hope the project gets what it deserves, it's unbelievable that a package supported by Vercel is so bad

note: I use Google's apis and it's easier because at least it works.

FabioDainese commented 7 months ago

In case someone else if facing the same issue, in order to authenticate the user also on the Firebase Authentication dashboard, you just need to use createCustomToken and signInWithCustomToken Firebase functions.

For the longer answer, I'll leave you with this exhaustive example here on StackOverflow that I've recently posted (tbh it was related to the Firebase Stripe extension, but the main issue was exactly the one discussed here).

Hope this helps!

Saiguna7 commented 7 months ago

create file name called next-auth.d.ts

import NextAuth,{DefaultSession} from "next-auth"
declare module 'next-auth'{
    interface Session{
        firebaseToken?:string;
user:{
    id:string;
}& DefaultSession["user"]
    }
}

create folder firebase/admin.ts

adapter for google or github authentications

import {initFirestore} from "@auth/firebase-adapter"
import admin from "firebase-admin"
let app;
if(!admin.apps.length){
    app=admin.initializeApp({
        credential:admin.credential.cert({
            projectId: process.env.FIREBASE_PROJECT_ID,
            clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
            privateKey: process.env.FIREBASE_PRIVATE_KEY,
        }),
    });
}
const adminDb=initFirestore({
    credential:admin.credential.cert({
        projectId: process.env.FIREBASE_PROJECT_ID,
        clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
        privateKey: process.env.FIREBASE_PRIVATE_KEY,
    }),
});
const adminAuth=admin.auth(app);
export{adminDb,adminAuth};

create a components/FirebaseAuthprovider.tsx this for google authentication for call backs and token created

"use client"
import { signInWithCustomToken } from 'firebase/auth';
import { useSession } from 'next-auth/react';
import React, { useEffect } from 'react'
import {auth} from "@/firebase/clientApp"
import { Session } from 'next-auth'
async function syncFirebaseAuth(session:Session){
    if(session&& session.firebaseToken){
        try{
            await signInWithCustomToken(auth,session.firebaseToken);
        }catch(error) {
            console.error("Error signing in with custom token:",error);
        }
    }else{
        auth.signOut()
    }
}
export default function FirebaseAuthProvider({
    children,
}: {
    children: React.ReactNode;
}) {
    const {data: session}=useSession();

    useEffect(()=>{
if(!session) return;
syncFirebaseAuth(session);
    },[session])
  return<> {children}</>
}

create a file in components/Sessionprovider.tsx

'use client';
import { SessionProvider} from 'next-auth/react';

type Props = {
  children: React.ReactNode;
}

export default function ClientProvider({children}: Props) {
  return (
    <SessionProvider>
      {children}
    </SessionProvider>
  )
}

after this rap this in layout.tsx

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import ClientProvider from "@/components/ClientProvider";
import FirebaseAuthProvider from "@/components/FirebaseAuthProvider";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
        <body className={inter.className}>
        <ClientProvider>
          {/* <FirebaseAuthProvider> */}
            {children}
            {/* </FirebaseAuthProvider> */}
   </ClientProvider>
        </body>
      </html>
  );
}

if your using google provider wrap that firebaseauthprovider it is not working in credentials provider because firebaseauth provider

use this in auth.ts

import CredentialsProvider from "next-auth/providers/credentials";
import { signInWithEmailAndPassword } from 'firebase/auth';
import { auth } from "@/firebase/clientApp";
import { NextAuthOptions } from "next-auth";
import { FirestoreAdapter } from "@auth/firebase-adapter";
import { adminAuth, adminDb } from "@/firebase/admin";
import Credentials from "next-auth/providers/credentials"
export const authOptions: NextAuthOptions = {
  // Configure one or more authentication providers
  pages: {
    signIn: '/sign-in'
  },
  session: {
    strategy: 'jwt',
  },
  providers: [
    CredentialsProvider({
      name: 'Credentials',
      credentials: {},
      async authorize(credentials): Promise<any> {
        try {
          const userCredential = await signInWithEmailAndPassword(auth, (credentials as any).email || '', (credentials as any).password || '');
          if (userCredential.user) {
            return userCredential.user;
          }
          return null;
        } catch (error) {
          console.error('Error during sign-in:', error);
          throw new Error('Authentication failed');
        }
      }
    })
  ],

  adapter: FirestoreAdapter(adminDb) as any,
  callbacks: {
    session: async ({ session, token }) => {
      if (session?.user) {
        if (token.sub) {
          session.user.id = token.sub;
          const firebaseToken = await adminAuth.createCustomToken(token.sub);
          session.firebaseToken = firebaseToken;
        }
      }
      return session;
    },
    jwt: async ({ user, token }) => {
      if (user) {
        token.sub = user.id;
      }
      return token;
    },
  },
} satisfies NextAuthOptions;

**now next auth is updated Simplify Server-side Authentication: Replace the various server-side authentication with a

methods ( getServerSession

function call in most cases.

getSession

withAuth

getToken

useSession

single

auth()**

Saiguna7 commented 7 months ago

In case someone else if facing the same issue, in order to authenticate the user also on the Firebase Authentication dashboard, you just need to use createCustomToken and signInWithCustomToken Firebase functions.

For the longer answer, I'll leave you with this exhaustive example here on StackOverflow that I've recently posted (tbh it was related to the Firebase Stripe extension, but the main issue was exactly the one discussed here).

Hope this helps!

how we can do with credentials provider ? how to store the data in database when sign up session callbacks

rpathways commented 6 months ago

@GroophyLifefor did you find a solution here?

GroophyLifefor commented 6 months ago

@GroophyLifefor did you find a solution here?

Yeah, I found, I never use this .... again.

Saiguna7 commented 6 months ago

@GroophyLifefor did you find a solution here?

Yeah, I found, I never use this .... again.

you can use clerk better and easly also i provided u the solve in above for next auth with google credentials , if u want custom sign in and sign up with next auth with firebase it is diffecult

rpathways commented 6 months ago

@Saiguna7 I tried your solution, it still was not adding users to the authentication section of firebase.

On Thu, Jun 6, 2024 at 11:55 AM Saiguna7 @.***> wrote:

@GroophyLifefor https://github.com/GroophyLifefor did you find a solution here?

Yeah, I found, I never use this .... again.

you can use clerk better and easly also i provided u the solve in above for next auth with google credentials , if u want custom sign in and sign up with next auth with firebase it is diffecult

— Reply to this email directly, view it on GitHub https://github.com/nextauthjs/next-auth/issues/10280#issuecomment-2153094244, or unsubscribe https://github.com/notifications/unsubscribe-auth/AXDG4OYATT2AS2D6HM3JL2TZGCO75AVCNFSM6AAAAABEQKOZM6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNJTGA4TIMRUGQ . You are receiving this because you commented.Message ID: @.***>

eminvergil commented 5 months ago

next-auth currently doesn't implement register because it assumes that you have existing users so it only provides signin and signout. as others mentioned if you want to add users to db you can implement that in a callback function or if you want to use firebase you can follow the official documentation here: https://firebase.google.com/codelabs/firebase-nextjs#0 which is way simpler than using next-auth. i would remove next-auth and stick with firebase

Saiguna7 commented 5 months ago

@Saiguna7 I tried your solution, it still was not adding users to the authentication section of firebase. On Thu, Jun 6, 2024 at 11:55 AM Saiguna7 @.> wrote: @GroophyLifefor https://github.com/GroophyLifefor did you find a solution here? Yeah, I found, I never use this .... again. you can use clerk better and easly also i provided u the solve in above for next auth with google credentials , if u want custom sign in and sign up with next auth with firebase it is diffecult — Reply to this email directly, view it on GitHub <#10280 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AXDG4OYATT2AS2D6HM3JL2TZGCO75AVCNFSM6AAAAABEQKOZM6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNJTGA4TIMRUGQ . You are receiving this because you commented.Message ID: @.>

Remove credentials provider then it work u can see sonny songa from YouTube creating sass app i did from him https://www.youtube.com/live/OOUsvDOKlGs

Saiguna7 commented 5 months ago

Ya but firebase is complex and old for fetching data and role and session update all are complex now I am using supabase with prisma which is very very easy damm it saved a lot supabase is firebase alternative it is very good u need to try