🗼

Firebase Authentication + Next.js でログイン機能を作るので大変だったこと

2022/10/18に公開

こんにちは。地図パズル製作所では、先日 Firebase Authentication を使って作った、サインアップ&ログイン機能をリリースしました!!こちらです。

https://chizu-puzzle.com/signup/

ログインすると、ランキングにも参加できますので、ぜひ挑戦してみてくださいね!すでに、最難関の 400ピースのパズルを30分ちょっとで完成してしまった方がいらっしゃいます(笑) すごいですね!

ですが、このログイン機能、なんと実装し始めてから、4カ月くらいかけてようやくリリース、となりました。。。遅いですね。。。もちろんメイン業務は他にあって、暇なときに地図パズル製作所の更新をしているのでどうしようもないのですが、さすがにこんなにかかるとは思っていませんでした。

ということで、今日は Firebase Authentication を使ってログイン機能を作って大変だったことをまとめていきたいと思います。

なお、この記事は、以下の記事を更新したものになります。

https://zenn.dev/chizu_puzzle/articles/605e948ba8c0a6

firebaseui-web-react が使えない

Firebase Authentication を使ってログイン機能を実装しようとする場合、ログイン画面を自分で実装する必要はありません。FirebaseUI for Web というものがあって、簡単に実装できます。また、React(Next)を使う場合は、firebaseui-web-react というライブラリがでてきます。

https://github.com/firebase/firebaseui-web-react

Firebase の公式のものだし、これを使おう!と思ってしまうところですが、注意が必要です。なんと、このライブラリ、一年近くメンテナンスされていないようです。。。(2022/10現在)なので、当然 React 18 にも対応しておりません。こちらの issue で半年ほど前から、「React 18 をサポートして!」と言っている方がいますが返事がなく、「このライブラリを使うのやめます」って言われちゃってます。。。

https://github.com/firebase/firebaseui-web-react/issues/165

そして、こちらの issue で Next.js で実装する場合の説明がされていますが、こちらも英語版 UI を使う場合のみに対応しているみたいです。

https://github.com/firebase/firebaseui-web-react/pull/173#issuecomment-1215648239

同じ感じで、React 17 で実装するなどして、無理やり firebase-web-react を使って実装しようとしたとしても、日本語化をどうするか?という問題が出てきます。こちらの URL に従ってやればできると書かれていますが、いろいろ難しいです。

https://github.com/firebase/firebaseui-web#developer-setup

まず、日本語版をビルドするには、Java と Chrome が入っている環境が必要だとのことです。私はそんな環境持ってないし、Java って最近ライセンスが厳しくなったんだっけ??という問題に直面して、やめました。ライセンスとか、苦手なんです。

ログイン用 UI を自分で作ろうとすると、ブランドの取扱いが大変

fireabaseui-web-react が駄目そうだったので、UI を自分で全て作ることを考えました。それで、実装を進めるにあたって調査していくと、大きな問題にぶつかりました。Google でログインを実装する場合、ログインボタンの仕様を Google が細かく規定しているのです。。詳細はこちらの URL をご覧ください。

https://developers.google.com/identity/branding-guidelines?hl=ja

ここだと、「テキストの左右のパディングは8dpにし…」などと書いてありますが、「dpって単位、何??pxじゃないの??」となってしましました。調べてもよく分からなかったです。。ということで、沼にはまってしまい、自分で実装することはあきらめました。

ブランドの取扱いについて調査しただけで私はあきらめてしまったので、ログイン UI を自分で実装した場合が大変かどうかとかは分かりません。もし実装したことがある方がいたら、コメントで教えてください!!

Pマークとの兼ね合い

FireabaseUI for Web の UI は、下の URL みたいな感じです。

https://fir-ui-demo-84a6c.firebaseapp.com/

と、ここで問題に気づきました。プライバシーポリシーと利用規約を確認するチェックボックスが付いていないのです。。FirebaseUI for Web でも採用している、ボタンを押したら同意したことにみなしますよ、というのでもいいことはいい感じですが、P マーク的に一番無難なのはチェックボックスを付けることみたいですね。

ちなみに、この件、こちらの issue でも取り上げられています。

https://github.com/firebase/FirebaseUI-Android/issues/1338

今後に期待です。

ちなみに私は、Firebase Authentication でユーザ登録後に別画面にリダイレクトしてハンドル名を登録させ、その時にプライバシーポリシーと利用規約に同意させることにしました。これで P マーク、大丈夫ですよね??

