Programming Room.
GCP Tips.
GAE Tips.
Identity Platformの使い方 : Email/Password IDプロバイダの設定.2020/05/07
更新 2020/06/10
Email/Password IDプロバイダの設定方法の説明です。
おしながき
概要.
Email/Password IDプロバイダは、大きく2つの認証方法に分かれています。
- パスワード認証
Eメールアドレスとパスワードによる、よくある認証方法です。 - メールリンク認証
パスワードの代わりに、エンドユーザが入力したEメールアドレスにメールを送り、メール内のリンクからログインを行う認証方法です。パスワードは使用しません。
設定と実装によりどちらか一方のみを使用することになります。エンドユーザが好きな方を選べるわけではありません。右の画面キャプチャはEmail/Password IDプロバイダの設定です。「パスワードを使用しないログインを許可する」がその設定項目で、チェックを入れるとメールリンク認証になります。
一部に、パスワード認証とメールリンク認証で実装が異なるケースがあります。
アプリの運用中に設定を切り替えると、1つのアプリの中に両方のアカウントが混在する状態になります。この場合は、アカウントごとにそれぞれどちらで作成されたアカウントなのかを判断して、処理を変えるように実装する必要があります。
注意点.
- Email/Password IDプロバイダを使用すると、GCPとメールをやり取りするケースが発生します。メーラによってはこれらのメールがスパムと認識されるケースがあります。実際に、Windowns10標準のメーラで迷惑メールに分類されているのを確認しました。
パスワード認証.
設定.
Email/Password IDプロバイダについては、「メール/パスワード プロバイダの編集」ページで設定を行います。設定しなれけばならないことは、あまりありません。
デフォルトの内容のまま何も変更せずに「保存」を押せば、パスワードによる認証に設定されます。つまり次の『メールリンク認証.』で説明する設定を2つとも行っていない状態であれば、パスワード認証が行われます。どちらか片方だけ設定していると、実行時にエラーメッセージが表示され、ログインできなくなります。
メールリンク認証.
Firebaseの公式ドキュメントは「JavaScriptでメールリンクを使用してFirebase認証を行う」にありました。Firebase UIを使わないで、UIを独自に構築する場合について述べられています。しかしFirebase UIを使用する場合でも参考になります。
設定.
設定方法は「メールリンク認証」に説明されているとおりです。必要なのは下記の2つのみ。2つとも揃わないと、実行時にエラーメッセージが表示され、ログインできなくなります。
- GCPコンソール「メール/パスワード プロバイダの編集」ページの「パスワードを使用しないログインを許可する」にチェックを入れ、設定を保存する。
- 「認証UIの初期化と実行.」で説明したsignInOptionsの、Email/Password IDプロバイダの設定に、下記の様にsignInMethodプロパティを追加する。
var uiConfig = { ... 'signInOptions': [ { provider: firebase.auth.EmailAuthProvider.PROVIDER_ID, // Email/Password IDプロバイダを選択 signInMethod: firebase.auth.EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD, // メールリンク認証には これが必要 }, ], ... };
送信されるメール.
実際に送られてきたメールは、以下のような文面でした。
from : noreply@プロジェクトID.firebaseapp.com
subject : アプリ名へのログイン
body :
お客様
このメールアドレスでの アプリ名 へのログインのリクエストを受け付けました。ユーザの入力したメールアドレス のアカウントでログインするには、こちらのリンクをクリックしてください。
アプリ名 にログイン
このリンクをリクエストしていない場合は、このメールを無視してください。
よろしくお願いいたします。
アプリ名 チーム
「プロジェクト名 にログイン」の部分が、ログイン後のリンクになっているHTMLメールです。このURIは署名付きになっているようで、1回のみ使用可能です。1度このリンクからログインした後、再度このリンクからのログインを試みると、右のようなエラーメッセージが表示され、ログインできなくなっています。
リンクの有効期限については特に説明が見つからず、不明です。
使用してみて.
気づいた点をいくつか。
- 実際にこのメールを受け取ったら、「なんか変なメール来た」と思ってしまいそうなくらい、簡素な内容です。GCPコンソール「メール/パスワード プロバイダの編集」ページの「テンプレートを構成」リンクを押すと、「メール テンプレートを構成する」パネルが表示されて送信されるメールの内容を編集できるのですが、ログイン時に送信されるメールについては編集できません。
- ユーザがデフォルトのブラウザに設定されていないブラウザからログインしようとし、メールをブラウザではなくメール専用のメーラ(OutLookとかBecky!とか)で開いた場合、メールのリンクからはデフォルトに設定されているブラウザで表示されてしまうケースがあります(メーラのパイパーリンクの扱いによって変わります)。ログイン操作を開始していないブラウザでリンクが開かれた場合、Eメールアドレスの再入力が必要です。Webメールで開いた場合は、ログイン後の画面は別ウィンドウ/別タブで開くことになるので、ログイン前の画面がどこかに残っていることになりそうです。
- メールリンク認証では、ユーザの表示名を入力する機会がありませんでした。「メールアドレスとパスワード」の手順3 に説明されている requireDisplayNameプロパティは無視されました。当然、APIから表示名の取得を試みても、nullが返ってきます。
ユーザにしてみればパスワードを管理しなくていいメリットはあるかもしれませんが、メールリンク認証はちょっと使いにくい気がします。慣れていないだけかなぁ。
Firebaseコンソールでの設定.
Firebaseコンソールからも設定可能です。
Authenticationページの「Sign-in method」タブを選択し、「ログインプロバイダ」のリストで「メール / パスワード」をマウスでポイントしたときに右端に表示される鉛筆アイコンを押して、編集ダイアログを表示させます。
Email/Password IDプロバイダを使用する場合の追加実装.追加 2020/06/10
上記までの設定のみでも、一応Identity Platformへユーザ登録し、ログイン・ログアウトなどの機能を使用できるようになります。しかしEmail/Password
IDプロバイダの場合は、設定だけでは実現できず、追加で実装が必要なものがいくらかあります。
公式ドキュメントで参考になりそうなのは、「Firebaseのユーザを管理する」くらいでしょうか。
Eメールアドレスの確認.
Eメールアドレスはエンドユーザの手入力なのでタイプミスしている可能性もあります。一般的には入力されたEメールアドレスに対して確認メールを送信し、そのメール内のリンクや認証コードの入力によって、Eメールアドレスが正しいことを確認します。パスワード認証の場合は、この手順を実行する必要があります。Eメールアドレスが確認されるまでは、アカウントは仮登録の状態と理解しておくべきのようです。
この手順は上記の設定やFirebase UIには実装されておらず、その実装の手助けになるメソッドがFirebase JavaScript SDKに用意されていますので、それを利用してアプリ開発者が実装する必要があります。
確認済みの判断.
Eメールアドレスが確認済みか否かは、以下のプロパティ/メソッドで確認することができます。
- fireauth.auth.User.emailVerifiedプロパティ
- com.google.firebase.auth.FirebaseToken.isEmailVerified()メソッド
- com.google.firebase.auth.UserRecord.isEmailVerified()メソッド
他のIDプロバイダでは、アカウントが最初に登録された時から「確認済み(=true)」になっているものと、「未確認(=false)」になっているものが混在しています。
確認メールの送信.
Eメールアドレスの確認メールは、firebase.auth.User.sendEmailVerification()メソッドで送信できます。送信先はUserインスタンスが持っているEメールアドレスになります。このメソッドの引数のActionCodeSettings.urlプロパティで、確認後の遷移先URIを指定できます。以下のサンプルソースを示しますが、ほぼ「ユーザに確認メールを送信する」のとおりです。
function sendEmailVerification() { var user = firebase.auth().currentUser; var actioncode = { url: '確認後の遷移先URI', handleCodeInApp: false, // デフォルト値 }; user.sendEmailVerification(actioncode).then(function() { // 成功 }) .catch(function(error) { // 失敗 }); }
以下のようなメールが届きます。from/reply-to/件名はGCPコンソールやFirebaseコンソールから編集可能ですが、本文は編集できません。
from : noreply@プロジェクトID.firebaseapp.com
subject : アプリ名 へのログイン
body :
ユーザの表示名 様
メールアドレスを確認するには、次のリンクをクリックしてください。
確認用のリンク
このアドレスの確認を依頼していない場合は、このメールを無視してください。
よろしくお願いいたします。
アプリ名 チーム
このメールの「確認用のリンク」から、ブラウザで右の様な簡単なページが表示されます。これでEメールアドレスの確認が完了し、User.emailVerifiedプロパティもtrueに変わります。「続行」ボタンを押すと、ActionCodeSettings.urlプロパティで指定したURIに遷移します。ActionCodeSettings.urlプロパティを指定しなかった場合、「続行」ボタンは表示されません。
またこのリンクは1回限り有効です。2回目以降はエラーメッセージが表示されます。
メールリンク認証の場合.
GCPコンソールの「IDプラットフォーム」-「設定」で「作成を可能にする」をチェックしていると(デフォルト状態です)、パスワード認証でもメールリンク認証でも、Firebase UIを使っていると初回ログイン時に自動的にIdentity
Platformに登録されてしまいます。その後ログインしただけでは「未確認(=false)」の状態です。
メールリンク認証ではEメールアドレスが間違っているとログインできなくなるので、ここで説明した確認の手順を踏まなくても、ログイン成功を確認済みと判断しても良いと思います。公式ドキュメントでも、パスワード認証のページには確認の手順が説明されていますが、メールリンク認証のページではその説明はありませんので、そういう意味と理解して良いのではないかと思います。
メールリンク認証でも、ここに説明したfirebase.auth.User.sendEmailVerification()メソッドによって、確認済みにすることは可能です。
再認証.
Email/Password IDプロバイダの場合、「再認証」に説明したように、OAuthProviderインスタンスをfirebase.auth.User.reauthenticateWithPopup()メソッドなどに渡してもエラーになります。
パスワード認証の場合.
パスワード認証の場合は、firebase.auth.EmailAuthProvider.credential()スタティックメソッドで取得したクレデンシャルを、firebase.auth.User.reauthenticateWithCredential()メソッドに渡して再認証します。
以下がそのサンプルソースです。password引数の値は、HTMLのinput要素などで適当にエンドユーザに入力させます。
function reauthenticateWithCredential(password) { // 引数passwordは事前にエンドユーザに入力してもらったパスワードを渡す var user = firebase.auth().currentUser; var credential = firebase.auth.EmailAuthProvider.credential(user.email, password); user.reauthenticateWithCredential(credential) .then(function() { // 認証成功 }) .catch(function(error) { // 認証失敗 }); }
メールリンク認証の場合.
メールリンク認証の場合は、firebase.auth.EmailAuthProvider.credentialWithLink()スタティックメソッドでクレデンシャルを取得するようです。しかし「メールリンクのリンクと再認証」のスニペット(2番目の方)をそのままコピペしたにもかかわらず、credentialWithLink()メソッドでエラーになってしまいます。以下はブラウザのコンソールに表示されていたメッセージです。やはり使われないから動作確認さえろくに行われないのか。
0: Error: Invalid email link!
パスワードのリセット.
当然、パスワード認証の場合のみ必要な実装です。
エンドユーザがパスワードを忘れてしまったなどの理由でパスワードの再設定が必要になるケースがあります。Firebase UI for Web
- Authを使用していれば、「メールでログイン」の先のUIに実装されているので必須ではありません。独自に実装する方法について述べます。
firebase.auth.Auth.sendPasswordResetEmail()メソッドで、パスワード再設定メールを指定のEメールアドレスに送信できます。ユーザがログインしていなくても実行できるように、Authクラスのメソッドです。以下のサンプルソースを示しますが、ほぼ「パスワードの再設定メールを送信する」のとおりです。
function sendPasswordResetMail(email) { var auth = firebase.auth(); auth.sendPasswordResetEmail(email).then(function() { // 送信成功 }) .catch(function(error) { // 送信失敗 }); }
ここでの送信成功/失敗は、再設定メールの送信の成否です。パスワードの再設定の成否ではありません。
Identity Platformに登録されていないメールアドレスを指定すると、送信失敗します。
以下のようなメールが届きます。from/reply-to/件名だけでなく本文も、GCPコンソールやFirebaseコンソールから編集可能です。
from : noreply@プロジェクトID.firebaseapp.com
subject : アプリ名 のパスワードを再設定してください
body :
お客様
アプリ名 の 送信先メールアドレス アカウントのパスワードをリセットするには、次のリンクをクリックしてください。
再設定用のリンク
パスワードのリセットを依頼していない場合は、このメールを無視してください。
よろしくお願いいたします。
アプリ名 チーム
このメールの再設定用のリンクから、ブラウザでこの様な簡単なページが表示されます。新しいパスワードを入力して「保存」を押すと、表示内容は右の様に変わります。ここで新しいパスワードが再設定されます。
またこのリンクは1回限り有効です。2回目以降はエラーメッセージが表示されます。
Firebase UI for Web - Authを使用している場合、ログインUIから「メールでログイン」を選択した先の、パスワード入力UI (タイトルは「ログイン」)の「ログインできない場合」をクリックした場合も、同様に画面遷移します。
メールリンク認証の場合.
この手順はメールリンク認証でも実行できます。そしてエンドユーザがパスワードを設定すると、アカウントはパスワード認証に変更されます。
Eメールアドレスの変更.
Firebaseの公式ドキュメントでは「ユーザのメールアドレスを設定する」に説明されていますが、ここ読むと使用されているfirebase.auth.User.updateEmail()メソッドは、単に「内部的にメールアドレスを設定するだけ」としか受け取れません。Googleさんドキュメントがクソ杉。単純にメールアドレスをIdentity Platformの内部データに設定するだけなら、「ユーザのプロフィールを更新する」に説明されているfirebase.auth.User.updateProfile()メソッドで可能と思われます。またサーバ側で行うなら、本サイト「ユーザ情報の編集」に説明しています。
実際にはfirebase.auth.User.updateEmail()メソッドは、「Eメールアドレス変更の手続きを開始するメールを送信する」ものです。このメソッドもSecurity Sensitiveな操作を行うので、ログイン・再認証から一定時間以内でないと実行できません。
以下がサンプルソースですが、公式ドキュメント「ユーザのメールアドレスを設定する」とほぼ同じです。
function sendUpdateEmail(new_email) { var user = firebase.auth().currentUser; user.updateEmail(new_email).then(function() { // 送信成功 }) .catch(function(error) { // 送信失敗 }); }
APIリファレンスに説明されているとおりなのですが、firebase.auth.User.updateEmail()メソッドの動作は以下のとおりです。
- Userオブジェクトが保持しているアカウントのEメールアドレスに、メールアドレス変更を伝えるメールを送信する。このメールにはアドレス変更を取り消すためのリンクも記載されています。
- 引数で指定されたEメールアドレスを、新たなEメールアドレスとして保持する。
- Eメールアドレスを「未確認」にする。つまりfirebase.auth.User.emailVerifiedプロパティをfalseに変更する。
変更前のEメールアドレスに、以下のようなメールが届きます。from/reply-to/件名はGCPコンソールやFirebaseコンソールから編集可能ですが、本文は編集できません。
from : noreply@プロジェクトID.firebaseapp.com
subject : アプリ名 のログイン用メールアドレスが変更されました
body :
ユーザの表示名 様
アプリ名 のログイン用メールアドレスが 新Eメールアドレス に変更されました。
メールの変更を依頼していない場合は、次のリンクをクリックして、ログイン用メールアドレスをリセットしてください。
変更取り消し用のリンク
よろしくお願いいたします。
アプリ名 チーム
上記1.のアドレス変更を取り消すためのリンクを押すと、ブラウザには右のようなページが表示されます。Eメールアドレスが元に戻ると同時に、Eメールアドレス確認の状態(firebase.auth.User.emailVerifiedプロパティ)も元に戻ります。
上記3.の動作によりアカウントの仮登録相当の状態(firebase.auth.User.emailVerifiedプロパティ=false)に戻されますので、新しいEメールアドレスに対して確認を行う必要があります。その手順は「Eメールアドレスの確認」と同じです
Eメールアドレスの変更後に、変更前のEメールアドレスを使用してログインすると、別アカウントとして扱われます。
Copyright 2005-2020, yosshie.