【Next.js】Firebase Authentication でパスワードの変更を実装する

はじめに

フロントエンドエンジニアの関(@kur0buchi)です。

hinataレンタルでは先日会員機能をリリースいたしました。 当記事は会員機能実装にあたり調査していく上で適当なパスワード変更のサンプルを探しても現在の環境に丁度よく流用できそうなものが見当たらなかったため執筆に至りました。

hinata-rental.me

前提

  • Next.js v9 以降
  • TypeScript v4.2.3
  • Firebase v9

この記事で利用している各技術の詳細な説明は省きます。

利用例

パスワード変更機能にも様々あると思いますが、今回は「現在のパスワード」と「新しく設定するパスワード」を渡す形式を採用することとします。

使い方としては旧パスワードと新パスワードを渡すと Promise<void> が返ってきて何かあったら catch できるくらい簡単な使用感を目指します。

バリデーションやエラーチェックは適宜行ってください。

import { updatePassword } from "path/to/logic";

export const Form = () => {
  const handleSubmit = async (oldPassword: string, newPassword: string) => {
    // パスワード更新処理
    await updatePassword(oldPassword, newPassword)
      .catch((e) => {
        // エラー処理
      })
      .then(() => {
        // 成功時処理
      });
  };

  return (
    <div>
      <button
        onClick={() => {
          handleSubmit("hoge", "fuga");
        }}>パスワード変更</button>
    </div>
  );
};

実装

下記の記事を参考にして、同じ使用感でパスワード変更のメソッドを追加する方針にしています。

zenn.dev

ディレクトリ名は一例です

// auth/app.ts
import { initializeApp } from "firebase/app";

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};

const firebaseApp = initializeApp(firebaseConfig);

export default firebaseApp;
// auth/index.ts
import {
  EmailAuthProvider,
  getAuth,
  reauthenticateWithCredential,
  updatePassword as firebaseUpdatePassword,
} from "firebase/auth";
import firebaseApp from "./app";

export const updatePassword = (
  oldPassword: string,
  newPassword: string
): Promise<void> => {
  return new Promise((resolve, reject) => {
    const auth = getAuth(firebaseApp);
    if (auth.currentUser == null) {
      return reject();
    }
    
    // クレデンシャルの取得
    const credential = EmailAuthProvider.credential(
      auth.currentUser.email || "",
      oldPassword
    );
    
    // メールアドレスの再認証
    reauthenticateWithCredential(auth.currentUser, credential)
      .then((userCredential) => {
      
        // パスワードの更新
        firebaseUpdatePassword(userCredential.user, newPassword)
          .then(() => resolve())
          .catch((error) => reject(error));
      })
      .catch((error) => reject(error));
  });
};

特筆するようなことはありませんが、クレデンシャルの取得、メールアドレスの再認証、パスワードの更新を順に処理しています。

firebase/auth/updatePassword をインポートする際のエイリアス命名の都合なので必須ではありません、お好みでどうぞ。

終わりに

vivit ではモダンな開発環境で活躍したいエンジニアを大募集中です。

www.wantedly.com

参考