Skip to content

Infinite loop when logging in  #601

@bowis

Description

@bowis

When filing a bug report, please confirm you've done the following:

Describe the bug
0

I have the following setup using Next-firebase-auth:

Login page:

import {
  AuthAction,
  withAuthUser,
  withAuthUserSSR,
  withAuthUserTokenSSR,
} from "next-firebase-auth";
import { FormProvider, useForm } from "react-hook-form";

import Link from "next/link";
import { MoonLoader } from "react-spinners";
import PageHead from "../components/PageHead";
import { auth } from "../config/firebase";
import { signInWithEmailAndPassword } from "firebase/auth";
import { useRouter } from "next/router";
import { useState } from "react";

interface LoginType {
  email: string;
  password: string;
}
const LoginPage = () => {
  const methods = useForm<LoginType>({ mode: "onBlur" });
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  const {
    register,
    handleSubmit,
    formState: { errors },
  } = methods;

  const onSubmit = async (data: LoginType) => {
    try {
      setLoading(true);
      const { email, password } = data;
      await signInWithEmailAndPassword(auth, email, password);
      setLoading(false);
    } catch (e: any) {
      setError(e.message);
      setLoading(false);
    }
  };

  return (
    <div className="flex min-h-screen flex-col justify-center py-12 sm:px-6 lg:px-8 bg-gray-50">
      <PageHead title="Inloggen" />
      <div className="bg-white py-8 shadow rounded-lg px-10 mx-auto">
        <FormProvider {...methods}>
          <form
            className="w-80 mx-auto pb-12 px-4"
            onSubmit={handleSubmit(onSubmit)}
          >
            <div className="mt-5">
              <label
                htmlFor="email"
                className="block text-sm font-medium text-gray-600"
              >
                Email
              </label>
              <input
                type="email"
                {...register("email", { required: "Email is verplicht" })}
                className="block mt-1 w-full appearance-none rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-hurks-green focus:ring-hurks-green focus:outline-none  sm:text-sm"
              />
              {errors.email && (
                <p className="text-red-400 mt-1  text-sm font-medium">
                  {errors.email.message}
                </p>
              )}
            </div>
            <div className="mt-7">
              <label
                htmlFor="password"
                className="block text-sm font-medium text-gray-600"
              >
                Wachtwoord
              </label>
              <input
                type="password"
                {...register("password", {
                  required: "Wachtwoord is verplicht",
                })}
                className="block w-full mt-1 appearance-none rounded-md border border-gray-300 px-3 py-2shadow-sm focus:border-hurks-green  focus:ring-hurks-green  focus:outline-none  sm:text-sm"
              />
              {errors.password && (
                <p className="text-red-400 mt-1  text-sm font-medium">
                  {errors.password.message}
                </p>
              )}
            </div>
            <div className="text-sm mt-2">
              <Link
                href="/forgot-password"
                className="font-medium text-hurks-green "
              >
                Wachtwoord vergeten?
              </Link>
            </div>
            <div className="pt-8">
              <button
                type="submit"
                className="flex w-full justify-center rounded-md border border-transparent bg-hurks-green py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-hurks-green focus:outline-none   "
              >
                {loading && (
                  <MoonLoader
                    size={15}
                    color={"white"}
                    className="-ml-0.5 mr-2 "
                  />
                )}
                Login
              </button>
              {error && (
                <p className="text-red-400 mt-1  text-sm font-medium">
                  {error}
                </p>
              )}
            </div>
          </form>
        </FormProvider>
      </div>
    </div>
  );
};

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

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

Protected page:

import { AuthAction, withAuthUser, withAuthUserTokenSSR } from "next-firebase-auth";
import { deleteDoc, doc } from "firebase/firestore";
import { useContext, useState } from "react";

import DeleteModal from "../../components/DeleteModal";
import { GeneralContext } from "../../context/GeneralContext";
import Link from "next/link";
import MaterialsTable from "../../components/material/MaterialsTable";
import PageHead from "../../components/PageHead";
import { db } from "../../config/firebase";

const Materials = () => {
  const { showDeleteModal, setShowDeleteModal } = useContext(GeneralContext);
  const [materialId, setMaterialId] = useState<null | string>(null);

  const handleSetMaterialId = (id: string) => {
    setMaterialId(id);
  };

  const deleteMaterial = async () => {
    setShowDeleteModal(!showDeleteModal);
    await deleteDoc(doc(db, "materials", `${materialId}`));
  };
  return (
    <>
      <PageHead title="Materialen Overzicht" />
      <div className="mt-14 w-9/12 mx-auto">
        <div className="flex pb-8 justify-between items-center">
          <h1 className="text-2xl font-semibold text-gray-900">Materialen</h1>
          <Link
            href="/materials/create"
            type="button"
            className="items-center justify-center rounded-md bg-hurks-green px-4 py-2.5 text-sm font-medium text-white shadow-sm hover:bg-hurks-green sm:w-auto"
          >
            Voeg materiaal toe
          </Link>
        </div>
        <MaterialsTable handleSetMaterialId={handleSetMaterialId} />
      </div>
      <DeleteModal deleteItem={deleteMaterial} />
    </>
  );
};

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

export default withAuthUser({
  whenUnauthedAfterInit: AuthAction.REDIRECT_TO_LOGIN,
})(Materials);

Config:

import { init } from "next-firebase-auth";

const TWELVE_DAYS_IN_MS = 12 * 60 * 60 * 24 * 1000;

const initAuth = () => {
  init({
    debug: true,
    authPageURL: "/login",
    appPageURL: "/materials",
    loginAPIEndpoint: "/api/login", // required
    logoutAPIEndpoint: "/api/logout", // required
    firebaseAdminInitConfig: {
      credential: {
        projectId:
          process.env.NODE_ENV === "production"
            ? process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID!
            : process.env.NEXT_PUBLIC_FIREBASE_DEV_PROJECT_ID!,
        privateKey:
          process.env.NODE_ENV === "production"
            ? process.env.FIREBASE_PRIVATE_KEY!
            : process.env.FIREBASE_DEV_PRIVATE_KEY!,
      },
    },

    firebaseClientInitConfig: {
      apiKey:
        process.env.NODE_ENV === "production"
          ? process.env.NEXT_PUBLIC_FIREBASE_API_KEY!
          : process.env.NEXT_PUBLIC_FIREBASE_DEV_API_KEY!,
      authDomain:
        process.env.NODE_ENV === "production"
          ? process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN
          : process.env.NEXT_PUBLIC_FIREBASE_DEV_AUTH_DOMAIN,
      projectId:
        process.env.NODE_ENV === "production"
          ? process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID
          : process.env.NEXT_PUBLIC_FIREBASE_DEV_PROJECT_ID,
    },
    cookies: {
      name: "Project",
      keys: [
        process.env.COOKIE_SECRET_CURRENT,
        process.env.COOKIE_SECRET_PREVIOUS,
      ],
      httpOnly: false,
      path: "/",
      maxAge: TWELVE_DAYS_IN_MS,
      overwrite: true,
      sameSite: "lax",
      secure: process.env.NEXT_PUBLIC_COOKIE_SECURE === "true",
      signed: true,
    },
  });
};

export default initAuth;

Versions

next-firebase-auth version: 1.0.0-canary.18
Firebase JS SDK: 9.12.1
Next.js: latest

To Reproduce
After logging in, i get the 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. error, which redirects me to the login page, which in turn redirects me to the protected page again, creating an endless loop. When inspecting the cookies, I do see that they are being written, so I'm not sure where it is going wrong at the moment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions