Nuxt

Nuxt + Firebase 入門① メール/パスワードでログイン機能を作る

Nuxt + Firebase 入門① メール/パスワード認証でログイン機能を作る

Nuxt4 と Firebase Authentication を使って 「メールアドレスとパスワードでログインできる仕組み」を最短で実装する手順をまとめました。 Firebase プロジェクト作成済みを前提に、

  • Firebase Auth の有効化
  • Nuxt 側の設定
  • ログイン画面の実装
  • ログイン状態の監視

までを コピペで動く形 で紹介します。

Firebase Authentication の設定

まずは Firebase コンソール側で、メール/パスワード 認証を有効化しておきます。

手順はシンプルです。
ここはスクリーンショットを見ながら進めればすぐ終わると思います。

  1. Firebase コンソールのAuthentication を開く
  2. ログイン方法を開き、「メール/パスワード」を有効にする
  3. Firebase の設定値の確認方法
  4. テスト用ユーザーを作成しておく

1. Authentication を開く

2 .ログイン方法を開き、「メール/パスワード」を有効にする

3. Firebase の設定値の確認方法

ログイン方法を設定したらNuxtとの連携のため、Firebase SDKの設定値を確認しておきましょう。
「設定」→「全般」→「マイアプリ」より確認できます。

4. テストユーザーを登録しておく

ログインテスト用にテスト用のユーザー情報を作成しておきます。
「Authentication」→「ユーザー」→「ユーザーを追加」より、テストユーザーを追加します。

Authenticationのユーザー追加

Nuxt 側に Firebase SDK を追加する

Nuxt 側では、まず Firebase の JavaScript SDK を npm で追加します。
Firebase の公式セットアップでも、Web アプリでは npm で firebase パッケージを入れる流れが案内されています。

npm install firebase

Firebase の設定を Nuxt で管理する

Firebase の設定値は .env に書き、Nuxt 側では runtimeConfig.public から使う形にしました。

まず、プロジェクト直下に .env ファイルを新規作成します。
すでにある場合は、その中に Firebase の設定値を追加します。

.env

NUXT_PUBLIC_FIREBASE_API_KEY=xxxxx
NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN=xxxxx.firebaseapp.com
NUXT_PUBLIC_FIREBASE_PROJECT_ID=xxxxx
NUXT_PUBLIC_FIREBASE_STORAGE_BUCKET=xxxxx.firebasestorage.app
NUXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=xxxxx
NUXT_PUBLIC_FIREBASE_APP_ID=xxxxx

xxxxx の部分は、Firebase Console に表示される自分の設定値に置き換えてください。

次に、nuxt.config.tsruntimeConfig.public に渡します。

nuxt.config.ts

export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      firebaseApiKey: process.env.NUXT_PUBLIC_FIREBASE_API_KEY,
      firebaseAuthDomain: process.env.NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
      firebaseProjectId: process.env.NUXT_PUBLIC_FIREBASE_PROJECT_ID,
      firebaseStorageBucket: process.env.NUXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
      firebaseMessagingSenderId: process.env.NUXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
      firebaseAppId: process.env.NUXT_PUBLIC_FIREBASE_APP_ID,
    },
  },
})

nuxt.config.ts は Nuxt 全体の設定を書くファイルです。
runtimeConfig はアプリ内で使う設定値の置き場で、runtimeConfig.public の値はブラウザ側からも利用でき、useRuntimeConfig() で参照できます。


Firebase 初期化用ファイルを作る

Firebase の初期化は app/utils/firebase.ts にまとめました。

app/utils/firebase.ts

import { initializeApp, getApps, getApp } from 'firebase/app'

export const getFirebaseApp = () => {
  const config = useRuntimeConfig()

  const firebaseConfig = {
    apiKey: config.public.firebaseApiKey,
    authDomain: config.public.firebaseAuthDomain,
    projectId: config.public.firebaseProjectId,
    storageBucket: config.public.firebaseStorageBucket,
    messagingSenderId: config.public.firebaseMessagingSenderId,
    appId: config.public.firebaseAppId,
  }

  // getApps() が空なら initializeApp()、既に初期化済みなら getApp()
  // → Nuxt の HMR や複数コンポーネントで初期化が二重になるのを防ぐため
  return getApps().length ? getApp() : initializeApp(firebaseConfig)
}

