🔍

Next.jsにClerkの認証を追加する前に詳しく調べてみた!

に公開

本記事のサマリ

Next.jsアプリで認証を実装する際、様々な選択肢がありますが、今回はClerkを詳しく調べてみました。Clerkは開発スピードとDX(開発者体験)に特化したマネージド認証サービスで、その仕組みを理解すると「なぜこんなに簡単に使えるのか」が見えてきます。この記事では、Clerkの内部アーキテクチャ、ユーザー管理の仕組み、そして実際に使う際の注意点を、公式ドキュメントを元に解説します。

はじめに - なぜClerkを調べることにしたのか

以前の記事で、Firebase Auth、Auth.js、JWT自前実装など様々な認証方法を試してきました。それぞれに良さはあるものの、認証実装にはそれなりの学習コストと実装時間がかかります。

特に、スタートアップやプロトタイプ開発では「認証は必要だけど、本当はプロダクトのコア機能に時間を使いたい」という場面が多いものです。認証機能自体はビジネス価値を直接生まないので、できるだけ効率的に済ませたいところです。

そんな時、Clerkが「セットアップが簡単」という評判を見かけました。ただ単に「使い方が簡単」というだけでなく、その内部でどういう仕組みが動いているのかを理解しておくことは重要だと思い、公式ドキュメントを詳しく調べてみることにしました。

Clerkとは何か

Clerkは、開発者体験(DX)に特化したマネージド認証サービスです。Next.jsだけでなく、React、Remix、Astroなど様々なフレームワークに対応しています。

https://clerk.com/docs

最大の特徴は、美しいUIコンポーネントが最初から提供されることです。ログイン画面、サインアップ画面、ユーザープロファイル画面など、認証に必要な画面が全て用意されていて、しかもデザインが洗練されています。

さらに、ユーザー管理ダッシュボードも標準装備されているため、開発者がユーザー情報を確認したり、管理したりする際の手間も大幅に削減されます。

ログイン画面

(Clerk標準の認証ページ)

→ その他にも import { UserButton, SignInButton, useAuth } from '@clerk/nextjs' のようなUIコンポーネントがある。

UserButtonコンポーネント

(UserButtonコンポーネント呼んだだけで↑)

https://clerk.com/react-authenticatio

Clerkの仕組み - なぜProviderで囲うだけで認証が動くのか

Clerkのセットアップが驚くほど簡単な理由は、その内部アーキテクチャにあります。公式ドキュメントを詳しく調べてみると、かなり洗練された仕組みが見えてきました。

https://clerk.com/docs/guides/how-clerk-works/overview

Frontend API(FAPI)とPublishable Key

Clerkでアプリケーションを作成すると、専用のFrontend API(FAPI)インスタンスが自動的にプロビジョニングされます。これは https://<slug>.clerk.accounts.dev のような専用URLでホストされています。

環境変数に設定する NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY が重要な役割を果たします。このキーは実はFAPI URLをbase64でエンコードしたもので、pk_test_pk_live_ といった環境識別子が前に付いています。

つまり、Publishable Keyによって、あなたのアプリは専用のFAPIインスタンスの場所を知り、通信できるようになるわけです。

ClerkProviderの役割

<ClerkProvider> で囲うだけで認証が動く仕組みは、このコンポーネントがReactのContext APIを使って、アプリ全体に認証コンテキストを提供しているからです。

https://clerk.com/docs/nextjs/reference/components/clerk-provider

ClerkProviderは以下のことを自動的に行います:

  1. Publishable Keyを読み込み: 環境変数からキーを取得し、FAPIの場所を特定
  2. セッション管理: ユーザーの認証状態を監視し、セッショントークンを自動的に更新
  3. 認証コンテキストの提供: useUser()useAuth() などのフックが使えるように

これにより、アプリのどこからでも認証情報にアクセスできるようになります。

ハイブリッド認証モデル - トークンの二重管理

Clerkは「ステートフル」と「ステートレス」の両方のメリットを組み合わせたハイブリッド認証モデルを採用しています。これが、他の認証サービスと比べて特徴的な部分です。

2種類のトークン:

  1. Client Token(__client cookie)

    • FAPI ドメインに保存される長期トークン
    • セッション全体の有効期限(デフォルト7日)と一致
    • HttpOnly cookieなので、JavaScriptからアクセスできない(セキュリティ最低限OK)
  2. Session Token(__session cookie)

    • アプリのドメインに保存される短期トークン
    • 有効期限はわずか60秒
    • フロントエンドからアクセス可能

「60秒しか持たないトークン?それじゃ使い物にならないのでは?」と思いますよね。実はここがClerkの賢いところです。

自動トークンリフレッシュの仕組み

Clerkのフロントエンド SDKは、バックグラウンドで50秒ごとに自動的にトークンをリフレッシュします。つまり、ユーザーは何も意識せずに、常に新鮮なトークンを持ち続けることができます。

