JavaScriptでFirebaseAuthenticationを使う方法

#Firebase Authenticationとは
Googleが提供しているユーザー認証をするBaaSです。
メールアドレスとパスワードでのログインやGoogleアカウント、Twitterアカウントなどでの様々なプロバイダでのユーザ認証が可能で、自分で作るのは大変なユーザ認証機能を簡単に実装できます。
今回はメールアドレスとパスワードを利用したログイン機能とGoogleアカウントでのユーザ認証機能を使っていきたいと思います。
#準備
##プロジェクトの作成
[Firebase](https://console.firebase.google.com)にアクセスしプロジェクトを作成します。
![Firebasetitle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686889/2dea0b2a-62b8-eb8a-eb88-587d3f703146.png)
##アプリの追加
アプリの追加ではウェブを選択
![appin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686889/fd06a6a0-240f-254c-41db-6d5a27e31d8e.png)
アプリのニックネームを入力し次へを押すとFirebaseSDKが表示されるのでbodyタグに入力します。

```html
<script src="https://www.gstatic.com/firebasejs/8.0.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.0.0/firebase-analytics.js"></script>
<script>
  const firebaseConfig = {
    apiKey: "",
    authDomain: "",
    databaseURL: "",
    projectId: "",
    storageBucket: "",
    messagingSenderId: "",
    appId: "",
    measurementId: ""
  };
  firebase.initializeApp(firebaseConfig);
  firebase.analytics();
</script>
```
ここまではFirebase共通の準備になります。
今回はFirebase Authenticationを使うためそれを使うための宣言を追加。

```html
<script src="https://www.gstatic.com/firebasejs/8.0.0/firebase-auth.js"></script>
```
バージョンはアプリの追加の時に入れたものと同じバージョンを入力してください。
##ログイン方法の設定
Firebaseの左タブからAuthenticationを選択し、sign-in methodから使用するプロバイダを有効にします。
今回はメール/パスワードとGoogleを使用するためその2つを有効にします。
![login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686889/6abd369c-0b03-6082-e86e-4e17ff204ec0.png)
以上で準備は終了です。
#メールアドレスとパスワードでのユーザ認証
メールアドレスとパスワードを使ったユーザ認証について説明します。
##コード
```html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="utf-8">
</head>

<body>
    <script src="https://www.gstatic.com/firebasejs/8.0.0/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.0.0/firebase-analytics.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.0.0/firebase-auth.js"></script>
    <script>
        const firebaseConfig = {
            apiKey: "",
            authDomain: "",
            databaseURL: "",
            projectId: "",
            storageBucket: "",
            messagingSenderId: "",
            appId: "",
            measurementId: ""
        };
        firebase.initializeApp(firebaseConfig);
        firebase.analytics();

    </script>
    <input id="txtmail" type="email" placeholder="メールアドレス">
    <input id="txtpass" type="password" placeholder="パスワード">
    <input id="txtpass2" type="password" placeholder="パスワード確認">
    <button id="crebtn">アカウント作成</button>
    <button id="inbtn">ログイン</button>
    <button id="outbtn">ログアウト</button>
    <br>
    <div id="sta"></div>
    <script>
        const mail = document.getElementById("txtmail");
        const pass = document.getElementById("txtpass");
        const pass2 = document.getElementById("txtpass2");
        const cre = document.getElementById("crebtn");
        const login = document.getElementById("inbtn");
        const logout = document.getElementById("outbtn");
        const sta = document.getElementById("sta");
        let mailv;
        let passv;
        let pass2v;
        let errorCode;
        let errorMessage;


        firebase.auth().onAuthStateChanged(function (user) { //ログイン状態確認
            if (user) {
                //ログイン時の処理
                console.log("ログイン中");
                sta.innerHTML = "ログイン中"
            } else {
                //非ログイン時の処理
                console.log("ログインなし");
                sta.innerHTML = "ログインなし"
            }
        });

        cre.addEventListener("click", function () { //メールアドレスとパスワードの登録
            mailv = mail.value;
            passv = pass.value;
            pass2v = pass2.value;
            if (passv === pass2v) { //パスの確認
                firebase.auth().createUserWithEmailAndPassword(mailv, passv).catch(function (error) {
                    //エラーが出た時
                    errorCode = error.code;
                    errorMessage = error.message;
                });
            } else {
                alert("確認パスが違います");
            }
        });

        login.addEventListener("click", function () { //ログイン
            mailv = mail.value;
            passv = pass.value;
            firebase.auth().signInWithEmailAndPassword(mailv, passv).catch(function (error) {
                //エラーが出た時
                errorCode = error.code;
                errorMessage = error.message;
            });
        });

        logout.addEventListener("click", function () { //ログアウト
            firebase.auth().signOut().then(function () {
                //ログアウトできた時
            }).catch(function (error) {
                //ログアウトできなかった時
            });
        });
    </script>
</body>

</html>
```
コードを実行するとこんな感じに表示されます
![index.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686889/111390da-e5ff-f572-1c95-edd5184c7963.png)

少し長いので分解して説明していきます。
##コードの説明
###ログイン状態の確認
このコードではログイン状態を確認しています。
ログインしている状態だとログイン中と表示され、ログインしてない状態だとログインなしと表示されます。
状態が変わった時に実行されます。
ログイン時の処理や非ログイン時の処理はここに書きます。

```javascript
firebase.auth().onAuthStateChanged(function(user) { //ログイン状態確認
            if (user) {
                //ログイン時の処理
                console.log("ログイン中");
                sta.innerHTML = "ログイン中"
            } else {
                //非ログイン時の処理
                console.log("ログインなし");
                sta.innerHTML = "ログインなし"
            }
        });
```
###アカウント登録
アカウント作成ボタンを押すと実行されます
ここではアカウントの登録を行っています。
アカウントの作成ボタンを押すと実行され、パスワードと確認パスワードが同じだった場合テキストの入力値を取得してそれを登録しています。

```javascript
cre.addEventListener("click", function() { //メールアドレスとパスワードの登録
            mailv = mail.value;
            passv = pass.value;
            pass2v = pass2.value;
            if (passv === pass2v) { //パスの確認
                firebase.auth().createUserWithEmailAndPassword(mailv, passv).catch(function(error) {
                    //エラーが出た時
                    errorCode = error.code;
                    errorMessage = error.message;
                });
            } else {
                alert("確認パスが違います");
            }
        });
```
アカウント作成を押すとAuthenticationの管理画面で追加されてることを確認できます。
![aca.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686889/eccfabb2-b419-8f4d-a82c-d0f68eef3abb.png)
###ログイン
ログインボタンを押すと実行されます。
入力したメールアドレスとパスワードが登録されているかを確認します。
登録されてる場合ログインされます。

```javascript
login.addEventListener("click", function() { //ログイン
            mailv = mail.value;
            passv = pass.value;
            firebase.auth().signInWithEmailAndPassword(mailv, passv).catch(function(error) {
                //エラーが出た時
                errorCode = error.code;
                errorMessage = error.message;
            });
        });
```
ログインするとログインなしからログイン中に切り替わります。
![loginn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686889/ccbcc517-920c-ab2e-5196-e3a2d3c6e3d1.png)
###ログアウト
ログアウトボタンを押すと実行されます。
ログインされている状態で押すとログアウトされます。
非ログイン時の押しても何も起こりません。

```javascript
logout.addEventListener("click", function() { //ログアウト
            firebase.auth().signOut().then(function() {
                //ログアウトできた時
            }).catch(function(error) {
                //ログアウトできなかった時
            });
        });
```
ログアウトを押すとログイン中からログインなしに切り替わります。
![logout.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686889/6c4555d5-218b-17a6-a87b-3c584a808008.png)
###エラーメッセージの例
エラーメッセージの例を記述します
***アカウント登録時のエラー***

| error.message | 状況 |
|:-:|:-:|
| auth/email-already-in-use  |  登録しようとしたメールアドレスが使用されている |
|  auth/invalid-email | 入力したメールアドレスが正しくない  |
***ログイン時のエラー***

|  error.message| 状況 |
|:-:|:-:|
|  auth/invalid-email | 入力したメールアドレスが正しくない  |
| auth/wrong-password  |  パスワードが間違っている |
|  auth/user-not-found |  登録されてないメールアドレス |
#構築された環境を使ってGoogleアカウントでのユーザ認証を行う。
ここでは事前にFirebaseで構築された環境を使ってログインを行います。
GoogleだけじゃなくメールアドレスとパスワードでのログインやTwitterでのログインなどができます。
プロバイダ(Googleやtwitter)でのログインは許可した環境下でしかできないため、**xamppなどを実行してください***。
今回はxamppを使ってlocalhostでサイトを開いてます。
許可はAuthenticationの管理画面の認証済みドメインから追加・確認ができます。
##コード

```html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="utf-8">
    <script src="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.js"></script>
    <link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.css" />
    <!--用意されたスタイルを使うための宣言-->
</head>

<body>
    <h1>Welcome to My Awesome App</h1>
    <div id="firebaseui-auth-container"></div>
    <!--ここにログインボタンが表示-->
    <div id="loader">Loading...</div>
    <button id="outbutton">ログアウト</button>
    <br>
    <div id="log"></div>
    <script src="https://www.gstatic.com/firebasejs/8.0.0/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.0.0/firebase-analytics.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.0.0/firebase-auth.js"></script>
    <script>
        const firebaseConfig = {
            apiKey: "",
            authDomain: "",
            databaseURL: "",
            projectId: "",
            storageBucket: "",
            messagingSenderId: "",
            appId: "",
            measurementId: ""
        };
        firebase.initializeApp(firebaseConfig);
        firebase.analytics();

        const logout = document.getElementById("outbutton");
        const log = document.getElementById("log");

        const provider = new firebase.auth.GoogleAuthProvider();

        firebase.auth().onAuthStateChanged(function (user) { //ログイン状態確認
            if (user) {
                console.log("ログイン中")
                log.innerHTML = "ログイン中"
            } else {
                console.log("ログインなし")
                log.innerHTML = "ログインなし"
            }
        });

        const ui = new firebaseui.auth.AuthUI(firebase.auth());

        const uiConfig = {
            callbacks: {
                signInSuccessWithAuthResult: function (authResult, redirectUrl) {
                    return true;
                },
                uiShown: function () {
                    document.getElementById('loader').style.display = 'none';
                }
            },
            signInFlow: 'popup',
            signInSuccessUrl: 'google.html', //ログイン成功時に遷移するURL(自分のものに変更)
            signInOptions: [
                firebase.auth.EmailAuthProvider.PROVIDER_ID,
                firebase.auth.GoogleAuthProvider.PROVIDER_ID,
            ],
            // 利用規約
            //tosUrl: '<your-tos-url>',
            // プライバシーポリシー
            //privacyPolicyUrl: '<your-privacy-policy-url>'
        };
        ui.start('#firebaseui-auth-container', uiConfig); //レンタリング
        logout.addEventListener("click", function () { //ログアウト
            firebase.auth().signOut().then(function () {
                //ログアウトログアウトできた時
            }).catch(function (error) {
                //ログアウトできなかった時
            });
        });
    </script>
</body>

</html>
```
このような画面が表示されます。
![googlelogin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686889/b8188f95-e63d-9614-004f-427800313515.png)
ログインを行うと追加されていることが確認できます。
![googlekekka.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686889/d084f595-8ab8-d966-07a3-8d27b01b3ad4.png)

##コードの説明
###用意されたスタイルを使うための宣言

```html
<script src="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.js"></script>
<link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.css" />
```
headタグに記述します。用意されたcssなどを読み込んでます。

```html
<div id="firebaseui-auth-container"></div>
```
ここの中にログインボタンなどが生成されます。

```javascript
const ui = new firebaseui.auth.AuthUI(firebase.auth());
```
uiの初期化を行っています。

###ログイン成功時に遷移するURL
ログイン成功した時に移動するURLを指定します。
今回は同じ場所を指定しています。
自分のものに変更してください。

```javascript
signInSuccessUrl: 'google.html',
```
###表示するログイン方法の設定
ここではログイン方法を設定しています。
今回はメールアドレスとパスワードログインとGoogleでのログインを表示しています。

```javascript
signInOptions: [
                firebase.auth.EmailAuthProvider.PROVIDER_ID,
                firebase.auth.GoogleAuthProvider.PROVIDER_ID,
            ],
```
ここに追加をすることでログイン方法の追加ができます。
***例***

| 方法 | 表記 |
|:-:|:-:|
| Twitter  |  firebase.auth.TwitterAuthProvider.PROVIDER_ID |
|  Facebook |  firebase.auth.FacebookAuthProvider.PROVIDER_ID |
|  電話番号 |  firebase.auth.PhoneAuthProvider.PROVIDER_ID  |
詳しくは[こちら](https://firebase.google.com/docs/auth/web/firebaseui#set_up_sign-in_methods)

###表示
ここで設定を読み込み表示をしています。

```javascript
ui.start('#firebaseui-auth-container', uiConfig);
```
#ユーザー情報の追加・取得(補足)
ユーザーの名前の送信や取得方法を補足します。
###ユーザーの名前と写真URLを設定
現在ログインしているユーザーの名前を設定します。
ログイン状態確認の処理に入れてください。

```javascript
const user = firebase.auth().currentUser;

    user.updateProfile({ //名前を送信
        displayName: "",
        photoURL: "URL",
    }).then(function () {
        //名前の設定完了時の処理
    }).catch(function (error) {
        //名前の設定失敗時の処理
    });
```
###ユーザー情報の取得
現在ログインしているユーザの情報を取得します。

```javascript
const user = firebase.auth().currentUser;
let name, email, photoUrl, uid, emailVerified;

 if (user != null) {
  name = user.displayName;
  email = user.email;
  photoUrl = user.photoURL;
  emailVerified = user.emailVerified;
  uid = user.uid; 
  console.log(name);
```
#リファレンス
パスワードでの認証
https://firebase.google.com/docs/auth/web/password-auth?hl=ja
構築環境での認証
https://firebase.google.com/docs/auth/web/firebaseui?hl=ja
ユーザ情報
https://firebase.google.com/docs/auth/web/manage-users