ClaudeCodeとSupabaseで認証付きアプリを作る方法【完全実践】
「ユーザー登録機能つきのアプリを作りたいけど、認証の実装は怖い」「データベースのセットアップが面倒」――そんな悩みを一気に解決するのがSupabaseです。Supabaseは「Firebaseのオープンソース版」とも呼ばれる統合バックエンドサービスで、認証、PostgreSQLデータベース、リアルタイム機能、ストレージがすべて揃っています。ClaudeCodeと組み合わせれば、自然な日本語で指示するだけで認証付きアプリのバックエンドを数十分で構築できます。本記事では、Supabase基礎から認証セットアップ、データベース連携、リアルタイム機能、デプロイまでを、実プロンプト例とコードサンプル多数で徹底解説します。
結論:ClaudeCode×Supabaseで認証付きアプリが数時間で完成
結論を先に言うと、ClaudeCodeとSupabaseの組み合わせは、認証・DB・リアルタイム機能つきWebアプリを最速で構築する黄金パターンです。
理由は3つあります。1つ目は、Supabaseが提供する機能の幅広さです。メール認証、OAuth(Google、GitHubなど)、PostgreSQL、ファイルストレージ、リアルタイムサブスクリプション、エッジ関数まで、必要なバックエンド機能がすべて揃っています。これらを個別サービスで構築すると数日かかるところ、Supabaseなら1日で完了します。
2つ目は、Row Level Security(RLS)という強力なアクセス制御機能です。「ユーザーは自分のデータしか見られない」というルールをDBレベルで宣言でき、フロントエンド側のミスでもデータ漏洩を防げます。
3つ目は、ClaudeCodeとの相性の良さです。SupabaseのSDKは型情報が豊富で、ClaudeCodeに「ユーザーの投稿一覧を取得する関数を書いて」と頼めば、適切なSQLクエリと型安全なTypeScriptコードが生成されます。
ただし、社内データや決済情報など機密性の高い情報を扱う場合は注意が必要です。Supabaseは便利ですが、Cloudflare Accessのような業務用のZero Trust認証とは別物です。一般向けのアプリやプロトタイプには最適ですが、機密度の高い社内アプリでは別の構成を検討してください(その場合はエンジニアに相談を)。
以下では、Supabaseの基礎、プロジェクト作成、認証セットアップ、データベース連携、リアルタイム機能、デプロイまでを順に解説します。
Supabaseとは:オープンソースの統合バックエンド
Supabaseは2020年に登場したBackend-as-a-Service(BaaS)で、Firebaseの代替として急成長しています。最大の特徴は、すべての機能がオープンソースで、内部はPostgreSQLという標準的なリレーショナルDBで動いている点です。
主な機能:
- Auth:メール、パスワード、OAuth、マジックリンク、SMSなど多様な認証方式に対応。
- Database:フルマネージドのPostgreSQL。SQL、リレーション、トリガー、関数すべて利用可能。
- Realtime:WebSocket経由でDBの変更をリアルタイム購読。チャットや通知に活用。
- Storage:S3互換のファイルストレージ。画像や動画のアップロードに利用。
- Edge Functions:Denoランタイムで動くサーバーレス関数。
- Vector:pgvectorによるベクトル検索。AIアプリにも対応。
料金プランは、Free(無料、データベース500MB、認証5万ユーザー)、Pro(月25ドル、データベース8GB、認証10万ユーザー)、Team、Enterpriseと続きます。個人開発や小規模サービスは無料プランで十分始められます。
Supabaseプロジェクトを作成する
プロンプト例1:Supabaseアカウントとプロジェクトの作成手順
Supabaseに登録してプロジェクトを作る手順を教えてください。
- アカウント未登録
- プロジェクト名: my-blog-app
- リージョン: 東京
- データベースパスワードはどう管理すればいいか
ClaudeCodeの案内:
- https://supabase.comにアクセスし、「Start your project」をクリック。
- GitHubアカウントでサインアップ(推奨)。
- 「New project」をクリック。
- Organizationを選び、プロジェクト名
my-blog-app、データベースパスワード(自動生成推奨)、リージョンNortheast Asia (Tokyo)を選択。 - 「Create new project」をクリック。数分でプロビジョニングが完了。
データベースパスワードはパスワードマネージャー(1Password、Bitwardenなど)に保管します。再表示できないため、紛失すると再設定が必要になります。
プロジェクト作成後、左メニューの「Project Settings → API」から以下の値を取得できます。これらは後で使います。
Project URL(例:https://xxxx.supabase.co)anon public key(フロントから使う公開キー)service_role key(サーバーから使う管理キー、絶対にフロントに渡さない)
Next.jsプロジェクトとSupabaseの連携
プロンプト例2:Next.js + Supabase SDKのセットアップ
Next.js(TypeScript、App Router)プロジェクトを作成し、
Supabaseと連携してください。
- プロジェクト名: my-blog-app
- @supabase/supabase-jsと@supabase/ssrをインストール
- src/lib/supabase/client.tsとserver.tsを作成
- 環境変数は.env.localで管理
ClaudeCodeは次のように進めます。
npx create-next-app@latest my-blog-app
cd my-blog-app
npm install @supabase/supabase-js @supabase/ssr
.env.localに環境変数を追加:
NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbG...
src/lib/supabase/client.ts:
import { createBrowserClient } from '@supabase/ssr';
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}
src/lib/supabase/server.ts:
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 {}
},
},
}
);
}
これでフロントエンドからもサーバーコンポーネントからもSupabaseにアクセスできるようになります。
メール認証のセットアップ
プロンプト例3:メール+パスワード認証の実装
Supabaseでメール+パスワード認証を実装してください。
- /signupページ: メールとパスワードで新規登録
- /loginページ: ログイン
- /logoutでログアウト
- ログイン状態に応じて表示を切り替えるヘッダーコンポーネント
- 認証後は/dashboardへリダイレクト
- 未認証ユーザーが/dashboardにアクセスしたら/loginへリダイレクト
ClaudeCodeが生成する例:
src/app/signup/page.tsx:
'use client';
import { useState } from 'react';
import { createClient } from '@/lib/supabase/client';
import { useRouter } from 'next/navigation';
export default function SignupPage() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState<string | null>(null);
const router = useRouter();
const supabase = createClient();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const { error } = await supabase.auth.signUp({ email, password });
if (error) setError(error.message);
else router.push('/dashboard');
};
return (
<form onSubmit={handleSubmit} className="max-w-sm mx-auto p-6 space-y-4">
<input
type="email"
placeholder="メールアドレス"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full border p-2 rounded"
/>
<input
type="password"
placeholder="パスワード"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full border p-2 rounded"
/>
<button className="w-full bg-blue-600 text-white p-2 rounded">登録</button>
{error && <p className="text-red-500">{error}</p>}
</form>
);
}
/dashboardの保護はミドルウェアで実装します。
src/middleware.ts:
import { NextResponse, type NextRequest } from 'next/server';
import { createServerClient } from '@supabase/ssr';
export async function middleware(request: NextRequest) {
let response = NextResponse.next();
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll: () => request.cookies.getAll(),
setAll: (cookies) =>
cookies.forEach(({ name, value, options }) =>
response.cookies.set(name, value, options)
),
},
}
);
const { data: { user } } = await supabase.auth.getUser();
if (!user && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return response;
}
export const config = {
matcher: ['/dashboard/:path*'],
};
OAuth(Google、GitHub)認証の追加
プロンプト例4:Google OAuthログインの追加
Googleアカウントでもログインできるようにしてください。
- /loginページに「Googleでログイン」ボタンを追加
- リダイレクトURIの設定方法も教えてください
ClaudeCodeは次の手順を案内します。
- Google Cloud Consoleで「OAuth 2.0 client ID」を作成。
- リダイレクトURIに
https://xxxx.supabase.co/auth/v1/callbackを登録。 - SupabaseダッシュボードのAuthentication → ProvidersでGoogleを有効化し、Client IDとSecretを入力。
- クライアントコード:
const handleGoogleLogin = async () => {
await supabase.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: `${location.origin}/auth/callback` },
});
};
- コールバックを処理する
src/app/auth/callback/route.tsを作成。
import { createClient } from '@/lib/supabase/server';
import { NextResponse } from 'next/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();
await supabase.auth.exchangeCodeForSession(code);
}
return NextResponse.redirect(`${origin}/dashboard`);
}
データベース連携とRow Level Security
プロンプト例5:データベース設計とRLS設定
ブログ投稿機能を作るためのテーブルを設計してください。
- postsテーブル: id, user_id, title, content, created_at
- ユーザーは自分の投稿のみ編集・削除でき、公開された投稿は誰でも読める
- 必要なSQLとRLSポリシーを生成してください
ClaudeCodeが生成するSQL:
-- テーブル作成
create table posts (
id uuid primary key default gen_random_uuid(),
user_id uuid not null references auth.users(id) on delete cascade,
title text not null,
content text,
published boolean default false,
created_at timestamptz default now()
);
-- RLS有効化
alter table posts enable row level security;
-- 全員が公開投稿を読める
create policy "Public can read published posts"
on posts for select
using (published = true);
-- 自分の投稿は全て読める
create policy "Users can read own posts"
on posts for select
using (auth.uid() = user_id);
-- 自分の投稿のみ作成可能
create policy "Users can insert own posts"
on posts for insert
with check (auth.uid() = user_id);
-- 自分の投稿のみ更新可能
create policy "Users can update own posts"
on posts for update
using (auth.uid() = user_id);
-- 自分の投稿のみ削除可能
create policy "Users can delete own posts"
on posts for delete
using (auth.uid() = user_id);
このSQLをSupabaseダッシュボードの「SQL Editor」で実行すれば、テーブルとRLSが一括で適用されます。
データを取得するコード:
const supabase = await createClient();
const { data: posts, error } = await supabase
.from('posts')
.select('id, title, content, created_at')
.eq('published', true)
.order('created_at', { ascending: false });
RLSが有効なので、ログインユーザーは自分の投稿を、未ログインユーザーは公開投稿だけを取得します。フロントエンドのコードでロジックを書く必要はありません。
リアルタイム機能の実装
Supabaseのリアルタイム機能を使うと、DBの変更を即座にフロントエンドに反映できます。チャットや通知に最適です。
プロンプト例6:リアルタイムコメント機能
ブログ投稿にコメント機能を追加してください。
- commentsテーブル: id, post_id, user_id, content, created_at
- 新しいコメントが投稿されたら、リアルタイムで画面に追加
- RLSはログインユーザーのみコメント可能、誰でも読める
クライアントコードの例:
'use client';
import { useEffect, useState } from 'react';
import { createClient } from '@/lib/supabase/client';
export function Comments({ postId }: { postId: string }) {
const [comments, setComments] = useState<any[]>([]);
const supabase = createClient();
useEffect(() => {
// 初期データ取得
supabase
.from('comments')
.select('*')
.eq('post_id', postId)
.order('created_at')
.then(({ data }) => setComments(data || []));
// リアルタイム購読
const channel = supabase
.channel(`comments:${postId}`)
.on(
'postgres_changes',
{
event: 'INSERT',
schema: 'public',
table: 'comments',
filter: `post_id=eq.${postId}`,
},
(payload) => {
setComments((prev) => [...prev, payload.new]);
}
)
.subscribe();
return () => {
supabase.removeChannel(channel);
};
}, [postId]);
return (
<ul className="space-y-2">
{comments.map((c) => (
<li key={c.id} className="border p-2 rounded">{c.content}</li>
))}
</ul>
);
}
postgres_changesイベントを購読することで、新規コメントが即座に画面に追加されます。
ファイルストレージ機能
Supabase Storageで画像や動画をアップロードできます。
const handleUpload = async (file: File) => {
const supabase = createClient();
const { data, error } = await supabase.storage
.from('avatars')
.upload(`${user.id}/${file.name}`, file, { upsert: true });
if (data) {
const { data: { publicUrl } } = supabase.storage
.from('avatars')
.getPublicUrl(data.path);
return publicUrl;
}
};
事前にSupabaseダッシュボードでavatarsバケットを作成し、RLSポリシーを設定しておきます。
実践チュートリアル:ミニブログサービスを構築
ここまでの内容を組み合わせて、認証付きミニブログサービスを作ります。
ステップ1:プロジェクト作成
ミニブログサービスを作りたいです。
- Next.js + TypeScript + App Router + Tailwind
- Supabase認証(メール+パスワード、Googleログイン)
- 投稿のCRUD、コメント機能、画像アップロード
- 公開投稿は誰でも閲覧、編集は本人のみ
プロジェクトを初期化してください。
ステップ2:DBスキーマ作成
profiles、posts、commentsテーブルとそれぞれのRLSポリシーをSQLで生成してください。
ステップ3:認証UIの実装
/signup、/login、/logout、ヘッダーのログイン状態表示を実装してください。
ステップ4:投稿機能の実装
/dashboardで自分の投稿一覧、新規作成、編集、削除ができるUIを作ってください。
/posts/[id]で公開投稿を閲覧、コメント投稿ができるようにしてください。
ステップ5:デプロイ
このアプリをVercelにデプロイしてください。
環境変数の登録も含めてお願いします。
ClaudeCodeはVercel CLIを使ってデプロイし、NEXT_PUBLIC_SUPABASE_URLとNEXT_PUBLIC_SUPABASE_ANON_KEYを登録します。
ステップ6:本番URLでSupabase認証設定
Supabaseダッシュボードの「Authentication → URL Configuration」で、Site URLを本番URLに変更し、Redirect URLsに本番のコールバックURLを追加します。
FAQ:Supabase × ClaudeCode よくある質問
Q1. Supabaseは無料でどこまで使えますか?
無料プランでDB 500MB、認証ユーザー5万人、ストレージ1GB、月50万のEdge Function呼び出しまで使えます。個人開発や小規模サービスなら十分です。プロジェクトを1週間使わないと一時停止になるので注意してください。
Q2. Firebase Authとどちらがいいですか?
機能面ではほぼ同等ですが、SupabaseはオープンソースかつPostgreSQLベースなので、データのエクスポートやセルフホストが容易です。Firebaseはエコシステムが大きく、Google系サービスとの連携が強力です。一般的にはSupabaseの方がベンダーロックインが少ないとされています。
Q3. ClaudeCodeがservice_role keyを使うコードを生成してしまった場合は?
service_role keyはRLSを完全にバイパスする管理キーなので、絶対にブラウザ側に渡してはいけません。ClaudeCodeに「これはサーバー側でのみ使う形に修正して」と頼めば、API Routeやserver.tsで扱う形に修正してくれます。コミット前に必ず.env.localにSUPABASE_SERVICE_ROLE_KEY=がNEXT_PUBLIC_なしで入っていることを確認してください。
Q4. データベース設計が苦手です。ClaudeCodeに任せていいですか?
はい、「こういう機能を実現したい。テーブル設計を提案して」と頼めばER図レベルから提案してくれます。RLSポリシーまで含めて生成できるので、設計と実装が同時に進みます。ただし、本番運用前にレビューは必須です。
Q5. リアルタイム機能の料金は別途かかりますか?
無料プランで同時接続200まで、メッセージ200万/月まで含まれています。小規模なチャットや通知なら無料で運用可能です。
Q6. メール認証のメールが届きません。
Supabaseの無料プランは送信レートに制限があり、また送信元ドメインがSupabaseのデフォルトドメインだとスパム判定されることがあります。本番ではSendGrid、Resendなどの外部SMTPを設定し、自社ドメインから送るのが推奨です。
Q7. 社内向け業務アプリにSupabaseを使ってもいいですか?
機密性の低いツール(社内ポータル、Wiki、簡易ToDoなど)なら問題ありませんが、決済情報や個人情報を多く扱う業務アプリは、Cloudflare AccessやSAML連携のあるエンタープライズ認証を使う構成を検討してください。判断に迷ったらエンジニアに相談してください。
まとめ
SupabaseはClaudeCodeとの相性が抜群で、認証付きWebアプリのバックエンドを最速で構築できます。メール認証、OAuth、PostgreSQL、RLS、リアルタイム、ストレージまですべて1つのサービスで揃うため、複数のSaaSを契約する必要がありません。ポイントは、RLSポリシーを早い段階で設定してデータ保護をDBレベルで実現すること、service_role keyをフロントに渡さないこと、本番URLをSupabaseのRedirect URLsに登録することです。これらを守れば、安全で機能豊富なアプリを誰でも作れます。まずはシンプルなToDoやブログから始めて、Supabaseの便利さを体験してみてください。