ログイン機能、まだ自前で作ってるの? Firebase Authenticationで私らが手に入れた「爆速」と「安心」

目次

徹夜でSQLと戦っていた、あの頃の私へ

15年ほど前、私がまだWebエンジニアとして駆け出しだった頃の話です。
あるクライアントから「会員サイトを作りたい」という依頼を受けました。当時の私は、意気揚々とPHPでコードを書き始めました。
データベースを設計し、ユーザーテーブルを作り、パスワードをハッシュ化して保存する。セッション管理のロジックを書き、クッキーの有効期限を設定する。

「よし、これで完璧だ」

そう思ってリリースした数週間後、背筋が凍るようなニュースを目にしました。自分が使っていたフレームワークに、SQLインジェクションの脆弱性が見つかったのです。
慌ててサーバーのログを確認し、パッチを当て、徹夜で全コードを見直しました。幸い被害はありませんでしたが、あの時の「自分の書いた認証コードが、誰かの個人情報を危険に晒すかもしれない」という恐怖は、今でもトラウマのように残っています。

時は流れ、今は2025年。
もし今、同じような会員サイトの依頼が来たら、私は迷わずこう言います。
「認証周りはFirebaseに任せましょう」と。

かつて数週間かけて実装し、その後もセキュリティの不安と戦い続けていた「ログイン機能」が、Firebaseを使えばわずか数時間、慣れれば数十分で実装できてしまう。しかも、Google基準の堅牢なセキュリティで。
これを「魔法」と呼ばずして何と呼ぶでしょうか。

正直に言うと、最初は抵抗がありました。「Googleに依存するのは怖い」「自前でコントロールできないのはエンジニアとしてどうなんだ」と。でも、一度使ってみて考えが180度変わりました。これは手抜きではありません。進化です。

今回は、かつて認証機能の自作に消耗し続けてきた私が、Firebase Authenticationという最強の武器を使って、どのようにWebアプリ(今回はReactを使用)にログイン機能を実装しているのか、その全貌を泥臭い経験談と共に書き残しておきます。
単なるコードの解説ではありません。副業エンジニアとして、クライアントにどう提案し、どう価値を提供するかという「ビジネス視点」も含めた、現場のノウハウを詰め込みました。

これを読み終わる頃には、あなたのエンジニアとしての武器が一つ、確実に増えているはずです。

深夜のオフィスで、過去の自分が書いた大量のPHPコードとセキュリティ警告のエラーログに囲まれ、頭を抱えて絶望している様子の線画イラスト

なぜ「認証」は自前で作ってはいけないのか

技術的な話に入る前に、少しだけ「考え方」の話をさせてください。
なぜ私がここまで強く「自前で作るな」と言うのか。それは、「認証機能は、アプリの本質的な価値ではないが、失敗すると全てを失う」という残酷な事実があるからです。

ユーザーは「ログイン」にお金を払わない

想像してみてください。クライアントがあなたに依頼するのは、「ログインできるアプリ」でしょうか?
違いますよね。「そのアプリを使って何かができること(マッチング、商品購入、業務効率化など)」にお金を払うんです。
ログイン機能なんて、あって当たり前。空気のようなものです。
そこに開発工数の3割も4割も割いていては、肝心の「アプリの価値」を作り込む時間がなくなってしまいます。予算が限られている副業案件なら尚更です。

セキュリティのリスクが大きすぎる

パスワードのハッシュ化アルゴリズムは何を使う? ソルトはどうする? セッションハイジャック対策は? CSRF対策は?
これらを全て、たった一人で、完璧に実装する自信がありますか?
GoogleやMicrosoftの天才エンジニアたちが束になって開発・保守しているセキュリティ基盤と、私たちが夜なべして書いたコード。どちらが安全かは火を見るよりも明らかです。
個人開発や副業において、セキュリティリスクを自前で抱え込むのは、あまりにも割に合いません。何かあった時の責任問題で、人生が狂います。

Firebase Authenticationという「逃げ道」であり「正解」

