🤖

Firebase Authenticationでパスワードの再設定をする

2021/09/28に公開

Firebase Authenticationでユーザー情報の管理をしている。
パスワードの再設定する時のメモ。

Firebaseのデフォルトの新パスワード設定を利用する場合

この場合は、

  1. 登録しているメールアドレスにメールが届く
%DISPLAY_NAME% 様

メールアドレスを確認するには、次のリンクをクリックしてください。

https://<project id>.firebaseapp.com/__/auth/action?mode=action&oobCode=code

このアドレスの確認を依頼していない場合は、このメールを無視してください。

よろしくお願いいたします。

%APP_NAME% チーム
  1. リンクをクリックすると以下の画面が開く

(「続行」ボタンは actionCodeSettings を設定した場合のみ表示される。)

実装

関数としては、sendPasswordResetEmailを利用する。この関数を呼び出すことで、第一引数のメールアドレスに、firebase authのurlでパスワード設定する画面へ誘導できる。

https://firebase.google.com/docs/reference/js/v8/firebase.auth.Auth#sendpasswordresetemail

const submitPasswordResetEmail = async () => {
  await auth
    .sendPasswordResetEmail(email)
    .then((resp) => {
      // メール送信成功
    })
    .catch((error) => {
      // メール送信失敗
      console.log(error)
    })
}

第二引数として、actionCodeSettingsを設定できる。これは、firebase authのurlでパスワードを再設定した後にリダイレクトする情報など付与できる。以下の場合、「続行」ボタンが現れ、それをクリックするとhttp://localhost:3000/loginに遷移させることができる。

const submitPasswordResetEmail = async () => {
  const actionCodeSettings = {
    // パスワード再設定後のリダイレクト URL
    url: 'http://localhost:3000/login',
    handleCodeInApp: false,
  }

  await auth
    .sendPasswordResetEmail(email, actionCodeSettings)
    .then((resp) => {
      // メール送信成功
    })
    .catch((error) => {
      // メール送信失敗
      console.log(error)
    })
}

ちなみにこの場合、パスワード再設定用のGetパラメータにcontinueUrlが追加される。これはもちろん、actionCodeSettingsurlプロパティで登録したもの。

https://<project ID>.com/__/auth/action?mode=resetPassword&oobCode=3zakKRxy5adKhTMX5kC81Kl0jKkit-YY4HRSUMeXagwAAAF8KwNVCw&apiKey=AIzaSyA9J-hMBpQkXViG6i2T52kIKLWX6w9cQpQ&continueUrl=http%3A%2F%2Flocalhost%3A3000%2Flogin&lang=ja

カスタマイズのパスワード再設定画面を使う場合

最初のパターンだと、firebaseのデフォルトであるものの、サービスの画面が出てこないためユーザーの不安を感じさせてしまう。そこでサービス独自のパスワード再設定画面を作りたい。

Firebase Authenticationでパスワード再設定画面のURLを自分の指定するURLに設定できる機能があり、

  • アクションURLで、自分のサービスのパスワード再設定画面のURLを登録
  • パスワード再設定画面でfirebase authの関数を色々呼び出す

ことで、実装ができる。

Firebase Authenticationの画面からアクションURLを設定する

アクションURLはもともと、https://<project ID>.firebaseapp.com/__/auth/actionになっている。

[パスワードの再設定] > 編集ボタンを押し、画面下部のアクションURLを編集する。

今回、開発用に例えばhttp://localhost:3000/set-new-passwordなどとする。

その結果、メール再設定用のメールの本文のリンクが以下のように変更される。

http://localhost:3000/set-new-password?mode=resetPassword&oobCode=WOBTj7bYcSLCWtWgwrt7dlNYgW_zlVbLUdQq0r_qmCsAAAF8Kvo8bA&apiKey=AIzaSyA9J-hMBpQkXViG6i2T52kIKLWX6w9cQp&lang=ja

これをクリックすると、http://localhost:3000/set-new-passwordに遷移する。

次にその画面の実装を見ていく。

実装

  • verifyPasswordResetCode関数
  • confirmPasswordReset関数

を使う。

https://firebase.google.com/docs/reference/js/v8/firebase.auth.Auth#confirmpasswordreset

https://firebase.google.com/docs/reference/js/v8/firebase.auth.Auth#confirmpasswordreset

今回はReactで作った画面の例だが、set-new-password.tsxは以下。

const NewPassword = () => {
  const [actionCode, setActionCode] = useState<string>('')

  const [password, setPassword] = useState<string>('')

  // 初回のレンダリングのみ
  useEffect(() => {
    const queryParams = new URLSearchParams(window.location.search)
    const oobCode = queryParams.get('oobCode') || ''
    setMode(mode)
    setActionCode(oobCode)
  }, [])

  const handleSubmit = (event: React.SyntheticEvent) => {
    event.preventDefault()
    
    if(oobCode === '') return // 取得できない場合処理終了

    firebase
      .auth()
      .verifyPasswordResetCode(actionCode)
      .then(() => {
        firebase
          .auth()
          .confirmPasswordReset(actionCode, password)
          .then(async (resp) => {
	    console.log("success")
            // 成功。ログイン画面などを表示するコードを足す場所
          })
          .catch((error) => {
            console.log(error)
          })
      })
  }

  return(
    // 略
  )

やっていることとしては、

  • URLのGetパラメータからoobCodeと取得する。
  • verifyPasswordResetCode関数でoobCodeが妥当か検証する。
  • 妥当だった場合、confirmPasswordReset関数にoobcodeを渡して新しいパスワードを登録。

oobCodeは、メールアドレスの所有者だけが知っている、時間制限付きのトークン。

The confirmation code send via email to the user.

verifyPasswordResetCode関数は以下の場合エラーを投げるようになっているので、後続の処理をしないようにできる。

  • トークンの有効時間を超えた場合
  • トークンが間違っていたり、最新のものではない
  • Firebase Authのユーザーがdisabledになっている
  • アカウントが無効になっている
  • アカウントが削除されている

verifyPasswordResetCode関数が正常に動作するとemailアドレスを取得可能。

参考

あとから調べると、以下の記事に書かれていた。

https://blog.ojisan.io/firebase-auth-ipass-login/

https://masalib.hatenablog.com/entry/2020/11/29/000000

Discussion