Authentication Actions

When working with Authentication, it's common you'll want to perform authentication actions throughout your application, such as signing in a user, creating a user, triggering an OAuth flow, updating a user and lots more.

The React Query Firebase library supports all of the authentication actions by wrapping around the useMutation hook.

Although the Firebase SDK makes it super simple to perform these actions, it is still up to you to handle local state such as loading, errors and success. The hooks provided by this library make such scenarios simple.

For example, to sign a user in without the hooks, we need to handle many states ourselves:

import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "./firebase";

function SignIn() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [loading, setLoading] = useState("");
  const [error, setError] = useState("");

  async function onSignIn() {
    try {
      setLoading(true);
      await signInWithEmailAndPassword(auth, email, password);
    } catch (e) {
      setError(e.message);
    } finally {
      setLoading(false);
    }
  }

  return (
    <>
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      <input value={password} onChange={(e) => setPassword(e.target.value)} />
      <button disabled={loading} onClick={onSignIn}>
        Sign In
      </button>
      {!!error && <p>{error}</p>}
    </>
  );
}

Granted this could be cleaned up using form libraries and reducers, however repeating this process for the many authentication actions becomes tiresome.

Instead, with React Query Firebase we're able to quickly setup the same flow with minimal code:

import { useAuthSignInWithEmailAndPassword } from "@react-query-firebase/auth";
import { auth } from "./firebase";

function SignIn() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const mutation = useAuthSignInWithEmailAndPassword(auth, {
    onError(error) {
      toast.error("Could not sign you in!");
    },
  });

  function onSignIn() {
    mutation.mutate({ email, password });
  }

  return (
    <>
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      <input value={password} onChange={(e) => setPassword(e.target.value)} />
      <button disabled={mutation.isLoading} onClick={onSignIn}>
        Sign In
      </button>
      {mutation.isError && <p>{mutation.error.message}</p>}
    </>
  );
}

By using the built in hooks, we abstract the async state handling to React Query, allowing us to focus building the UI and not local state management. Another bonus is we're able to provide the React Query mutation options to all of the hooks, allowing us to handle side-effects such as error handling!

Hooks

Below is a list of all of the available hooks which wrap the Firebase API.

useAuthApplyActionCode

Applies a verification code sent to the user by email or other out-of-band mechanism.

const mutation = useAuthApplyActionCode(auth);
mutation.mutate("oobCode");

useAuthCheckActionCode

Checks a verification code sent to the user by email or other out-of-band mechanism.

const mutation = useAuthCheckActionCode(auth, {
  onSuccess(actionCodeInfo) {
    console.log("Valid action code!");
  },
  onError(error) {
    console.error("Invalid action code: ", error.code);
  },
});

mutation.mutate("oobCode");

useAuthConfirmPasswordReset

Completes the password reset process, given a confirmation code and new password.

const mutation = useAuthCheckActionCode(auth);

mutation.mutate({
  oobCode: "...",
  newPassword: "...",
});

useAuthCreateUserWithEmailAndPassword

Creates a new user account associated with the specified email address and password.

const mutation = useAuthCreateUserWithEmailAndPassword(auth);

mutation.mutate({
  email: "[email protected]",
  password: "...",
});

useAuthDeleteUser

Deletes and signs out the user.

const mutation = useAuthDeleteUser(auth);

mutation.mutate();

useAuthLinkWithCredential

Links the user account with the given credentials.

const mutation = useAuthLinkWithCredential();

mutation.mutate({
  user: auth.currentUser,
  // Any Auth credential supported...
  credential: EmailAuthProvider.credential('[email protected]', '...');
});

useAuthLinkWithPhoneNumber

Links the user account with the given phone number.

const mutation = useAuthLinkWithPhoneNumber();

mutation.mutate({
  user: auth.currentUser,
  phoneNumber: '+44123456789'
  appVerifier: new RecaptchaVerifier('recaptcha'),
});

useAuthLinkWithPopup

Links the authenticated provider to the user account using a pop-up based OAuth flow.

const mutation = useAuthLinkWithPopup();

mutation.mutate({
  user: auth.currentUser,
  // Any provider supported...
  provider: new GithubAuthProvider(),
});

useAuthLinkWithRedirect

Links the OAuthProvider to the user account using a full-page redirect flow.

const mutation = useAuthLinkWithRedirect();

mutation.mutate({
  user: auth.currentUser,
  // Any provider supported...
  provider: new GithubAuthProvider(),
});

useAuthReauthenticateWithCredential

Re-authenticates a user using a fresh credential.

const mutation = useAuthReauthenticateWithCredential();

mutation.mutate({
  user: auth.currentUser,
  // Any Auth credential supported...
  credential: EmailAuthProvider.credential('[email protected]', '...');
});

useAuthReauthenticateWithPhoneNumber

Re-authenticates a user using a fresh phone credential.

const mutation = useAuthReauthenticateWithCredential();