そこで登場するのが、Firebase Authenticationです。
Googleが提供するBaaS(Backend as a Service)の一部で、認証機能をまるっと代行してくれるサービスです。

  • サーバー構築不要: データベースを用意する必要すらありません。
  • 多様なログイン方法: メール/パスワードはもちろん、Google、Apple、X(旧Twitter)、GitHubなどのSNSログインが、スイッチ一つで有効化できます。
  • 圧倒的な無料枠: 月間アクティブユーザー数(MAU)が5万人までは無料です。個人の副業案件でこのラインを超えることは稀でしょう。つまり、実質タダでGoogleの認証基盤が使えるのです。

これを使わない手はありません。

Firebaseプロジェクトの準備:ここから全てが始まる

では、実際に手を動かしていきましょう。今回は、モダンなWeb開発のスタンダードであるReactを使って実装していきます。
(※FlutterやVue.jsでも基本的な考え方は同じなので、読み替えてください)

Firebase Consoleでの作業

まずは「Firebase Console」にアクセスし、Googleアカウントでログインします。
「プロジェクトを作成」ボタンを押し、適当なプロジェクト名(例: my-auth-app)を入力します。Googleアナリティクスの設定は、今回はオフでも構いません。オンにしてもいいですが、最初はシンプルな方が混乱しません。

プロジェクトができたら、ダッシュボードの左メニューから「構築」→「Authentication」を選びます。ここが認証機能の司令室です。
「始める」ボタンを押すと、ログインプロバイダの選択画面になります。

ズラリと並ぶアイコンたち。
メール/パスワード、電話番号、Google、Game Center…。
かつてこれらを実装するためにAPIドキュメントと格闘していた身からすると、涙が出るほど親切な画面です。「え、これ選ぶだけでいいの?」と拍子抜けするはずです。

まずは基本となる「メール / パスワード」を選択し、「有効にする」のスイッチをONにして保存します。
たったこれだけ。これだけで、裏側ではユーザーデータベースが構築され、パスワードの暗号化ロジックが準備されました。SQLを一文字も書いていません。

ウェブアプリとしての登録

次に、作成したFirebaseプロジェクトに、これから作るReactアプリを登録します。
プロジェクトの概要ページ(家のアイコン)に戻り、</>(ウェブ)のアイコンをクリックします。
アプリのニックネームを入力し、「登録」を押すと、以下のようなコードが表示されます。

const firebaseConfig = {
  apiKey: "AIzaSyB...",
  authDomain: "my-auth-app.firebaseapp.com",
  projectId: "my-auth-app",
  storageBucket: "my-auth-app.appspot.com",
  messagingSenderId: "123456...",
  appId: "1:123456..."
};

これが、あなたのアプリとFirebaseを繋ぐ「鍵」です。このコードは後で使うので、コピーしておきましょう。
(※よく聞かれますが、このAPIキーはブラウザで公開される前提のものなので、盗まれてもデータベースを全消しされるようなことはありません。ただし、後述するセキュリティルールでの制限は必須です)

Firebase Consoleの画面を見ながら、ログイン方法の「メール/パスワード」のスイッチを「ON」に切り替え、その手軽さに驚きと感動を覚えているエンジニアの線画イラスト

Reactプロジェクトの立ち上げとSDKの導入

ここからはエディタ(VS Codeなど)での作業になります。黒い画面(ターミナル)を開く時間です。
Viteなどを使ってサクッとReactプロジェクトを作成しましょう。

npm create vite@latest my-auth-app -- --template react
cd my-auth-app
npm install

Firebase SDKのインストール

続いて、FirebaseをReactで使うためのライブラリ(SDK)をインストールします。

npm install firebase

初期化ファイルの作成

src フォルダの中に firebase.js というファイルを作成し、先ほどコピーした設定コードを貼り付けます。
そして、認証機能を使うための準備を書き加えます。

// src/firebase.js
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  // ...先ほどコピーした内容...
  apiKey: import.meta.env.VITE_FIREBASE_API_KEY, // 環境変数で管理するのがベターです
  // ...
};