この仕組みの利点:

  • セキュリティ: トークンが盗まれても、60秒後には使えなくなる
  • 即座の失効: セッションを無効化すると、最大60秒後には確実に無効になる
  • パフォーマンス: 通常のリクエストではDBに問い合わせる必要がない

開発者ツールのネットワークタブを開くと、/client/sessions/<id>/tokens へのリクエストが50秒ごとに送られているのが確認できます。

Production環境と開発環境の違い

実は、開発環境(localhost)と本番環境では、セッション管理の方法が異なります。

Production環境: FAPI が clerk.example.com のようにアプリのサブドメインでホストされるため、same-site cookieが使えます。これにより、__client cookieが安全に送信されます。

開発環境: アプリは localhost、FAPIは .accounts.dev と異なるドメインになるため、cross-site cookieの問題が発生します。そのため、開発環境では「dev browser」という仕組みを使い、querystring(__clerk_db_jwt)でセッション状態を維持します。

これが、「開発環境を本番にデプロイしてはいけない」と言われる理由です。Querystring経由でトークンを送るのは、セキュリティ的に推奨されないためです。

https://clerk.com/docs/guides/development/managing-environments#session-architecture-differences

Clerkで管理できるユーザー情報

Clerkのユーザー管理機能は、かなり柔軟です。公式ドキュメントを調べてみると、3種類のメタデータを使って、様々な情報を追加できることが分かりました。

https://clerk.com/docs/guides/users/extending

3種類のメタデータ

1. Public Metadata

  • 読み取り: フロントエンド・バックエンドの両方から可能
  • 書き込み: バックエンドのみ
  • 用途: フロントエンドで表示したいが、ユーザーには変更させたくない情報
  • : ユーザーの誕生日、アカウント作成日、プロフィールバッジ

2. Private Metadata

  • 読み取り: バックエンドとWebhookハンドラーのみ
  • 書き込み: バックエンドとWebhookハンドラーのみ
  • 用途: 機密情報で、フロントエンドに公開したくないもの
  • : Stripe Customer ID、内部メモ、管理者用フラグ

3. Unsafe Metadata

  • 読み取り: フロントエンド・バックエンドの両方から可能
  • 書き込み: フロントエンド・バックエンドの両方から可能
  • 用途: ユーザー自身が変更できる情報
  • : プロフィール設定、表示名、テーマ設定

「Unsafe」という名前の通り、フロントエンドから変更できるため、悪意のあるユーザーに改ざんされる可能性があります。重要な情報は絶対にunsafe metadataに入れないようにしましょう。

メタデータのサイズ制限

メタデータには最大8KBという制限があります。さらに、セッショントークンに含める場合は、最大1.2KBという制限があります(ブラウザのcookieサイズ制限のため)。

この制限を超えると、cookieが正しく設定されず、Clerkが動作しなくなるので注意が必要です。大量のデータを保存したい場合は、自分のデータベースを使うべきでしょう。

RoleとOrganizationsによるRBAC

Clerkは、Organizationsという機能を使って、本格的なRole-Based Access Control(RBAC)を実装できます。

https://clerk.com/docs/guides/organizations/roles-and-permissions

デフォルトのロール:

  • Admin (org:admin): 組織の完全なアクセス権限
  • Member (org:member): 限定的なアクセス権限

カスタムロール:
インスタンスごとに最大10個のカスタムロールを作成できます。例えば、「Billing」ロールを作成して、請求書や支払い情報を管理する権限を付与することができます。