getFirebaseApp() は、Firebase の初期化済み app を返すための共通関数です。
今後、Authentication だけでなく Firestore など他の Firebase 機能を使うときも、この関数を入口として使えます。

今回は initializeApp() で Firebase を初期化しつつ、すでに初期化済みの場合は getApps()getApp() で既存の app を返すようにしています。
こうしておくことで、同じアプリを何度も初期化してしまうのを防げます。


ログイン画面を作る

次に、メール/パスワード でログインできる画面を作ります。
今回作成するログイン画面の動作をご紹介します。

ログイン画面機能紹介

nuxtで作成したログイン画面

Firebaseコンソールで追加したユーザー情報を入力し、ログインボタンを押すことによって、ログイン成功の表示となります。

ログイン後は、ログイン済みメッセージとユーザー情報を表示するようにしました。
現段階ではユーザー名は設定されてないため、「未設定」と表示されています。
合わせて、ログアウトボタンも付けています。

nuxtで作成したログイン成功画面

それ以外のユーザー情報では「ログインに失敗しました」と表示されます。

ログイン画面コード

ログイン画面のコードを全てご紹介します。
ある程度スタイルも整えているためCSSなども含め全て記載しております。

今回のログイン画面では、入力値・エラーメッセージ・送信中状態・ログイン中ユーザーを ref で管理しています。

特に currentUser は、現在ログインしているユーザー情報を入れておくための値です。
ログイン中ならユーザー情報、未ログインなら null が入ります。

<script setup lang="ts">

import {
  getAuth,
  signInWithEmailAndPassword,
  signOut,
  onAuthStateChanged,
  type User,
} from "firebase/auth";


const email = ref("");
const password = ref("");
const errorMessage = ref("");
const loading = ref(false);
const currentUser = ref<User | null>(null);

const app = getFirebaseApp();
const auth = getAuth(app);

onMounted(() => {
  onAuthStateChanged(auth, (user) => {
    currentUser.value = user;
  });
});

const login = async () => {
  errorMessage.value = "";
  loading.value = true;

  try {
    await signInWithEmailAndPassword(auth, email.value, password.value);
  } catch (error) {
    console.error(error);
    errorMessage.value = "ログインに失敗しました";
  } finally {
    loading.value = false;
  }
};

const logout = async () => {
  errorMessage.value = "";
  try {
    await signOut(auth);
  } catch (error) {
    console.error(error);
    errorMessage.value = "ログアウトに失敗しました";
  }
};
</script>
<template>
  <div class="page">
    <div class="card">
      <h1 class="title">Firebase ログイン</h1>
      <p class="subtitle">メールアドレスとパスワードでログインします</p>

      <div v-if="currentUser" class="user-box">
        <p class="success">ログインしました</p>
        <p class="user-text">
          ユーザー名:
          <span>{{ currentUser.displayName || "未設定" }}</span>
        </p>
        <p class="user-text">
          メールアドレス:
          <span>{{ currentUser.email }}</span>
        </p>

        <button class="button logout-button" @click="logout">
          ログアウト
        </button>
      </div>

      <form v-else class="form" @submit.prevent="login">
        <div class="form-group">
          <label for="email">メールアドレス</label>
          <input
            id="email"
            v-model="email"
            type="email"
            placeholder="example@test.com"
          />
        </div>

        <div class="form-group">
          <label for="password">パスワード</label>
          <input
            id="password"
            v-model="password"
            type="password"
            placeholder="パスワードを入力"
          />
        </div>

        <button class="button login-button" type="submit" :disabled="loading">
          {{ loading ? "ログイン中..." : "ログイン" }}
        </button>
      </form>
<p v-if="!currentUser" class="footer-text">
  アカウントをお持ちでない方は
  <NuxtLink to="/signup" class="footer-link">新規登録はこちら</NuxtLink>
</p>
      <p v-if="errorMessage" class="error-message">{{ errorMessage }}</p>
    </div>
  </div>
</template>
<style scoped>
.page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f5f7fb;
  padding: 24px;
}