// Firebaseアプリの初期化
const app = initializeApp(firebaseConfig);

// Authインスタンスのエクスポート
export const auth = getAuth(app);
export default app;

これで、アプリ全体から auth オブジェクトを使ってFirebaseに命令を送れるようになりました。環境変数を使うのは少し手間ですが、GithubにAPIキーを直接上げないためにも癖をつけておいた方がいいですね。

新規登録(サインアップ)の実装:魔法の関数

いよいよ機能を実装していきます。まずはユーザーを新しく登録する「サインアップ」からです。

フォームの作成

Reactで簡単なフォームを作ります。メールアドレスとパスワードを入力するだけのシンプルなものです。デザインは後回しで、まずは機能です。

import { useState } from "react";
import { createUserWithEmailAndPassword } from "firebase/auth";
import { auth } from "./firebase";

const SignUp = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      await createUserWithEmailAndPassword(auth, email, password);
      alert("登録成功!");
    } catch (error) {
      alert("登録失敗: " + error.message);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <h1>新規登録</h1>
      <input
        type="email"
        placeholder="メールアドレス"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <input
        type="password"
        placeholder="パスワード"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button type="submit">登録</button>
    </form>
  );
};

ポイント:createUserWithEmailAndPassword

見てください、この関数。createUserWithEmailAndPassword。名前が長いですが、やっていることは凄まじいです。
この1行だけで、以下の処理が全て自動で行われます。

  1. メールアドレスの形式チェック
  2. パスワードの強度チェック(デフォルトでは6文字以上)
  3. メールアドレスが既に登録されていないかチェック
  4. パスワードのハッシュ化(ソルト付き)
  5. データベースへの保存
  6. セッションの確立(登録と同時にログイン状態になる)

昔の私なら、これだけの処理を書くのに3日はかかっていたでしょう。バグを出して修正する時間も含めれば1週間コースです。それがたった1行。
エラーハンドリングも優秀で、error.code を見れば「メールアドレスが既に使われている(auth/email-already-in-use)」や「パスワードが弱い(auth/weak-password)」といった具体的な原因が分かります。

ログインとログアウト:これまた一瞬

登録ができたら、次はログインです。といっても、やることは登録とほぼ同じです。

ログイン機能

使う関数が signInWithEmailAndPassword に変わるだけです。

import { signInWithEmailAndPassword } from "firebase/auth";

// ...省略

const handleLogin = async (e) => {
  e.preventDefault();
  try {
    await signInWithEmailAndPassword(auth, email, password);
    alert("ログインしました!");
  } catch (error) {
    alert("ログイン失敗");
  }
};

ログアウト機能

これも signOut 関数を呼ぶだけです。

import { signOut } from "firebase/auth";

const handleLogout = () => {
  signOut(auth).then(() => {
    alert("ログアウトしました");
  }).catch((error) => {
    console.error(error);
  });
};

あまりにあっけなくて、「本当にこれでいいの?」と不安になるレベルです。でも、これでいいんです。

自宅の作業デスクで、Reactのコードを書き進め、シミュレーター上でログイン機能がエラーなく動作した瞬間に、静かにガッツポーズをするエンジニアの線画イラスト

【重要】ログイン状態の監視と維持:初心者がハマる沼

ここからが、初心者が最もつまずきやすいポイントです。
「ログインしたはずなのに、ページをリロードするとログアウトしてしまう」
「ログインしているかどうか、どうやって判定すればいいの?」

Webアプリにおいて、HTTPはステートレス(状態を持たない)なプロトコルです。そのため、Firebase SDKが裏側でよしなにやってくれている「セッション管理」を、React側で正しく受け取る必要があります。ここを理解していないと、挙動不審なアプリが出来上がります。

onAuthStateChanged の魔法

Firebaseには、ログイン状態が変化した時(ログインした、ログアウトした、アプリを起動して初期化が終わった)に、自動で呼び出される監視リスナーが用意されています。それが onAuthStateChanged です。

