言語を切り替える
テーマを切り替える

Supabase Auth 実践ガイド:メール認証、OAuth、セッション管理

Supabase Dashboard を開き、Authentication タブをクリックしました。そこで私は立ち止まりました。メール認証、Magic Link、OAuth、SSR 設定… 選択肢が多すぎます。結局どれを使えばいいのでしょう?どう設定すればいいのでしょうか?

同じような疑問を抱えている方もいらっしゃると思います。実は私も、あるプロジェクトにログイン機能を追加した際、半日ほど試行錯誤してやっと分かりました。それぞれの認証方式には、適切な使用シーンがあるのです。この記事では、Supabase Auth の 3 つのコアとなる方式を順に解説します。メール認証、OAuth 連携、そして多くの人が頭を悩ませるセッション管理について。読み終える頃には、30 分程度で完全なユーザー認証システムを構築できるようになるでしょう。

メール認証 — 最も基本的な認証方式

正直なところ、メール認証は Supabase Auth で最もシンプルですが、最も見落とされがちな部分でもあります。

Dashboard を開き、Authentication → Providers → Email に移動すると、「Confirm Email」というスイッチが表示されます。このスイッチは、ユーザー登録後にメール認証が必要かどうかを決定します。ホスト型プロジェクトではデフォルトで有効になっています。つまり、ユーザーは登録後に確認メールを受け取り、リンクをクリックして初めてアカウントが正式に有効化されます。

初めて設定した際、誤ってこのスイッチをオフにしてしまいました。結果はどうなったでしょうか? 適当なメールアドレスを入力するだけでログインでき、スパムアカウントが大量に登録されました。後になって、このスイッチは本番環境で必ず有効にしなければならないことを知りました。

設定コードは実にシンプルです:

// 登録時にメール認証をトリガー
const { data, error } = await supabase.auth.signUp({
  email: '[email protected]',
  password: 'secure-password',
  options: {
    emailRedirectTo: 'https://yourapp.com/auth/callback'
  }
})

ここで重要なのが、emailRedirectTo パラメータです。ユーザーがメール内の確認リンクをクリックすると、このアドレスにリダイレクトされます。アプリのホームページや、専用のウェルカムページを指定できます。

メールテンプレートについて言及すると、Supabase にはいくつかの組み込みテンプレートが用意されています。確認メール、パスワードリセット、Magic Link 用のメールなどです。Dashboard の Email Templates で直接編集できます。Resend や SendGrid などの独自の SMTP サービスを使用したい場合、Auth Hooks で設定可能です。ただし、これは高度な設定なので、入門段階ではデフォルトテンプレートで十分です。

開発環境で直面した問題もあります。ローカル開発環境では、メール認証がスタックすることがあります。これは、Supabase ローカルインスタンスのメールサービスがデフォルトで実際のメールを送信しないためです。Mailcatcher などのツールでテストメールを確認するか、ローカル開発時は一時的に Confirm Email をオフにし、本番リリース前に再度有効にする方法があります。

OAuth 連携 — ワンクリックログインでより便利に

OAuth ログインは、ユーザー体験の観点から革命的です。ユーザーはパスワードを覚える必要がなく、GitHub や Google ボタンをクリックするだけでログインできます。コンバージョン率は、メール登録と比較して大幅に向上することが一般的です。

Supabase がサポートする OAuth プロバイダーは非常に多岐にわたります。GitHub、Google、Facebook、Apple、Azure、Twitter、Discord… 数えてみると 15 種類以上になります。私が最も頻繁に使用するのは GitHub と Google で、この 2 つの設定フローが最も明確だからです。

まず GitHub OAuth から説明します。GitHub で OAuth App を作成する必要があります(Settings → Developer settings → OAuth Apps → New OAuth App)。重要なのは、Callback URL を正しく設定することです:

https://<あなたのプロジェクトref>.supabase.co/auth/v1/callback

ローカル開発時はこれを使用します:

http://localhost:54321/auth/v1/callback

次に、GitHub OAuth App の Client ID と Client Secret を Supabase Dashboard にコピーします(Authentication → Providers → GitHub)。保存後、クライアント側の呼び出しは非常にシンプルです:

// GitHub OAuth ログイン
const { data, error } = await supabase.auth.signInWithOAuth({
  provider: 'github',
  options: {
    redirectTo: 'https://yourapp.com/auth/callback'
  }
})

Google OAuth のフローもほぼ同様ですが、1 つ違いがあります。Google は Web、iOS、Android の 3 つのプラットフォームで Client ID を区別する必要がある点です。アプリが Web とモバイルの両方をサポートする場合、それぞれ個別に設定する必要があります。

ちなみに、OAuth ログイン後、Supabase はプロバイダートークンを提供します。このトークンは、サードパーティ API の呼び出しに使用できます。例えば、GitHub トークンでユーザーのリポジトリ一覧を取得したり、Google トークンで Google Drive にアクセスしたりできます。この機能は、サードパーティサービスとの統合が必要なアプリで特に便利です。

