もうログインシステムを一から作るのはやめよう!

フルスタックプロジェクトでNode.jsを使って会員登録・ログインシステムを自作したことがあるなら、その苦労はよくわかるはずです。 パスワードにソルトを加えてbcryptでハッシュ化したり、JWTトークンを発行したり、トークンの有効期限やリフレッシュトークンの処理、「パスワード忘れ」時のメール送信ロジックの実装... さらに面倒なOAuth(Google/GitHubログイン)も考慮しなければなりません。 しかも一箇所でも間違えると、システムの会員データがハッカーに丸ごと盗まれる可能性があります。

2026年の現代的なフルスタック開発では、プロのエンジニアは車輪の再発明をしません。私たちはBASS(Backend as a Service)を利用します。そしてSupabaseこそが、Vibe Tutorが選び抜いた最強の脳なのです。


なぜSupabaseを選ぶのか?

多くの人がFirebaseと比較します。Firebaseも便利ですが、その基盤はNoSQLデータベースです。私たちのように「会員」と「複数の注文」を厳密に関連付ける必要があるEC/知識課金システムにとって、リレーショナルデータベース(RDBMS)の方が確実に安全な選択です。 Supabaseの基盤は世界最強のオープンソースRDBMSであるPostgreSQLです。超高速なAPIを提供するだけでなく、完璧なAuth(認証)システムも内蔵しています。

Next.js 15でのSupabase Auth実装

Next.jsのApp Routerアーキテクチャでは、環境がサーバーサイドとクライアントサイドに分離されているため、両方に対応する2種類のSupabase Clientを準備する必要があります。 これらはすべて、私たちのプロジェクトのsrc/utils/supabase/フォルダ内に設定済みです。

1. client.ts(フロントエンドブラウザ用)

これは主に"use client"があるコンポーネント(例えばログインフォームコンポーネント)で使用します。

import { createBrowserClient } from '@supabase/ssr'

export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  )
}

2. server.ts(バックエンドサーバー用)

これはServer ComponentsやAPI Routesで使用し、ユーザーの認証を行います。Cookieの読み書きを処理する必要があります。

import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'

export async function createClient() {
  const cookieStore = await 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 (error) {
            // Server Componentでは直接Cookieを設定できない場合があるため、例外を捕捉
          }
        },
      },
    }
  )
}

メールマジックリンク(Magic Link)ログイン実践

Vibe Tutorのログインページ(src/app/login/page.tsx)では、現在最も流行している摩擦のないMagic Linkログイン方式を採用しています。 ユーザーはパスワードを設定・記憶する必要があ���ません。メールアドレスを入力するだけで、システムが安全なリンク付きのメールを送信し、クリックすれば即座にログインできます。

ログイン処理のコアロジックを見てみましょう:

"use client";
import { createClient } from "@/utils/supabase/client";

const handleLogin = async (e) => {
  e.preventDefault();
  
  const supabase = createClient();
  
  // SupabaseのsignInWithOtpメソッドを呼び出してマジックリンクを送信
  const { error } = await supabase.auth.signInWithOtp({
    email,
    options: {
      // ログイン成功後、会員センターにリダイレクト
      emailRedirectTo: `${location.origin}/auth/callback?next=/dashboard`,
    },
  });

  if (error) {
    alert("メール送信に失敗しました。しばらくしてから再試行してください。");
  } else {
    alert("マジックリンクをメールで送信しました!メールを確認してください。");
  }
};

たったこれだけ!SMTPサーバーの設定など一切不要で、Supabaseが内部ですべて処理してくれます。

Authコールバック処理メカニズム

ユーザーがメール内のマジックリンク(https://あなたのサイト.com/auth/callback?code=xxxのようなURL)をクリックすると、 src/app/auth/callback/route.tsというAPI Routeでこれをインターセプトし、URLのcodeを実際のログイン認証情報(Session Cookie)と交換する必要があります。

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')
  const next = searchParams.get('next') ?? '/dashboard' // デフォルトは会員センターへ

  if (code) {
    const supabase = await createClient()
    
    // codeをユーザーのログインセッションと交換
    const { error } = await supabase.auth.exchangeCodeForSession(code)
    
    if (!error) {
      return NextResponse.redirect(`${origin}${next}`)
    }
  }

  // 認証失敗時の処理
  return NextResponse.redirect(`${origin}/login?error=InvalidToken`)
}

この交換プロセスが完了すると、ブラウザにはHttpOnly属性を持つ安全なCookieが書き込まれます。 これ以降、ユーザーがどのページを閲覧しても、サーバーサイドでawait supabase.auth.getUser()を呼び出すだけで瞬時に誰なのかを識別し、その注文権限を読み取ることができます。

強力でエレガントなSupabase認証をマスターしたところで、次はシステムの核心であるPostgreSQLデータベース設計に進み、神秘的なvt_purchases注文テーブルがどのように設計されているのかを見ていきましょう。

完全なチュートリアルをロック解除

このチャプターは有料コンテンツです。プロジェクトに参加して、10以上の神レベルのPromptや実際のソースコード例を含む、5000字以上の深い分析をロック解除してください!