通常、これは useEffect の中で使います。

import { useEffect, useState } from "react";
import { onAuthStateChanged } from "firebase/auth";
import { auth } from "./firebase";

const App = () => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true); // ロード中かどうか

  useEffect(() => {
    // 監視を開始する
    const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
      setUser(currentUser); // ユーザー情報をStateに保存
      setLoading(false);    // 読み込み完了
    });

    // クリーンアップ関数(コンポーネントが消える時に監視を解除)
    return () => unsubscribe();
  }, []);

  if (loading) {
    return <p>Loading...</p>;
  }

  return (
    <div>
      {user ? (
        <h1>ようこそ、{user.email}さん</h1>
      ) : (
        <h1>ログインしてください</h1>
      )}
    </div>
  );
};

このパターンは、Firebaseを使うReactアプリの鉄板テンプレートです。丸暗記してもいいくらいです。
onAuthStateChanged は、ブラウザのリロード時にもFirebaseのローカルストレージ(IndexedDBなど)を確認し、有効なトークンがあれば自動的にユーザー情報を復元してくれます。
これのおかげで、ユーザーは「リロードしてもログインしたまま」という当たり前の体験を得ることができるのです。

PC画面に表示されたアプリで、ページをリロードしても「ようこそ〇〇さん」という表示が消えないことを確認し、仕組みを理解して深く納得しているエンジニアの線画イラスト

現場の知恵:副業案件で「差がつく」ポイント

ここまでで基本的な機能は完成です。しかし、プロとして納品するにはまだ足りない部分があります。
現場で求められる、そしてクライアントに「おっ、分かってるね」と思わせるプラスアルファの品質についてお話しします。

1. エラーメッセージの日本語化

Firebaseが返すエラーメッセージは英語です。
Firebase: Error (auth/user-not-found).
これをそのまま画面に出したら、ユーザーは逃げ出します。不親切すぎます。
現場では、エラーコードに応じた日本語変換関数を用意するのが常識です。

const getErrorMessage = (errorCode) => {
  switch (errorCode) {
    case "auth/user-not-found":
      return "メールアドレスまたはパスワードが間違っています。";
    case "auth/email-already-in-use":
      return "このメールアドレスは既に使用されています。";
    case "auth/weak-password":
      return "パスワードは6文字以上で入力してください。";
    default:
      return "エラーが発生しました。もう一度お試しください。";
  }
};

こういった細やかな気配りが、クライアントからの信頼に繋がります。「使いやすいですね」と言われるのは、こういうところなんです。

2. Googleログインの実装

メールアドレス入力すら面倒、というユーザーは多いです。
副業案件でも「Googleログインも入れてほしい」と言われる確率は80%を超えます。これもFirebaseなら簡単に追加できます。

  1. Firebase Consoleで「Google」を有効にする。
  2. コードで GoogleAuthProvidersignInWithPopup を使う。
import { GoogleAuthProvider, signInWithPopup } from "firebase/auth";

const handleGoogleLogin = async () => {
  const provider = new GoogleAuthProvider();
  try {
    await signInWithPopup(auth, provider);
  } catch (error) {
    console.error(error);
  }
};

これだけで実装完了です。OAuthの複雑なフローを理解する必要すらありません。これを提案に追加するだけで、見積もりの単価を少し上げることだって可能です。

3. Firestoreセキュリティルールとの連携

ログイン機能を作って終わりではありません。
「ログインした人だけが自分のデータを読み書きできる」という制御が必要です。
FirebaseのデータベースであるFirestoreを使う場合、以下のようなセキュリティルールを設定します。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      // 自分のIDのドキュメントだけ読み書きOK
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

このルール設定まで含めて「認証機能の実装」です。ここまで提案できれば、あなたは単なるコーダーではなく「セキュリティも分かるエンジニア」として評価されます。

