Next.js(App Router)×TypeScriptで
FirebaseのAuthenticationを使ってGoogleログイン認証を実装した時の手順。

ちなみに「メール認証」編はこちら👇
目次
前提
- Next.js:プロジェクト作成済み
- Firebase : プロジェクト作成済み
- フォームのUI:実装済み
Firebase AuthenticationでGoogle認証を実装する方法
アプリ追加〜初期化まですでに実施済みの場合は、ログインとログアウト機能を実装するまでスキップ🏃♀️💨
Firebaseでアプリを追加
プロジェクトの設定>全般タブ から「アプリの追加」をクリック。
下記は左から3つ目を選択。(今回はWebアプリなので)

手順通りに進め、上記を実施。
※うろ覚えなので次回実施時に修正するかも。firebase init
含めそれ以降は実施不要。
.env.localに必要情報を記述
上記を行うと下記の値が表示されるので.env.local
に記述する
NEXT_PUBLIC_FIREBASE_API_KEY="xxxxxxx"
FIREBASE_AUTH_DOMAIN="xxxxxxx.firebaseapp.com"
FIREBASE_PROJECT_ID="xxxxxxx"
FIREBASE_STORAGE_BUCKET="xxxxxxx.firebasestorage.app"
FIREBASE_MEASUREMENT_ID="xxxxxxx"
FIREBASE_SENDER_ID="xxxxxxx"
FIREBASE_APP_ID="xxxxxxx"
FIREBASE_API_KEYだけ”NEXT_PUBLIC_”をつけている理由
クライアントサイドでAPI KEYの値が参照できず、下記エラーとなるため。
FirebaseError: Firebase: Error (auth/invalid-api-key).
✍️その他の変数も、クライアントサイドで利用する場合は適宜NEXT_PUBLIC_
を付与する。
✍️ただしNEXT_PUBLIC_
をつけた環境変数はクライアント (ブラウザ) にも送信され、誰でも見れる状態になる。機密情報 (APIキーやDB接続情報など) を含む環境変数には使わないこと。
Firebase を初期化する
service/firebase.js
import { initializeApp } from 'firebase/app';
import { getAuth, signInWithPopup, GoogleAuthProvider, signOut } from "firebase/auth";
import { getFirestore } from 'firebase/firestore';
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
ログインとログアウト機能を実装する
service/firebase.js
に下記を追記
export const auth = getAuth(app);
export const db = getFirestore(app);
export const provider = new GoogleAuthProvider();
export const signInWithGoogle = () => {
signInWithPopup(auth, provider).then((result) => {
console.log(result);
});
};
export const signOutWithGoogle = () => {
auth.signOut();
};
ログインボタンを実装する
components/auth/GoogleLogin.tsx
に下記を記述
※ router.push("/");
でログイン後のリダイレクト先を設定
"use client";
import Image from 'next/image'
import { signInWithGoogle } from '../../service/firebase'
import { useRouter } from 'next/navigation';
function GoogleLogin() {
const router = useRouter();
const handleSignIn = async () => {
await signInWithGoogle();
router.push("/");
};
return (
<button onClick={handleSignIn}>
<Image src={"/img/web_light_rd_SU@2x.png"} alt={"Googleでログインする"} width={358} height={80} />
</button>
)
}
export default GoogleLogin
ログアウトボタンを実装する
components/auth/Logout.tsx に下記を記述
※ router.push("/login");
でログアウト後のリダイレクト先を設定
"use client";
import { signOutWithGoogle } from '@/service/firebase';
import { useRouter } from 'next/navigation';
import React from 'react'
function Logout() {
const router = useRouter();
const handleSignOut = async () => {
await signOutWithGoogle();
router.push("/login");
};
return (
<button onClick={handleSignOut}>ログアウト</button>
)
}
export default Logout
ログイン・ログアウト状態を判定し、表示分けをする
context/AuthContext.tsx
を作成
"use client";
import { createContext, useContext, useEffect, useState } from "react";
import { onAuthStateChanged, User } from "firebase/auth";
import { auth } from "@/service/firebase";
const AuthContext = createContext<{ user: User | null }>({ user: null });
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setUser(user);
});
return () => unsubscribe();
}, []);
return <AuthContext.Provider value={{ user }}>{children}</AuthContext.Provider>;
}
export function useAuth() {
return useContext(AuthContext);
}
全体で↑を利用できるようにする。
下記では、「ログインしているかどうかでクラスの付け替え(containerClassName
)」も合わせて実施している。
"use client"
import { AuthProvider, useAuth } from '@/context/AuthContext';
import React, { ReactNode, useEffect } from 'react'
function LayoutContent({ children }: { children: ReactNode }) {
const { user } = useAuth();
const isLoggedIn = user !== null;
const containerClassName = isLoggedIn ? "login" : "logout";
return (
<div className={containerClassName}>
{children}
</div>
);
}
function AsyncLayout({ children }: { children: ReactNode }) {
return (
<AuthProvider>
<LayoutContent>{children}</LayoutContent>
</AuthProvider>
);
}
export default AsyncLayout
参考:https://firebase.google.com/docs/auth/web/manage-users?hl=ja#get_the_currently_signed-in_user
今のところこんな感じでうまく行っています🤔
以上です!