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

Supabase Auth 実践:メール認証・OAuth・セッション管理

Supabase Dashboard を開いて、Authentication の項目に入った瞬間、私は固まってしまいました。メール認証、Magic Link、OAuth、SSR の設定……選択肢が多すぎます。結局どれを使えばいいのか、どう設定すればいいのか。

あなたも同じように迷っているなら、慌てなくて大丈夫です。以前、小さなプロジェクトにログイン機能を追加したとき、半日も格闘してようやく気づきました——認証方式にはそれぞれ向いている場面があるのです。この記事では、Supabase Auth の 3 つのコア方式をひとつにつなげて解説します。メール認証、OAuth 連携、そして多くの人を悩ませるセッション管理です。読み終えれば、30 分ほどで完全なユーザー認証システムを構築できるようになるはずです。

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

正直に言うと、メール認証は Supabase Auth の中で最もシンプルでありながら、最も見落とされやすい部分です。

Dashboard を開き、Authentication → Providers → Email を見つけると、「Confirm Email」というスイッチがあります。このスイッチは、ユーザーが登録後にメールを認証しないとログインできないかどうかを決めます。Hosted プロジェクトではデフォルトで有効になっており、ユーザーは登録後に認証メールを受け取り、リンクをクリックして初めてアカウントが正式に有効になります。

私は最初に設定したとき、うっかりこれをオフにしてしまいました。その結果どうなったか。適当なメールアドレスでもログインでき、迷惑アカウントが大量に作られてしまったのです。あとから、このスイッチは本番環境では必ずオンにすべきだと分かりました。

設定コードは実はとても簡単です。

// 登録時にメール認証をトリガー
const { data, error } = await supabase.auth.signUp({
  email: 'user@example.com',
  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 Provider はたくさんあります。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 のフローもほぼ同じですが、ひとつ違いがあります。Google では Web、iOS、Android の 3 つのプラットフォームの Client ID を区別する必要があるのです。アプリが Web とモバイルの両方に対応するなら、それぞれ設定しなければなりません。

そういえば、OAuth ログイン後に Supabase は provider token を返してくれます。この token を使えばサードパーティの API を呼び出せます。たとえば GitHub token でユーザーのリポジトリ一覧を取得したり、Google token で Google Drive にアクセスしたりできます。この機能は、サードパーティサービスと連携したいアプリでとても役立ちます。

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

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

この章は、おそらく最も混乱しやすい部分です。正直なところ、私も最初は JWT、refresh token、PKCE といった概念がどう連携して動くのか、完全には理解していませんでした。

Supabase のセッションは 2 つの部分から成ります。access token(短命の JWT)と refresh token(長命のトークン)です。access token のデフォルトの有効期限は 1 時間で、公式は最低でも 5 分を下回らないよう推奨しています——時計のずれの問題を考慮する必要があるからです。refresh token は 1 回限りの使用で、新しい access token と交換するために使います。

ここで重要な細かいポイントがあります。refresh token には 10 秒の再利用ウィンドウがあるのです。どういう意味かというと、SSR 環境で複数のリクエストが同時に token を更新しようとした場合、Supabase は 10 秒以内の重複した更新操作を許可し、セッションが予期せず終了しないようにします。フロントエンドとバックエンドが同時に session を操作する状況はよくあるので、この設計はなかなか理にかなっています。

次に PKCE です。Next.js やその他の SSR フレームワークを使うなら、PKCE フローは必須の設定です。なぜでしょうか。Implicit flow は token を URL に直接露出させてしまい、SSR 環境ではこれが非常に危険だからです。PKCE は code verifier によって token 交換のプロセスを保護します。

PKCE の設定では、クライアントの初期化時に 2 つのパラメータを加える必要があります。

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

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

そして、code 交換を処理する callback route が必要です。

// 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 回だけです。デバッグ中に code 交換が失敗するときは、たいていタイムアウトか、重複して使ってしまったのが原因です。

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 から session を自動抽出させる
  2. flowType: 'pkce' — PKCE フローを強制する
  3. redirectTo を正しく設定 — callback route が auth code を正しく処理できるようにする
  4. 環境変数の確認 — NEXT_PUBLIC_SUPABASE_URL と NEXT_PUBLIC_SUPABASE_ANON_KEY が両方とも設定されているか確認

最後に、よくある質問をいくつか挙げます。

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

おそらく callback URL の設定ミスです。Supabase Dashboard の Provider の callback 設定を確認し、本番環境のドメインではなく localhost アドレスになっているか確かめましょう。

Q: JWT が失効するとユーザーが強制ログアウトされる?

クライアントに自動更新の仕組みがあることを確認しましょう。Supabase の onAuthStateChange リスナーが token の更新を自動的に処理してくれるので、更新ロジックを手書きする必要はありません。

Q: セッションが突然消えてしまったら?

SSR 環境ではこの問題はよく起こります。server client と browser client が両方とも正しく初期化されているか、特に cookies の受け渡しが正常か確認しましょう。

まとめ

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 ルートを作成して code 交換を処理
    • auth code の有効期限は 5 分、1 回だけ使用可能
  4. 4

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

    セッションを継続的に有効に保つ:

    • access token はデフォルトで 1 時間で失効
    • refresh token は 1 回限りの使用、10 秒の再利用ウィンドウあり
    • クライアントは onAuthStateChange を監視して自動更新
    • SSR 環境では cookies が正しく渡されることを確認

FAQ

Supabase Auth はどの OAuth Provider に対応していますか?
GitHub、Google、Facebook、Apple、Azure、Twitter、Discord、GitLab、Bitbucket、LinkedIn、Twitch、Spotify、Slack、Notion など 15 種類以上に対応しています。最もよく使われるのは GitHub と Google です。
JWT access token のデフォルトの有効期限はどれくらいですか?
デフォルトは 1 時間です。公式は時計のずれを考慮して最低でも 5 分を下回らないよう推奨しています。Dashboard から調整できます。refresh token は 1 回限りの使用で、新しい access token と交換するために使います。
なぜ SSR 環境では PKCE フローが必須なのですか?
Implicit flow は token を URL に露出させるため、SSR 環境では安全ではありません。PKCE は code verifier によって token 交換を保護します。auth code は 5 分で失効し、交換できるのは 1 回だけです。
ローカル開発で OAuth の callback が必ず失敗するときは?
3 点を確認しましょう。1) Supabase Dashboard の Provider の callback URL が localhost になっているか。2) ポート番号が正しいか(Supabase のローカルポートは 54321)。3) フロントエンドのポート(3000 など)になっていないか。
refresh token の再利用ウィンドウとは何ですか?
10 秒のウィンドウのことです。SSR 環境で複数のリクエストが同時に更新を行い、セッションが終了してしまうのを防ぎます。フロントエンドとバックエンドが同時に session を操作する場合、10 秒以内の重複した更新操作が許可されます。
3 つの認証方式はどう選べばよいですか?
メール認証は正式な登録フロー(完全なユーザー情報が必要な場合)に向いています。OAuth は素早いログイン(開発者ツール、B2B アプリ)に向いています。Magic Link はパスワードレスの場面(一時的なアクセス、モバイル優先)に向いています。

4分で読めます · 公開日: 2026年4月8日 · 更新日: 2026年6月8日

関連記事

コメント

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