この記事では、Next.jsのApp RouterとSupabaseでGoogleログインを実装する方法を紹介します。「Auth Helpers for Next.js」が以前まで使われていましたが、現在は@supabase/ssrの使用が推奨されています。
この記事では、公式ドキュメントに沿いながら、フロント/サーバーそれぞれでSupabaseクライアントを使い分ける構成を紹介します。
Next.jsとSupabaseでのGoogle認証ログイン実装の流れ
流れは以下のようになっています。
- Google Cloud PlatformとSupabaseで事前準備
- 必要パッケージのインストール
- Supabaseクライアントの作成
- ログインボタンの実装
- 認証後のコールバック処理(cookie保存)
認証の流れをメインにしたいのでスタイルやページなどは最低限のもので進めます。
Google Cloud PlatformとSupabaseで事前準備
まずはGoogle CloudとSupabaseで事前準備をします。
設定が必要な項目は以下になります。
- Google Cloud Platform
- プロジェクト作成
- APIとサービスからWebアプリケーションの認証情報を作成する
- クライアントIDとクライアントシークレットをSupabase登録用にコピーする
- 承認済みのリダイレクト URIにSupabaseのCallback URLを貼り付ける
- Supabase
- AuthenticationのAuth ProviderからGoogleをEnableに変更する
- クライアントIDとクライアントシークレットをGoogle Cloud Platformでコピーしたものを貼り付ける
- Callback URL (for OAuth)をコピーする
これが設定できれば事前準備は完了です。
必要パッケージのログイン
続いてNext.jsで必要なパッケージをインストールします。
npm install @supabase/supabase-js @supabase/ssr
「@supabase/supabase-js」と「@supaba/ssr」が必要なのでこの2つをインストールします。
続いて、.env.localファイルに以下2つの定数を定義します。
NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key
「NEXT_PUBLIC_SUPABASE_URL」にはプロジェクトのURLを、「NEXT_PUBLIC_SUPABASE_ANON_KEY」にはanon_keyを入れます。
anon_keyはAPI Keysページにあります。

Supabaseクライアントの準備
続いては、Supabaseクライアントの準備をします。
Supabaseクライアントは、クライアント側とサーバー側用に分けて管理するのがApp Router構成では基本となっています。
Next.js(特にApp Router構成)では、クライアントとサーバーの境界が明確に分かれているため、Supabaseの認証やデータ取得も、それぞれの適した環境で処理する必要があります。
クライアント側のSupabaseクライアント作成
まずはクライアント側のsupabaseクライアントを作成します。
/lib/supabase/client.tsファイルを準備します。
'use client'
import { createBrowserClient } from '@supabase/ssr'
export const supabase = createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
ログインやログアウトなど、ユーザーの操作を扱うClient Componentで使用します。
サーバー側のSupabaseクライアント作成
続いてはサーバー側になります。
/lib/supabase/server.tsファイルを準備します。
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {
}
},
},
}
)
}
サーバー上でセッションやユーザー状態を扱うためのクライアントになります。
App Routerの Server Component や Server Action で利用します。
2つのSupabaseクライアントの使い分け
ざっくり2つの使い分けは以下のようになります。
処理 | Supabaseクライアント | 主な利用場所 |
---|---|---|
Googleログイン/OAuth認証開始 | c reateBrowserClient(クライアント用) | Client Component(ブラウザ操作) |
セッション保存(Cookieに記録) | createServerClient(サーバー用) | 認証コールバック後のServer Component |
ログインユーザー取得 | createServerClient | HeaderやDashboardなどのServer Component |
ログアウト処理 | createServerClient | Server ActionやAPI Route |
Supabaseからのデータフェッチ(認証付き) | createServerClient | Server Component(セッションに基づく制限が必要なとき) |
ローカルに保存されたセッションで操作する(例:プロフィール変更) | createBrowserClient | Client Component(ユーザー操作ありのとき) |
Googleログイン処理
続いては先ほど作成したSupabaseクライアントを使って実際にGoogleログイン処理を実装していきます。
ログインボタン
まずはログインボタンを作成します。
'use client'
import { supabase } from '@/lib/supabase/client'
export const LoginButton = () => {
const handleLogin = async () => {
await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: `${location.origin}/auth/callback`,
},
})
}
return <button onClick={handleLogin}>Googleでログイン</button>
}
クライアント側のSupabaseクライアントを使ってOAuth認証を開始します。
認証後は redirectTo に指定したURLに遷移され、Supabaseがアクセストークンを返してくれます。
今回は「${location.origin}/auth/callback」にアクセストークンを返します。
コールバック処理(セッション保存)
ここでサーバー側のSupabaseクライアントを使い、セッションを保存してリダイレクトする処理を書きます。
先ほどリダイレクトURLを「/auth/callback」としているので、「app/auth/callback/route.ts」ファイルを作成し、以下のように記述します。
import { NextResponse } from 'next/server'
import { createClient } from '@/lib/supabase/server'
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url)
const code = searchParams.get('code')
let next = searchParams.get('next') ?? '/'
if (!next.startsWith('/')) {
next = '/'
}
if (code) {
const supabase = await createClient()
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
const forwardedHost = request.headers.get('x-forwarded-host')
const isLocalEnv = process.env.NODE_ENV === 'development'
const redirectUrl = isLocalEnv
? `${origin}${next}`
: forwardedHost
? `https://${forwardedHost}${next}`
: `${origin}${next}`
return NextResponse.redirect(redirectUrl)
}
}
return NextResponse.redirect(`${origin}/auth/auth-code-error`)
}
今度はサーバー側のSupabaseクライアントを使って、セッション情報をcookieに保存しています。
「supabase.auth.exchangeCodeForSession(code)」の箇所が実際に保存している処理です。
そして次のページへリダイレクトさせています。
事前準備含め正常に設定できていれば、cookieが保存された状態でリダイレクト先のページに遷移されるはずです。
おわりに
App Router環境ではクライアントとサーバーでSupabaseクライアントを明確に分けて使う必要があります。@supabase/ssrを使えば、公式が推奨するセッション管理方式に従った安全な実装ができます。
公式ドキュメントも整備されているので、状況に応じてそちらも参照してください。