gladly-team / next-firebase-auth

Simple Firebase authentication for all Next.js rendering strategies
https://nfa-example-git-v1x-gladly-team.vercel.app/
MIT License
1.34k stars 291 forks source link

Infinite redirection loop between SSR page & login page due to cookies #591

Closed splacentino closed 1 year ago

splacentino commented 1 year ago
  1. Have you set onVerifyTokenError and onTokenRefreshError in your config and checked for any helpful errors?

    Yes, no error shown.

  2. Have you set debug: true in your config and read through server-side and client-side debug logs for any helpful messages?

    Yes

  3. Have you tried the example app with your own Firebase credentials?

    No.

  4. Have you read through the troubleshooting Q&A?

    Yes.

Describe the bug I am not able to run a wrapped getServerSideProps due to failure at getting user from cookies. It then does infinite redirection between the main page and the login page.

Versions

next-firebase-auth version: 1.0.0-canary.18 Firebase JS SDK: 9.14.0 Next.js: 12.3.1

To Reproduce Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior A clear and concise description of what you expected to happen.

Debug and error logs

next-firebase-auth: [withAuthUserSSR] Calling "withAuthUserSSR" / "withAuthUserTokenSSR".
next-firebase-auth: [getUserFromCookies] Attempting to get user info from cookies via the ID token.
next-firebase-auth: [getUserFromCookies] Failed to retrieve the ID token from cookies. This will happen if the user is not logged in, the provided cookie values are invalid, or the cookie values don't align with your cookie settings. The user will be unauthenticated.

next-firebase-auth: [withAuthUserSSR] Redirecting to login.
next-firebase-auth: [withAuthUserSSR] Calling "withAuthUserSSR" / "withAuthUserTokenSSR".
next-firebase-auth: [getUserFromCookies] Attempting to get user info from cookies (not using the ID token).
next-firebase-auth: [getUserFromCookies] Successfully retrieved the user info from cookies.