ただし、OAuth にも落とし穴があります。ローカル開発時に callback URL の設定ミスは頻発するエラーです。初めて設定した際、ポートを 3000(フロントエンドのポート)に設定してしまいました。ログイン後にページがエラーになりました。後で分かったのですが、callback はフロントエンドのポートではなく、Supabase のポートを指す必要があります。

セッション管理 — JWT と PKCE フロー

この章は、最も混乱しやすい部分かもしれません。正直なところ、私も当初は JWT、リフレッシュトークン、PKCE といった概念がどのように連携しているのか完全に理解していませんでした。

Supabase のセッションは、2 つの部分で構成されています。アクセストークン(短期 JWT)とリフレッシュトークン(長期トークン)です。アクセストークンのデフォルトの有効期間は 1 時間です。公式では最低 5 分以下にしないことを推奨しています。クロックドリフト(時刻のズレ)の問題を考慮する必要があるからです。リフレッシュトークンは 1 回のみ使用可能で、新しいアクセストークンと交換するために使用します。

ここで重要なディテールがあります。リフレッシュトークンには 10 秒間の再利用ウィンドウがあります。どういうことかというと、SSR 環境で複数のリクエストが同時にトークンを更新しようとした場合、Supabase は 10 秒以内の重複更新操作を許可し、セッションが予期せず終了することを防ぎます。フロントエンドとバックエンドが同時にセッションを操作する状況はよくあるため、この設計は合理的です。

PKCE について説明します。Next.js やその他の SSR フレームワークを使用する場合、PKCE フローの設定は必須です。なぜでしょうか? 暗黙的フロー(Implicit Flow)はトークンを URL に直接露出させるため、SSR 環境では安全ではありません。PKCE は、コードベリファイア(code verifier)を使用してトークン交換プロセスを保護します。

PKCE を設定するには、クライアントの初期化時に 2 つのパラメータを追加します:

import { createClient } from '@supabase/supabase-js'

const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
  auth: {
    detectSessionInUrl: true,
    flowType: 'pkce'
  }
})

次に、コード交換を処理するための callback ルートが必要です:

// Next.js App Router - app/auth/callback/route.ts
import { NextResponse } from 'next/server'
import { createClient } from '@/utils/supabase/server'

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url)
  const code = searchParams.get('code')

  if (code) {
    const supabase = await createClient()
    const { error } = await supabase.auth.exchangeCodeForSession(code)
    if (!error) {
      return NextResponse.redirect(`${origin}/dashboard`)
    }
  }
  return NextResponse.redirect(`${origin}/auth/error`)
}

ここで、認証コード(auth code)は 5 分間のみ有効で、1 回しか使用できません。デバッグ時にコード交換が失敗する場合、タイムアウトか再使用が原因である可能性が高いです。

Supabase はさらに 3 つのセッション制限モードをサポートしています。タイムボックス(Time-boxed、固定時間後に強制期限切れ)、非アクティブタイムアウト(Inactivity timeout、長時間操作がないと期限切れ)、シングルセッションモード(Single session per user、1 アカウントで 1 つのアクティブセッションのみ)。これらのモードは、SOC 2 や HIPAA コンプライアンスが必要なアプリで特に有用です。

実践的なアドバイスとよくある質問

ここまで説明してきましたが、結局どの認証方式を選ぶべきなのでしょうか?

シンプルに言うと、メール認証はユーザー情報が必要な登録フローに適しています。例えば、ユーザーが詳細なプロフィールを入力する必要がある場合など。OAuth は手軽なログインを重視するシーンに適しています。開発者ツールや B2B アプリなど。Magic Link はパスワードレスシーンに適しています。一時的なアクセスやモバイルファーストのアプリなど。

3 つの方式の比較:

方式適用シーンメリットデメリット
メール認証正式な登録フロー情報が完整、管理しやすいユーザーがパスワードを覚える必要がある
OAuth手軽なログインパスワード不要、コンバージョン率高いサードパーティサービスの安定性に依存
Magic Linkパスワードレスシーン安全、シンプル毎回メールを確認する必要がある

Next.js やその他の SSR フレームワークを使用する場合、以下の設定チェックリストを確認してください:

  1. detectSessionInUrl: true — Supabase が URL からセッションを自動的に抽出
  2. flowType: 'pkce' — PKCE フローを強制使用
  3. redirectTo の正しい設定 — callback ルートが認証コードを正しく処理
  4. 環境変数の確認 — NEXT_PUBLIC_SUPABASE_URL と NEXT_PUBLIC_SUPABASE_ANON_KEY が正しく設定されている

最後に、よくある質問をいくつか紹介します:

Q: なぜローカル開発で OAuth が常に失敗するのか?

おそらく、callback URL の設定ミスです。Supabase Dashboard のプロバイダー設定を確認し、localhost アドレスを使用していること、本番環境のドメインではないことを確認してください。

