FirebaseでOAuth2の認証・認可を30分で実装する


## はじめに
Oauth2.0に対応しているフェデレーションIDを使った認証、認可をFirebase Authenticationを用いて実装してみました。
Oauthによる認証、認可は、Auth0やOpenID ConnectなどといったIDaasの利用や、Googleアカウントに限定すればCloud IAPを用いる方法などたくさんありますが、今回はその中でも一番シンプルに実装できる(と思った)Firebase Authentication SDKを用いた認証について解説していきます。
なお、認証結果のJWTをサーバ側に渡してFirebase AdminSDKでゴニョるところは気分が向いたらまた別記事で解説していきます。

## 結論
作成したサンプルアプリはGAEに公開しています
https://authentication-test-436b3.appspot.com
コードは
https://github.com/KatsuyaAkasaka/firebase-auth
に公開してますのでここらへんを確認してください。

以降は重要ポイントをかいつまんで解説します。

## 実装内容
今回は、Googleと作成アプリの認可までのロジックを作成します。

今回の実装内容は、サンプルのfirebase公式ドキュメントが参考になるかと思います。
[FirebaseUI でウェブアプリに簡単にログイン機能を追加する](https://firebase.google.com/docs/auth/web/firebaseui)

## プロジェクト作成
ここらへんはいろいろな記事で解説しているところですので軽く。
Firebase Authenticationのプロジェクトを作成して、Googleを有効にしておいてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178971/825e0c41-1d87-fbbc-0bff-12a09e3b6acc.png)

左上の歯車からFirebaseConfigが取れます。こちらの値は今後使用します。


## 初期化
```js
const initializeApp = () => {
    if (!firebase.apps.length) {
        const firebaseConfig = {
            apiKey: process.env.API_KEY,
            authDomain: "***",
            databaseURL: "***",
            projectId: "***",
            storageBucket: "***",
            messagingSenderId: "***",
            appId: "***"
        };
        firebase.initializeApp(firebaseConfig);
    }
    return firebase;
};

exports.firebase = initializeApp();
```

この関数を実行することで、firebaseオブジェクトを初期化します。firebaseConfig内のidは先程の歯車から参照できますので、それをコピペしてください。
このconfig情報はhtmlから直接閲覧できる情報ですので、セキュリティ面で不安がありますが、
firebaseのプロジェクト作成時に同時に作成されるgcpプロジェクトから、このAPIキーを利用できるドメインを制限させることができます。
以下参照
https://stackoverflow.com/questions/35418143/how-to-restrict-firebase-data-modification

Browser keyで
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178971/8f33c183-c95d-45c1-455f-418017030fb2.png)

以下のように設定させることで、このAPIキーを利用できるドメインがGAEに乗せたプロジェクトとfirebaseapp.comだけにします。
appspot.comは後述するFirebaseUIがfirebaseに向けてoauthの認証リクエスト送信時に、firebaseapp.comはそこからgoogleのoauth認証画面( https://accounts.google.com/signin/oauth/ )にリクエストする際にそれぞれ使用します。


## 認証・認可
```html

<html>
    <h1>this is login.</h1>
    <div id="firebaseui-auth-container"></div>
    <div id="loader">Loading...</div>
</html>
```

```js
function createUI() {
    const ui = new firebaseui.auth.AuthUI(firebase.auth());
    ui.start('#firebaseui-auth-container', {
        callbacks: {
            signInSuccessWithAuthResult: (authResult, redirectUrl) => {
                authResult.user.getIdToken(true)
                    .then(
                        //アカウント作成
                    )
                    .catch((error)  => { console.log(`Firebase getIdToken failed!: ${error.message}`) });
                return true;
            },
            uiShown: () => { document.getElementById('loader').style.display = 'none' }
        },
        signInSuccessUrl: '/success',
        signInFlow: 'popup',
        signInOptions: [
            firebase.auth.GoogleAuthProvider.PROVIDER_ID
        ],
    });
} 
```

firebaseui-auth-containerのidをもつdivを用意しておくと、loaderのidを持つdivにFirebaseUIの標準的なログインウィンドウが埋め込まれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178971/bc4ec2b9-2845-c292-bf66-f3276a0036e5.png)
FirebaseUIを使用することで、今回のような標準的なUIが一瞬で作成されます。

`ui.start`の第二引数に入れることができるオプションのプロパティはこちらに乗っています。
https://github.com/firebase/firebaseui-web#configuration

この `Sign in with Google`のボタンをクリックするだけでGoogleのOauth認証画面が表示され、acceptすることで認可が成功します！

## ログアウト

```js
function logout() {
    firebase.auth().signOut()
    .then(()=>{
        location.href = '/';
    })
    .catch((error)=>{
        console.log(`ログアウト時にエラーが発生しました (${error})`);
    });
};
```

`firebase.auth().signOut()`を呼び出すだけでGoogleとの認証を破棄できます。
ログアウトはこれを自前のボタンに埋め込むだけでOKです。楽すぎる...！


## まとめ
Firebase AuthenticationやFirebaseUIを使えば非常にかんたんに認証認可の実装ができます！
[github](https://github.com/KatsuyaAkasaka/firebase-auth)にサンプルのコードを公開していますのでご確認ください。