mutation.mutate({
  user: auth.currentUser,
  phoneNumber: '+44123456789'
  appVerifier: new RecaptchaVerifier('recaptcha'),
});

useAuthReauthenticateWithPopup

Reauthenticates the current user with the specified OAuthProvider using a pop-up based OAuth flow.

const mutation = useAuthReauthenticateWithPopup();

mutation.mutate({
  user: auth.currentUser,
  // Any provider supported...
  provider: new GithubAuthProvider(),
});

useAuthReauthenticateWithRedirect

Reauthenticates the current user with the specified OAuthProvider using a full-page redirect flow.

const mutation = useAuthReauthenticateWithRedirect();

mutation.mutate({
  user: auth.currentUser,
  // Any provider supported...
  provider: new GithubAuthProvider(),
});

useAuthReload

Reloads user account data, if signed in.

const mutation = useAuthReload();

mutation.mutate({
  user: auth.currentUser,
});

useAuthSendEmailVerification

Sends a verification email to a user.

const mutation = useAuthSendEmailVerification();

mutation.mutate({
  user: auth.currentUser,
  actionCodeSettings: {...}, // optional
});

useAuthSendPasswordResetEmail

Sends a password reset email to the given email address.

const mutation = useAuthSendPasswordResetEmail(auth);

mutation.mutate({
  email: '[email protected]',
  actionCodeSettings: {...}, // optional
});

useAuthSendSignInLinkToEmail

Sends a sign-in email link to the user with the specified email.

const mutation = useAuthSendPasswordResetEmail(auth);

mutation.mutate({
  email: '[email protected]',
  actionCodeSettings: {...},
});

useAuthSignInAnonymously

Asynchronously signs in as an anonymous user.

const mutation = useAuthSignInAnonymously(auth);

mutation.mutate();

useAuthSignInWithCredential

Asynchronously signs in with the given credentials.

const mutation = useAuthSignInWithCredential(auth);

const credential = EmailAuthProvider.credential("[email protected]", "...");
mutation.mutate(credential);

useAuthSignInWithCustomToken

Asynchronously signs in using a custom token.

const mutation = useAuthSignInWithCustomToken(auth);

mutation.mutate("xxxxx");

useAuthSignInWithEmailAndPassword

Asynchronously signs in using a custom token.

const mutation = useAuthSignInWithEmailAndPassword(auth);

mutation.mutate({
  email: "[email protected]",
  password: "...",
});

useAuthSignInWithPhoneNumber

Asynchronously signs in using a phone number.

const mutation = useAuthSignInWithPhoneNumber(auth);

mutation.mutate({
  phoneNumber: '+44123456789'
  appVerifier: new RecaptchaVerifier('recaptcha'),
});

useAuthSignInWithPopup

Authenticates a Firebase client using a popup-based OAuth authentication flow.

const mutation = useAuthSignInWithPopup(auth);

mutation.mutate({
  // Any provider supported...
  provider: new GithubAuthProvider(),
});

useAuthSignInWithRedirect

Authenticates a Firebase client using a full-page redirect flow.

const mutation = useAuthSignInWithRedirect(auth);

mutation.mutate({
  // Any provider supported...
  provider: new GithubAuthProvider(),
});

useAuthSignOut

Signs out the current user.

const mutation = useAuthSignOut(auth);

mutation.mutate();

useAuthUpdateCurrentUser

Asynchronously sets the provided user as Auth.currentUser on the Auth instance.

const mutation = useAuthUpdateCurrentUser(auth);

mutation.mutate(user); // Some `User` instance
mutation.mutate(null); // Removes the user

useAuthUpdateEmail

Updates the user's email address.

const mutation = useAuthUpdateEmail();

mutation.mutate({
  user: auth.currentUser,
  newEmail: "[email protected]",
});

useAuthUpdatePassword

Updates the user's password.

const mutation = useAuthUpdatePassword();

mutation.mutate({
  user: auth.currentUser,
  newPassword: "...",
});

useAuthUpdatePhoneNumber

Updates the user's phone number.

const mutation = useAuthUpdatePhoneNumber();

mutation.mutate({
  user: auth.currentUser,
  // PhoneAuthCredential returned from phone auth flow
  credential,
});

useAuthUpdateProfile

Updates a user's profile data.

const mutation = useAuthUpdateProfile();

mutation.mutate({
  user: auth.currentUser,
  displayName: "...", // optional
  photoURL: "https://...", // optional
});

useAuthVerifyBeforeUpdateEmail

Sends a verification email to a new email address.

const mutation = useAuthVerifyBeforeUpdateEmail();

mutation.mutate({
  user: auth.currentUser,
  newEmail: "[email protected]",
  actionCodeSettings: {}, // optional
});

useAuthVerifyPasswordResetCode

Checks a password reset code sent to the user by email or other out-of-band mechanism.

const mutation = useAuthVerifyPasswordResetCode(auth);

mutation.mutate("oobCode");