アカウントに複数の認証プロバイダをリンクする方法【typescript, javascript, reactjs, nextjs, firebase, firestore】


概要

firebaseが提供しているアカウントリンク機能を使用すると既存アカウントをTwitterやFacebook、Googleなどの認証プロバイダに紐付けることでどのアカウントからでも一つのアカウントにログインできるようになります。弊サービスでは携帯番号認証でユーザーの新規登録/ログインを行っていましたがメールアドレスでのログインにも対応させるためメールアドレスにリンクさせる実装を行いました。本記事では既存アカウントにメールアドレス認証プロバイダをリンクさせる方法をご紹介します。

実装方法

実装

アカウントをリンクする方法はシンプルで、firebase.auth().currentUser からlinkWithCredentialを呼んでメールとパスワードを引数に入れます。

async link(): Promise<auth.UserCredential | Error> {
     const credential = firebase.auth.EmailAuthProvider.credential(email,password)
     return this.currentUser.linkWithCredential(credential)
}

他のプロバイダにリンク完了するとこのように新しいプロバイダが追加されていることを確認できます。

ただし、TwitterやFacebookなどの認証プロバイダでアカウントリンクを行う場合、linkWithCredentialではなくlinkWithPopupまたはlinkWithRedirectを使用するので実装方法が少し異なります。

リンク先となるプロバイダにログインするようユーザーに促します。ポップアップ ウィンドウをユーザーに表示するか、プロバイダのログインページにリダイレクトすることにより、ログインを促すことができます。モバイル デバイスではリダイレクトすることをおすすめします。

詳しくはこちらから
https://firebase.google.com/docs/auth/web/account-linking?hl=ja

アカウントにリンクされたプロバイダを削除するにはproviderIdをunlinkの引数に入れます。指定されたプロバイダがアカウントから削除されます。

async unlink(providerId: string, callback: (user: firebase.User | null) => void) {
      if (this.currentUser) {
          const user = await this.currentUser.unlink(providerId)
        callback(user)
      } else {
        callback(null)
      }
}

例えば、電話番号認証を削除したい場合はこのように指定するとアンリンクすることができます。

await unlink("phone")

そのほかのプロバイダリスト↓

Providers Provider ID
EmailAuthProviderID password
PhoneAuthProviderID phone
GoogleAuthProviderID google.com
FacebookAuthProviderID facebook.com
TwitterAuthProviderID github.com
AppleAuthProviderID apple.com
YahooAuthProviderID yahoo.com
MicrosoftAuthProviderID hotmail.com

サインイン

async login(email: string,password: string): Promise<auth.UserCredential | undefined> {
    return firebase.auth().signInWithEmailAndPassword(email, password)
}

パスワードリセット。この関数を実行するとfirebaseからパスワード変更メールが届きます。

await firebase.auth().sendPasswordResetEmail(email)

ログイン時に発生すエラーに対応するために以下のオブジェクトを作成して使いました。

export const errorMessages = {
    'auth/user-not-found':
        'ユーザーが見つかりませんでした',
    'auth/requires-recent-login': '再ログインが必要です。',
    'auth/wrong-password': 'パスワードが違います。',
    'auth/weak-password': 'パスワードが弱いです。',
    'auth/email-already-in-use':
        '既に使われているメールアドレスです',
    'auth/operation-not-allowed':
        'メールアドレス/パスワード方式が有効化されていません。',
    'auth/invalid-email': ' メールアドレスの形式が正しくありません。',
    'auth/user-disabled': 'ユーザーが無効化されています。',
}

所感

エラーハンドリング、リファクタしようかなあ。。。

リファレンス