next-firebase-auth: [withAuthUserSSR] Calling "withAuthUserSSR" / "withAuthUserTokenSSR".
next-firebase-auth: [getUserFromCookies] Attempting to get user info from cookies (not using the ID token).
next-firebase-auth: [getUserFromCookies] Failed to retrieve the user info from cookies. The provided cookie values might be invalid or not align with your cookie settings. The user will be unauthenticated.
next-firebase-auth: [withAuthUser] Set AuthUser to: {
  id: null,
  email: null,
  emailVerified: false,
  phoneNumber: null,
  displayName: null,
  photoURL: null,
  claims: {},
  getIdToken: [Function (anonymous)],
  clientInitialized: false,
  firebaseUser: null,
  signOut: [Function (anonymous)],
  serialize: [Function: serialize]
}
next-firebase-auth [withAuthUser] Calling "withAuthUser". [index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] Set AuthUser to: 
Object { id: null, email: null, emailVerified: false, phoneNumber: null, displayName: null, photoURL: null, claims: {}, getIdToken: v()
, clientInitialized: false, firebaseUser: null, … }
[index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] The Firebase ID token changed. New Firebase user: 
Object { providerId: "firebase", proactiveRefresh: {…}, reloadUserInfo: {…}, reloadListener: null, uid: "NpzAq...cm917wquisgYqNie63", auth: {…}, stsTokenManager: {…}, accessToken: "eyJh............NiIsImtpZCI6Ijk1MWMwOGM1MTZhZTM1MmI4OWU0ZDJlMGUxNDA5NmY3MzQ5NDJhODciLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiU2ltb24gUGxhY2VudGlubyIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BRWRGVHA2RUplbzA2XzlIMFQtWEZFbm1rMlJNQUc0bDZudkswbTBwSDhHTD1zOTYtYyIsImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9wZXRwcm9qZWN0Mi1lMWU4YiIsImF1ZCI6InBldHByb2plY3QyLWUxZThiIiwiYXV0aF90aW1lIjoxNjcwNTAwNjQ1LC......X2lkIjoiTnB6QXFIbGFtSWNtOTE3d3F1aXNnWXFOaWU2MyIsInN1YiI6Ik5wekFxSGxhbUljbTkxN3dxdWlzZ1lxTmllNjMiLCJpYXQiOjE2NzA1MDQ5MjcsImV4cCI6MTY3MDUwODUyNywiZW1haWwiOiJzaW1vbkBsYWItYm.....................sX3ZlcmlmaWVkIjp0cnVlLCJmaXJlYmFzZSI6eyJpZGVudGl0aWVzIjp7Imdvb2dsZS5jb20iOlsiMTExNzY1NDUxNjAxODIwNTU3MDY3Il0sImVtYWlsIjpbInNpbW9uQGxhYi1ib3guc3R1ZGlvIl19LCJzaWduX2luX3Byb3ZpZGVyIjoiZ29vZ2xlLmNvbSJ9fQ.pKyO2ERzgh_kl_sYFpGrP3MAq5l-ESw1tMReugdfzwfaSt0qJb3Jw3Yp1NBmcX1c2PpoHwBBG7VAeX_Zh6NGNhEqnPhpfqtOa9qSUUHFev6DZddPzvsVwUClGciELJhOkiiw2GuIEiE_g7brwJ2YggT7VrcUP1-oOzkTYAhxuG3K2_ZUAbdHYoHiprEnRgcpBPwxEBfrMkk8tQ9j-chbYsd5TyOR41XwD9gBJH0E1AFfPcmdn6WCXpJNTqqwe3E_PilT9dWZCtsk-IDCU1fg3s8NyzEBpihjgH7GeH2HVMSPzbTj1E48-2MdE8cCB6QxetKej-ltBidMU0zOe1w0EQ", displayName: "", email: "email@gmail.com", … }
[index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] Calling the login endpoint. [index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] Set AuthUser to: 
Object { id: "NpzAq...cm917wquisgYqNie63", email: "email@gmail.com", emailVerified: true, phoneNumber: null, displayName: "", photoURL: "http://photorul", claims: {}, getIdToken: v(e)
, clientInitialized: true, firebaseUser: {…}, … }
[index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] Completed the auth API request. [index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] Set AuthUser to: 
Object { id: "NpzAq...cm917wquisgYqNie63", email: "email@gmail.com", emailVerified: true, phoneNumber: null, displayName: "", photoURL: "http://photorul", claims: {}, getIdToken: v(e)
, clientInitialized: true, firebaseUser: {…}, … }
[index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] Redirecting to app. [index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] Calling "withAuthUser". [index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] Set AuthUser to: 
Object { id: "NpzAq...cm917wquisgYqNie63", email: "email@gmail.com", emailVerified: true, phoneNumber: null, displayName: "", photoURL: "http://photorul", claims: {}, getIdToken: v(e)
, clientInitialized: true, firebaseUser: {…}, … }
[index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] Redirecting to app. [index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] Set AuthUser to: 
Object { id: "NpzAq...cm917wquisgYqNie63", email: "email@gmail.com", emailVerified: true, phoneNumber: null, displayName: "", photoURL: "http://photorul", claims: {}, getIdToken: v(e)
, clientInitialized: true, firebaseUser: {…}, … }
[index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
next-firebase-auth [withAuthUser] Redirecting to app.

next-firebase-auth [withAuthUser] Redirecting to app. [index.browser.js:2:7784](webpack://_N_E/node_modules/next-firebase-auth/build/index.browser.js?07e6)
Too many calls to Location or History APIs within a short timeframe. [main.js:1217:42](http://localhost:4200/_next/static/chunks/main.js?ts=1670507323938%20line%20841%20%3E%20eval)
Uncaught (in promise) DOMException: The operation is insecure.

Additional context

Main page (/):

export const getServerSideProps = withAuthUserTokenSSR({
  whenUnauthed: AuthAction.REDIRECT_TO_LOGIN,

})(async ({ AuthUser, ...context }) => {
  const token = await AuthUser.getIdToken();

  console.log({ token });
  // fetch & return props
});

function Index(data: DataType) {
    // render page
}

export default withAuthUser<DataType>({
  whenUnauthedAfterInit: AuthAction.REDIRECT_TO_LOGIN,
})(Index);

Login page (/login):


export const Login = () => {
 return <div><FirebaseAuth /></div>
}

export const getServerSideProps = withAuthUserSSR({
  whenAuthed: AuthAction.REDIRECT_TO_APP,
})();

export default withAuthUser({
  whenAuthed: AuthAction.REDIRECT_TO_APP,
})(Login);

Custom FirebaseAuth component:

import { getApp } from 'firebase/app';
import { getAuth, GoogleAuthProvider, EmailAuthProvider, signInWithPopup } from 'firebase/auth';

export function FirebaseAuth() {
  const loginWithGoogle = async () => {
    const auth = getAuth(getApp());
    await signInWithPopup(auth, new GoogleAuthProvider());
  };

  return (
    <div>
      <button onClick={loginWithGoogle}>CLICK</button>
    </div>
  );
}

configuration:

const initAuth = () => {
  init({
    debug: process.env.NODE_ENV === 'development',

    authPageURL: '/login',
    appPageURL: '/',
    loginAPIEndpoint: '/api/auth/login', // defined + initAuth()
    logoutAPIEndpoint: '/api/auth/logout', // defined + initAuth()
    firebaseAdminInitConfig: process.env.FIREBASE_PRIVATE_KEY
      ? {
          credential: {
            projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID as string,
            clientEmail: process.env.FIREBASE_CLIENT_EMAIL as string,
            privateKey: process.env.FIREBASE_PRIVATE_KEY,
          },
          databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL as string,
        }
      : undefined,
    firebaseClientInitConfig: {
      apiKey: process.env.NEXT_PUBLIC_FIREBASE_PUBLIC_API_KEY as string,
      authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
      databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
      projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
    },
    onVerifyTokenError: (error) => {
      console.error('nop');
      console.error(error);
    },
    onLoginRequestError(error) {
      console.error('nop');
      console.error(error);
    },
    onTokenRefreshError: (error) => {
      console.error('nop');
      console.error(error);
    },
    cookies: {
      name: 'ProjectRelatedName',
      keys: [process.env.COOKIE_SECRET_CURRENT, process.env.COOKIE_SECRET_PREVIOUS],
      httpOnly: true,
      maxAge: TWELVE_DAYS_IN_MS,
      overwrite: true,
      path: '/',
      sameSite: 'strict',
      secure: process.env.NODE_ENV === 'production',
      signed: true,
    },
  });
};
kmjennison commented 1 year ago

@splacentino Is it fixed if you use withAuthUserTokenSSR in /login rather than withAuthUserSSR? It looks like there could be a mismatch here where the ID token value in cookies isn't valid, while the user value is valid.

splacentino commented 1 year ago

@splacentino Is it fixed if you use withAuthUserTokenSSR in /login rather than withAuthUserSSR? It looks like there could be a mismatch here where the ID token value in cookies isn't valid, while the user value is valid.

Same issue.

I reproduced the same issue (same setup) on a brand new nextjs pet project.

splacentino commented 1 year ago

I found the issue:

got a nice non-UTF8 character in my FIREBASE_PRIVATE_KEY.

Thanks for your support