オンライン会議の画面越しに、クライアントに対してセキュリティルールの仕組みと安全性を図解を使って丁寧に説明し、信頼を勝ち取っているエンジニアの線画イラスト

よくある質問(FAQ)

Q. Firebaseは本当に無料ですか?
A. ほとんどの場合、無料です。
Authentication(認証)に関しては、無料プラン(Sparkプラン)でも制限が非常に緩く、MAU(月間アクティブユーザー)が5万人を超えるまでは課金されません。ただし、電話番号認証など一部の機能には制限があります。個人開発や初期のスタートアップなら、無料枠を使い切ることの方が難しいでしょう。私も個人開発で課金されたことは一度もありません。

Q. ユーザーデータをCSVでエクスポートできますか?
A. はい、可能ですが少し手間です。
Firebase CLI(コマンドラインツール)を使うか、管理画面の設定からはできませんが、自前で管理画面を作ってAdmin SDKを使えば可能です。案件によっては「管理画面でユーザー一覧を見たい」と言われることがあるので、その場合は別途開発が必要になることを事前に伝えておくとトラブルを防げます。

Q. 本番環境と開発環境はどう分けるべきですか?
A. プロジェクト自体を分けましょう。
my-app-dev(開発用)と my-app-prod(本番用)という2つのFirebaseプロジェクトを作成し、環境変数(.env)でAPIキーを切り替えるのがベストプラクティスです。同じデータベースを使って開発していると、誤って本番データを消してしまうリスクがあります。これは絶対にやっておきましょう。

その「余裕」を、アプリの価値へ

ここまで、Firebase Authenticationを使ったログイン機能の実装について解説してきました。
コード量にしてわずか数十行。
かつて私たちが血眼になって構築していたあの重厚な認証システムは、今やクラウドの向こう側にある巨大なインフラの一部として、APIを叩くだけで利用できるものになりました。

これを「手抜き」と言う人もいるかもしれません。
でも、私はそうは思いません。これは「進化」です。そして、エンジニアに与えられた「時間」というプレゼントです。

認証機能の実装にかかる時間が、3日から3時間に短縮されたとします。
浮いたその2日と21時間を、あなたは何に使いますか?

もっと使いやすいUIを考える時間に充てられるかもしれない。
ユーザーが喜ぶ新機能を一つ追加できるかもしれない。
クライアントのビジネス課題をもっと深くヒアリングできるかもしれない。

Firebaseを使う本当のメリットは、楽ができることではありません。
「エンジニアが、本来向き合うべき『アプリの価値』の創造に集中できる時間を生み出してくれること」です。

副業案件においても同じです。
「ログイン機能の実装に10万円かかります」と言うよりも、
「ログイン機能はFirebaseを使ってコストを抑えましょう。その分、この検索機能をリッチにしませんか?」と提案できるエンジニアの方が、間違いなく市場価値は高いですし、クライアントも喜びます。

私がかつてSQLインジェクションに怯えていたあの夜から、技術は大きく進歩しました。
その恩恵を最大限に受け取り、あなたの作るアプリをもっと素晴らしいものにしてください。

さあ、エディタを開いて、npm install firebase を叩きましょう。
面倒な認証周りは全部Googleに任せて、私たちはもっと楽しい「モノづくり」の世界へ飛び込みましょう。

PCのモニターに表示された管理ダッシュボードのグラフが右肩上がりに伸びており、ユーザー数が順調に増えている様子を確認して、穏やかな達成感を感じながらお茶を飲んでいるエンジニアの線画イラスト

あなたが作ったアプリが、安全な認証基盤の上で、多くのユーザーに愛されるサービスへと育っていくことを心から願っています。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いたエンジニア

新垣 亮のアバター 新垣 亮 Webアプリエンジニア

Webアプリ開発で幅広く活躍するフルスタック寄りのエンジニア。堅実で素早い対応力が魅力。好奇心旺盛で新技術を試すのが好き。周囲を明るくする軽快さがあり、チームコミュニケーションを円滑にする潤滑油的存在。休日はランニングで汗を流す。

目次