システムパーミッション:
Clerkが提供する組み込みのパーミッション:

  • 組織の管理(org:sys_profile:manage
  • 組織の削除(org:sys_profile:delete
  • メンバーの閲覧(org:sys_memberships:read
  • メンバーの管理(org:sys_memberships:manage
  • ドメインの閲覧・管理
  • 請求の閲覧・管理

カスタムパーミッション:
独自の機能に対して、きめ細かいアクセス制御を定義できます。例えば、org:invoices:create のようなパーミッションを作成し、特定のロールに付与することが可能です。

ただし、Organizations機能を本格的に使いたい場合は、無料プランでは制限があるため、Proプラン以上が必要になります。

メタデータなしの基本的なRBAC

Organizationsを使わずに、もっとシンプルなRBACを実装したい場合は、publicMetadata にロール情報を保存する方法もあります。

https://clerk.com/docs/guides/secure/basic-rbac

例えば、user.publicMetadata.role に "admin" や "user" といった文字列を保存し、バックエンドでそれをチェックするという方法です。これなら、無料プランでも実装できます。

この場合、セッショントークンにロール情報を含めることで、毎回APIリクエストを送ることなく、効率的に権限チェックができます👍

Clerkのメリット

実際に使ってみて感じたメリットをまとめます。

1. 圧倒的なセットアップの速さ

本当に15分程度で本番レベルの認証が完成します。UIコンポーネントが美しく、カスタマイズも可能です。

2. ユーザー管理ダッシュボード

ユーザー情報の閲覧、編集、削除が簡単にできます。メタデータの管理も直感的で、開発中のデバッグにも重宝します。

3. 豊富な認証オプション

  • OAuth(Google、GitHub、Twitter等)
  • Email/Password
  • Magic Link
  • Phone(SMS)
  • Passkeys(Proプラン)

どの認証方法も設定だけで使えるようになります。

4. セキュリティが考慮済み

  • ボット保護
  • ブルートフォース攻撃対策
  • 使い捨てメールアドレスのブロック
  • リークされたパスワードデータベースとの照合

これらのセキュリティ機能がデフォルトで含まれているのは心強いです。

5. Next.js App Routerとの親和性

Server Components、Client Componentsどちらでも使いやすく、Middlewareでの保護も簡単。RSC(React Server Components)に完全対応しているのも嬉しいポイントです。

6. ドキュメントの質

公式ドキュメントが非常に充実していて、サンプルコードも豊富です。Auth.js v5のドキュメント問題を経験した後だと、この差は本当に大きいと感じました。

Clerkのデメリット・注意点

正直に言うと、いくつか気になる点もあります。

1. 無料版のセッション期間制限

無料版ではセッション期間が7日固定されています。つまり、ユーザーは7日ごとに再ログインが必要になります。これは小規模プロジェクトでも結構痛い制限です。Proプランなら5分〜10年まで自由に設定可能ですが。

2. コストの上昇

10,000 MAUを超えると有料プラン必須になり、$25/月の基本料金 + $0.02/MAUという料金体系です。成長してユーザーが増えると、コストが急激に上がる可能性があります。

例えば50,000 MAUの場合:

  • $25(基本料金)+ $0.02 × 40,000(超過分)= $825/月

Firebase Authならこの規模でもほぼ無料なので、この差は大きいです。

3. ベンダーロックインのリスク

Clerk依存になるため、将来的な移行が難しくなる可能性があります。自前実装やAuth.jsなら、比較的簡単に別の方法に切り替えられますが、Clerkからの移行はそう簡単ではありません。

4. カスタマイズの限界

認証フローを細かくカスタマイズしたい場合には不向きです。UIはテーマでカスタマイズできますが、構造自体は変更しにくいという制限があります。

5. 日本語対応

UIコンポーネントの日本語化は可能ですが、デフォルトは英語です。ドキュメントも英語のみで、サポートも英語での対応になります。

6. MFAが有料アドオン

多要素認証を使いたい場合、Pro + Enhanced authentication add-on($100/月)が必要になります。Firebase Authなら標準で使えるので、この点は不利です。

どんな時にClerkを選ぶべきか

実際に調べてみて、以下のような場合にClerkが適していると感じました。

Clerkが向いているケース:

  • プロトタイプやMVPを素早く作りたい
  • スタートアップの初期段階で、認証にかける工数を最小にしたい
  • 美しいUIを簡単に実現したい
  • ユーザー管理ダッシュボードが欲しい
  • Next.js App Routerを使っている
  • セキュリティの実装を専門チームに任せたい
  • 10,000 MAU以下の小規模サービス

注意が必要なケース:

  • 予算が限られていて、ユーザー数が急速に増える見込みがある
  • 認証フローを細かくカスタマイズしたい
  • ベンダーロックインを避けたい
  • 無料で使い続けたい(7日ごとの再ログインを許容できない場合)

まとめ

Clerkを詳しく調べてみて、その内部の仕組みがよく理解できました。特に印象的だったのは以下の点です:

アーキテクチャの工夫:

  • ハイブリッド認証モデルによる、セキュリティとパフォーマンスの両立
  • 60秒という短いトークン有効期限と、自動リフレッシュの組み合わせ
  • Publishable Keyを通じた、専用FAPIインスタンスとの通信

柔軟なユーザー管理:

  • 3種類のメタデータ(Public、Private、Unsafe)による柔軟な情報管理
  • OrganizationsによるRBAC、またはシンプルなメタデータベースのRBAC
  • 最大8KBのメタデータ、セッショントークン内は1.2KBという制限

DXの高さ:

  • ClerkProviderで囲うだけで認証コンテキストが提供される
  • 美しいUIコンポーネントとダッシュボード
  • 充実した公式ドキュメント

注意すべきポイント:

  • 無料版はセッション期間7日固定
  • 成長に応じてコストが上昇(50,000 MAUで$825/月)
  • ベンダーロックインのリスク
  • カスタマイズの限界

プロトタイプやスタートアップの初期段階では、認証実装にかける時間を最小限にして、プロダクトのコア機能に集中することが重要です。その点でClerkは、セットアップの簡単さと強固なセキュリティを両立した、非常に魅力的な選択肢だと思います✨

ただし、長期的な運用を考える場合は、コストとベンダーロックインのリスクを十分に検討する必要があります。プロジェクトの特性、成長予測、予算を総合的に判断して、適切な認証方法を選んでいきましょう👍


参考リンク:

株式会社StellarCreate | Tech blog📚

Discussion