Q: JWT が期限切れ後、ユーザーが強制ログアウトされる?

クライアントに自動更新メカニズムがあることを確認してください。Supabase の onAuthStateChange リスナーはトークンの自動更新を処理するため、手動で更新ロジックを書く必要はありません。

Q: セッションが突然消える場合は?

SSR 環境でよくある問題です。サーバークライアントとブラウザクライアントが正しく初期化されているか、特に Cookie の受け渡しが正常か確認してください。

まとめ

Supabase Auth の 3 つの認証方式には、それぞれ用途があります。メール認証は基本で、正式な登録フローに適しています。OAuth はユーザー体験を向上させ、手軽なログインを重視するシーンに適しています。セッション管理は基盤となる部分で、JWT と PKCE フローを理解することで、SSR 環境で正しく設定できます。

私が以前踏んだ落とし穴は、実はシンプルなものでした。callback URL の設定ミス、confirm email スイッチのオン忘れ、PKCE フローの未設定。これらのディテールを明確にすれば、認証システムは安定して動作します。

次のステップとして、Auth の設定が完了したら、Row Level Security(RLS)でデータを保護することを忘れないでください。Supabase の RLS と Auth は密接に連携しており、各ユーザーは自分のデータのみにアクセスできます。これが認証システムの完全なクローズドループです。

Supabase Auth 完全設定フロー

メール認証から OAuth 連携、SSR 環境の PKCE 設定まで

⏱️ 目安時間: 30 分

  1. 1

    ステップ1: メール認証を有効化

    Supabase Dashboard で操作:

    • Authentication → Providers → Email に移動
    • Confirm Email スイッチをオン
    • emailRedirectTo パラメータをアプリのコールバックアドレスに設定
    • ローカル開発時は Mailcatcher でテストメールを確認
  2. 2

    ステップ2: GitHub OAuth を設定

    GitHub と Supabase 間で OAuth 接続を確立:

    • GitHub で OAuth App を作成(Settings → Developer settings → OAuth Apps)
    • Callback URL に設定:https://&lt;ref&gt;.supabase.co/auth/v1/callback
    • ローカル開発用:http://localhost:54321/auth/v1/callback
    • Client ID と Client Secret を Supabase Dashboard にコピー
  3. 3

    ステップ3: PKCE フローを設定

    SSR 環境(Next.js)用の安全な認証フロー:

    • クライアント初期化時に flowType: 'pkce' を設定
    • detectSessionInUrl: true を有効化
    • /auth/callback ルートを作成してコード交換を処理
    • 認証コードは 5 分間有効、1 回のみ使用可能
  4. 4

    ステップ4: セッション更新を処理

    セッションを継続的に有効にする:

    • アクセストークンはデフォルトで 1 時間で期限切れ
    • リフレッシュトークンは 1 回のみ使用可能、10 秒再利用ウィンドウ
    • クライアントで onAuthStateChange をリッスンして自動更新
    • SSR 環境では Cookie の正しい受け渡しを確認

FAQ

Supabase Auth はどの OAuth プロバイダーをサポートしていますか?
15 種類以上をサポートしています。GitHub、Google、Facebook、Apple、Azure、Twitter、Discord、GitLab、Bitbucket、LinkedIn、Twitch、Spotify、Slack、Notion など。最も一般的に使用されるのは GitHub と Google です。
JWT アクセストークンのデフォルトの有効期限は?
デフォルトで 1 時間です。公式では最低 5 分以下にしないことを推奨しています(クロックドリフトを考慮)。Dashboard で調整可能。リフレッシュトークンは 1 回のみ使用可能で、新しいアクセストークンと交換するために使用します。
なぜ SSR 環境で PKCE フローが必須なのか?
暗黙的フロー(Implicit Flow)はトークンを URL に露出させるため、SSR 環境では安全ではありません。PKCE はコードベリファイアでトークン交換を保護し、認証コードは 5 分で期限切れ、1 回のみ交換可能です。
ローカル開発で OAuth callback が常に失敗する場合は?
3 点を確認:1) Supabase Dashboard のプロバイダー設定で callback URL が localhost を使用しているか、2) ポート番号が正しいか(Supabase ローカルポートは 54321)、3) フロントエンドのポート(例:3000)ではないか。
リフレッシュトークン再利用ウィンドウとは?
10 秒間のウィンドウで、SSR シーンで複数のリクエストが同時に更新を行いセッションが終了するのを防ぎます。フロントエンドとバックエンドが同時にセッションを操作する場合、10 秒以内の重複更新操作を許可します。
3 つの認証方式はどう選ぶべきか?
メール認証は正式な登録フロー向け(完全なユーザー情報が必要)、OAuth は手軽なログインシーン向け(開発者ツール、B2B アプリ)、Magic Link はパスワードレスシーン向け(一時的なアクセス、モバイルファースト)。

5 min read · 公開日: 2026年4月8日 · 更新日: 2026年4月8日

コメント

GitHubアカウントでログインしてコメントできます

関連記事