.card {
  width: 100%;
  max-width: 420px;
  background: #ffffff;
  border-radius: 16px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
  padding: 32px;
}

.title {
  margin: 0 0 8px;
  font-size: 28px;
  font-weight: 700;
  text-align: center;
  color: #222;
}

.subtitle {
  margin: 0 0 24px;
  text-align: center;
  color: #666;
  font-size: 14px;
}

.form {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.form-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.form-group label {
  font-size: 14px;
  font-weight: 600;
  color: #333;
}

.form-group input {
  padding: 12px 14px;
  border: 1px solid #d8dee9;
  border-radius: 10px;
  font-size: 14px;
  outline: none;
  transition: 0.2s;
}

.form-group input:focus {
  border-color: #4f46e5;
  box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.12);
}

.button {
  width: 100%;
  border: none;
  border-radius: 10px;
  padding: 12px 16px;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  transition: 0.2s;
}

.button:disabled {
  opacity: 0.7;
  cursor: not-allowed;
}

.login-button {
  background: #4f46e5;
  color: white;
}

.login-button:hover {
  background: #4338ca;
}

.logout-button {
  margin-top: 16px;
  background: #ef4444;
  color: white;
}

.logout-button:hover {
  background: #dc2626;
}

.user-box {
  background: #f8fafc;
  border: 1px solid #e5e7eb;
  border-radius: 12px;
  padding: 20px;
}

.success {
  margin: 0 0 16px;
  color: #16a34a;
  font-weight: 700;
  font-size: 16px;
}

.user-text {
  margin: 8px 0;
  color: #333;
}

.user-text span {
  font-weight: 600;
}

.error-message {
  margin-top: 16px;
  color: #dc2626;
  font-size: 14px;
  text-align: center;
}
</style>

onAuthStateChanged() でログイン状態を監視する

onAuthStateChanged() は、Firebase Authentication のログイン状態の変化を監視する関数です。

ページを開いたときや、ログイン・ログアウトしたときに呼ばれ、ログイン中なら user、未ログインなら null が返ります。
今回はその値を currentUser に入れることで、ログインフォームとログイン後の表示を切り替えています。

onMounted(() => {
  onAuthStateChanged(auth, (user) => {
    currentUser.value = user;
  });
});

signInWithEmailAndPassword

signInWithEmailAndPassword() は、メール/パスワード 認証でログインするための関数です。

第1引数には Firebase Authentication のインスタンス、
第2引数にはメールアドレス、
第3引数にはパスワードを渡します。

今回は、入力欄で受け取った email.valuepassword.value を使ってログインしています。

await signInWithEmailAndPassword(auth, email.value, password.value);

ログイン後の表示

ログイン後は、ログイン済みメッセージとユーザー情報を表示するようにしました。
合わせて、ログアウトボタンも付けています。

currentUser には、Firebase Authentication が持っているユーザー情報が入ります。
たとえば emaildisplayName などを参照できます。

ただし、メール/パスワード 認証でユーザーを作成した直後は displayName が未設定のことも多いため、今回はメールアドレスも一緒に表示するようにしました。


次にやること

今回は、Nuxt で Firebase Authentication を使った メール/パスワード ログイン の基本実装までをまとめました。

次回以降は、認証機能をもう少し広げて、以下のようなところを追加していく予定です。

  • 新規登録
  • パスワードリセット
  • プロフィール表示
  • displayName の更新

そのあとで、Firestore を使ったデータ保存や一覧取得にも進めていこうと思います。

【完全無料】独学で挫折しかけたら、0円で“質問できる環境”を試そう。

独学だと、調べても解決できず手が止まる瞬間があります。
私も実際に登録して、カリキュラム内容と質問導線を一通り試しました。
0円で試せる学習環境を、メリット・注意点込みでレビューにまとめています。

✅ 調べても解決せず、学習が止まりがち
✅ 質問できる相手がいなくて不安
✅ 何から手を付けるべきか迷う
✅ 0円で質問できる環境を試してみたい

体験レビューを読む(無料の理由・注意点も)

まずは雰囲気を知りたい人向けに、体験レビューを用意しました。

-Nuxt
-