対象読者:Next.js(App Router)で B2C/B2B SaaS を作っていて、Clerk を「ただ導入する」から「安全に運用できる設計で使う」へ進みたい人
この記事では Cookie/Session の仕組み と Organization(マルチテナント) を軸に、実務でハマらないための体系をまとめます。
1. Clerk って何をしてくれるサービス?
Clerk は一言でいうと Authentication(認証)+ User Management(ユーザー管理)+ Session Management(セッション管理) を提供するサービスです。Next.js 側では Clerk の SDK を通じて「このリクエストは誰のものか」を取り出し、あなたのアプリ(DB/機能)はそれを前提に動きます。(clerk.com)
2. まず押さえるべき “内部イメージ”
Clerk を使う上で一番大事なのは、「ログインしたら終わり」ではなく Session を中心に全てが回る ことです。
- ユーザーが Sign in
- Clerk が Session を発行(ブラウザに Cookie 等として保持)
- 以後のアクセスではブラウザが Cookie を自動送信
- Next.js 側は
auth()や middleware で Session を検証し、userId等を得る(clerk.com)
3. 認証と認可を分けて考える(重要)
-
Authentication(認証):あなたは誰?ログインしてる? →
userIdが取れるか - Authorization(認可):その人は “この操作” をしていい? → Role/Permission、org の所属、DB 条件など
Clerk は主に「認証情報(+ org context)を提供」しますが、データ分離や権限チェックの最終責任はアプリ側にあります(ここが事故ポイント)。(clerk.com)
4. Next.js App Router での基本部品(何をどこで使うか)
4.1 clerkMiddleware():入口で “認証状態” を付与する
App Router では middleware を使って、対象ルートで Clerk が認証情報を扱えるようにします。
重要:デフォルトでは何も保護されません(opt-in)。守りたいルートは自分で指定します。(clerk.com)
例(イメージ):
// middleware.ts
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
const isProtectedRoute = createRouteMatcher([
"/dashboard(.*)",
"/api(.*)",
]);
export default clerkMiddleware((auth, req) => {
if (isProtectedRoute(req)) auth().protect();
});
export const config = {
matcher: [
// Next.js 推奨の matcher パターン(静的ファイル除外 + API)
"/((?!_next|.*\\..*).*)",
"/(api|trpc)(.*)",
],
};
createRouteMatcher() を使った保護は Clerk 公式の middleware リファレンスでも触れられています。(clerk.com)
4.2 auth():Server / Route Handler 側で “誰か” を取り出す
App Router では auth() で Auth object(認証結果)を取り出します。(clerk.com)
例(Route Handler):
import { auth } from "@clerk/nextjs/server";
export async function GET() {
const { userId, orgId } = auth();
if (!userId) return new Response("Unauthorized", { status: 401 });
// orgId が必要なページならここで弾く
// if (!orgId) return new Response("No active org", { status: 400 });
return Response.json({ userId, orgId });
}
5. Session token / JWT を “いつ気にすべきか”
Clerk の session は JWT(session token)として扱われることがあり、必要に応じて claim を拡張できます。(clerk.com)
-
普通の Web アプリ(Next.js 内で完結)なら:まずは Cookie +
auth()を理解すればOK -
次の用途が出たら JWT を意識すると良い
- 外部サービスに渡すトークンが必要(analytics、別バックエンド、CLI など)
- 「この claim を token に入れて downstream で検証したい」
- 長期トークンをテンプレで発行したい(JWT templates)(clerk.com)
6. Organization(マルチテナント)の考え方:Active Organization が核心
6.1 “所属してる” と “今その org として操作してる” は別
Organization を使うと、ユーザーは複数 org に所属でき、アプリ内では通常「今どの org を active にしてるか」が重要になります。Clerk の org ガイドでも org を作成/切替し、org 単位で保護する流れが説明されています。(clerk.com)
アプリでよく見る状態:
-
userIdはある(ログイン済み) - でも
orgIdがない(active org 未選択)
→ 「Organization を選んでください」画面へ誘導する必要がある
6.2 Organization slug を URL に入れる設計
B2B SaaS で多いのが /{orgSlug}/... 形式です。Clerk 公式には org slug を URL に使うガイドがあり、OrganizationSwitcher や middleware 設定、org-specific rendering の考え方が整理されています。(clerk.com)
この設計での実務ポイント:
- URL の
orgSlugと active org を一致させる(不一致はリダイレクト or 403) - link 共有が多い・org 切替が多いなら slug 方式が効く(公式も注意点を提示)(clerk.com)
7. DB 設計の鉄則:必ず “tenant key” を持たせる
Organization を使うなら、DB のすべての “テナント依存データ” に以下のどちらかを入れます:
-
orgId(Clerk の organization id)をそのまま保存 - もしくは自前
tenant_idを作ってclerk_org_idと紐付け
そして 全クエリに WHERE org_id = auth().orgId を入れる。
Clerk は orgId を教えてくれますが、データ分離はあなたのアプリの責務です(ここがマルチテナント事故の最大要因)。(clerk.com)
例(擬似コード):
const { userId, orgId } = auth();
if (!userId) throw new Error("Unauthorized");
if (!orgId) throw new Error("No active org");
// ✅ orgId で必ず絞る
const interviews = await db.interview.findMany({
where: { orgId },
});
8. Role / Permission(認可)の実装パターン
Organization を使うと「org 内の Role/Permission」で管理画面や操作権限を分けるのが王道です(Clerk の org チュートリアルでも “protect routes by Organization and Roles” を扱います)。(clerk.com)
実務ルール:
- UI だけ隠すのはNG(API/Server Action でも必ず検証)
- “管理者だけ” は server 側で弾く
- 迷ったら「最小権限」をデフォルトにする
9. ハマりどころ(よくある症状 → 原因)
9.1 auth() を呼ぶと「middleware が検出できない」系エラー
auth() は middleware が正しく設定されている前提で動きます。matcher がそのルートを対象にしていない等で起きます。(GitHub)
9.2 orgId が undefined/null になる
多くの場合「所属はしているが active org が未設定」か、slug/切替導線や middleware 設定の問題です。実際に同様の相談がコミュニティでも繰り返し出ています(=設計で回避しやすい)。(GitHub)
10. まとめ:Clerk を “使いやすくする知識” の最短ルート
- Clerk は Session を中心に動く(Cookie 自動送信 + server 側検証)(clerk.com)
- Next.js(App Router)では
clerkMiddleware()とauth()が基本セット(clerk.com) - Organization では Active Organization / orgId が核心(URL slug 設計も含めて考える)(clerk.com)
- マルチテナントの安全性は DB の
orgId絞り込みで担保する(ここが最重要)(clerk.com) - JWT/claim は「外部連携・別バックエンド・CLI」などが出たら理解を深める(clerk.com)