Yahoo と連携させる方法が大変だったので Apple も一旦あきらめる

Firebase Authentication ではメールログインと Google ログインはとても簡単に実装できます。Firebase が Google 系だからかな、と個人的に思っているのですが、Yahoo と連携させようとしたところ、大変でした。こちらの Firebase の説明によると、

https://firebase.google.com/docs/auth/web/yahoo-oauth?hl=ja

下の Yahoo の説明に従ってやればできる、と書いてありますが、うまくいきませんでした。。。

https://developer.yahoo.com/oauth2/guide/openid_connect/getting_started.html

ということで、Yahoo と連携させるのはあきらめました。

地図パズル製作所ではもともと、メール、Google、Yahoo、Apple の4種類のログイン方式を使うつもりだったのですが、Yahoo はうまくいかず、Apple も Apple Developer Program か何かに登録しないといけない、ということでした。。ということで、Apple もやる気が出なくなったので、一旦あきらめて、後で追加することにしました。「後でやる」ということはたいていやらない私ですが、、、いつかやってみたいと思っています。。。

結局どうなったか

結局 FirebaseUI for Web のライブラリを CDN から取得する、という方法で実装することにしました。loadJS というライブラリで CDN から取得しています。ただ、これもなかなかうまくいきませんでした。始めは loadJs で firebase 関連のライブラリを一度に3つロードしていたのですが、それでは、エラーになる可能性が高いようです。そして、なぜだか、1つずつ、順々にロードしたところエラーがなくなりました。ライブラリに依存関係があるのかもしれませんね。ただ、このソースコード、いまいちきれいじゃないですよね。。

import { EmailAuthProvider, getAuth, GoogleAuthProvider } from "firebase/auth";
import loadJs from "loadjs";
import Head from "next/head";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
import { Alert } from "reactstrap";
import "../utils/InitializeApp";
import Waiting from "./Waiting";

const auth = getAuth();

interface Props {}

const LoginAndSignUp = (props: Props) => {
  const router = useRouter();
  const [displayWaiting, setDisplayWaiting] = useState(true);

  useEffect(() => {
    const redirectUrl =
      router.query.redirectUrl != null
        ? router.query.redirectUrl.toString()
        : "/";
    const uiConfig = {
      callbacks: {
        uiShown: () => {
          // なぜかログインボタンが複数できてしまうことに対応
          const containers = document.getElementsByClassName(
            "firebaseui-container"
          );
          for (let i = 0; i < containers.length; i++) {
            if (i === 0) continue;
            containers[i].remove();
          }
          setDisplayWaiting(false);
        },
      },
      signInSuccessUrl: `/success_login/?redirectUrl=${redirectUrl}`,
      signInFlow: "popup",
      signInOptions: [
        {
          provider: EmailAuthProvider.PROVIDER_ID,
          requireDisplayName: false,
        },
        {
          provider: GoogleAuthProvider.PROVIDER_ID,
          customParameters: {
            // Forces account selection even when one account
            // is available.
            prompt: "select_account",
          },
        },
      ],
    };
    loadJs(
      "https://www.gstatic.com/firebasejs/9.9.1/firebase-app-compat.js",
      () => {
        loadJs(
          "https://www.gstatic.com/firebasejs/9.9.1/firebase-auth-compat.js",
          () => {
            loadJs(
              "https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth__ja.js",
              () => {
                const ui = new (window as any).firebaseui.auth.AuthUI(auth);
                ui.start("#firebaseui-auth-container", uiConfig);
              }
            );
          }
        );
      }
    );
  }, [router]);

  return (
    <React.Fragment>
      <Alert color="danger">
        ログイン・サインアップ時にエラーになることがあるようです。エラーになる場合は
        <a href="#" onClick={() => router.reload()}>
          こちら
        </a>
        を押して画面をリロードしてください。
      </Alert>
      <div className="m-4">
        <Head>
          <link
            type="text/css"
            rel="stylesheet"
            href="https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.css"
          />
        </Head>
        {displayWaiting && <Waiting />}
        <div id="firebaseui-auth-container" />
      </div>
    </React.Fragment>
  );
};

export default LoginAndSignUp;

まとめ

今回は Next.js + Firebase Authentication を使ってログイン機能を実装する方法を紹介しました。間違っていることや、こうしたらいいよ、ということがありましたら、コメントで教えてください。それと、ぜひ、地図パズル製作所にログインして、ランキングに参加してみてくださいね!!

https://chizu-puzzle.com/signup/

Discussion