netlify-identity について
netlify-identity は、ブラウザーや Netlify Functions、Edge Functions で認証・認可を実装する開発者向けのスキルです。クライアント認証、サーバー側のユーザー確認、ロール制御、Identity イベントを扱い、ダッシュボード設定とデプロイ環境でのテストも説明します。
主な機能
- 01登録、ログイン、ログアウト、OAuth の実装
- 02確認、招待、復旧リンクの処理
- 03関数内でのユーザーとロールの検証
- 04Identity イベントによる登録検証とロール付与
- 05リダイレクトルールによるエッジ RBAC
活用シーン
- 01Netlify アプリへの登録・ログイン機能の追加
- 02ユーザーとロールの確認による関数エンドポイントの保護
- 03登録時のユーザー検証やロール付与
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ netlify/ context-and-tools --skill netlify-identityインストール後、Claude Code で/netlify-identityを入力して読み込まれたか確認します。
同梱ファイルreferences/advanced-patterns.mdreferences/authorization-and-sessions.md
詳細
Netlify Identity
@netlify/identity(npm)を使用してください。新しいプロジェクトでは、従来の netlify-identity-widget と gotrue-js に代わるため、これらは使用しないでください。
npm install @netlify/identity
フレームワークの例(Next.js/Astro/Remix/SvelteKit)と API リファレンスの全内容は、npm の @netlify/identity README にあります。
Identity は
netlify devでは動作しません。 すべての認証フローはデプロイ環境でテストしてください。Deploy Previews も利用できます。ローカル開発環境では、サインアップ、ログイン、OAuth は完了しません。
Identity の設定はダッシュボードでのみ行えます。公開 API はありません。 Identity の設定を切り替えたり読み取ったりするために
api.netlify.comに curl したり、ローカルの Netlify 設定からトークンを読み取ったり、ドキュメント化されていないエンドポイントを調べたりしないでください。Identity はhttps://app.netlify.com/projects/{site_name}/identityで有効化して設定してください。
Identity と並行して、独自の OAuth フローを一から構築しないでください。 コード内でプロバイダーアプリを登録したり、ソースに
client_id/secretを記述したり、独自のコールバックでトークンを交換したりしないでください。oauthLogin()とhandleAuthCallback()を使用してください。Identity と並行して生の OAuth を実装することは、手戻りが発生する最も一般的な原因です。
クライアント認証(ブラウザー)
import { signup, login, logout, getUser, oauthLogin, handleAuthCallback } from '@netlify/identity'
// Register — confirmation email sent by default (unless autoconfirm is on)
const user = await signup('[email protected]', 'securepassword', { full_name: 'Jane Doe' })
// Log in / out
await login('[email protected]', 'securepassword')
await logout()
// Current user or null
const current = await getUser()
if (current) console.log(`Logged in as ${current.email}`)
// External provider — redirects the browser; provider is one of
// 'google' | 'github' | 'gitlab' | 'bitbucket'
oauthLogin('github')
ランディングページでは
handleAuthCallback()の呼び出しが必須です。 これがないと、OAuth リダイレクト、メール確認リンク、パスワード再設定リンク、招待リンクが完了しません。ページの読み込み時に呼び出してください。
import { handleAuthCallback } from '@netlify/identity'
const result = await handleAuthCallback() // falsy if no token in URL hash
if (result) console.log(result.type, result.user.email) // confirmation | invite | recovery | email change
トークンタイプが 1 種類の場合は、代わりに recoverPassword()(再設定)、acceptInvite()(招待)を使用できます。セッションを更新するには refreshSession() を使用してください。
利用可能なプロバイダーをハードコードしないでください。起動時に getSettings() を呼び出し、返された内容に基づいてサインアップフォームと OAuth ボタンを表示してください。
サーバーサイド認証(Netlify Functions と Edge Functions)
サーバーサイドの getUser()/login()/admin.* には、最新の v2 関数(export default)が必要です。v1 の export { handler } 形式には対応していません。
getUser() はどちらのランタイムでも動作します。admin.* が実行されるのは Netlify Functions のみです。ブラウザーや Edge Functions では実行されません。
// netlify/functions/me.ts — verify user
import { getUser } from '@netlify/identity'
import type { Context } from '@netlify/functions'
export default async (req: Request, context: Context) => {
const user = await getUser()
if (!user) return new Response('Unauthorized', { status: 401 })
return Response.json({ id: user.id, email: user.email })
}
Edge Function も同じ形式ですが、Context は @netlify/edge-functions からインポートします。
ロールの確認
// netlify/functions/admin-users.ts
import { getUser, admin } from '@netlify/identity'
import type { Context } from '@netlify/functions'
export default async (req: Request, context: Context) => {
const user = await getUser()
if (!user) return new Response('Unauthorized', { status: 401 })
if (!user.roles.includes('admin')) return new Response('Forbidden', { status: 403 })
const users = await admin.listUsers()
return Response.json({ users })
}
CSRF:サーバーサイド認証エンドポイントで必須
サーバーサイドで
login()、signup()、logout()を実行するエンドポイントでは、ハンドラーの先頭で必ずverifyRequestOrigin(req)を呼び出してください。オリジンが一致しない場合、これは 403 をスローします。
// netlify/functions/login.ts
import { login, verifyRequestOrigin } from '@netlify/identity'
import type { Context } from '@netlify/functions'
export default async (req: Request, context: Context) => {
verifyRequestOrigin(req)
const { email, password } = await req.json()
await login(email, password)
return new Response(null, { status: 302, headers: { Location: '/dashboard' } })
}
Identity イベント関数
Identity イベントが発生すると、プラットフォームからハンドラーが呼び出されます。イベントごとのメソッドを含むオブジェクトをデフォルトエクスポートしてください。ファイル:netlify/functions/identity.mts。
型付きハンドラー(
UserSignupEvent、event.deny())には@netlify/functions≥ 5.2.0 が必要です。古いインストールでは、従来のファイル名規則(identity-signup.tsなど)を使用してください。詳しくはreferences/authorization-and-sessions.mdを参照してください。
| ハンドラー | 呼び出されるタイミング |
|---|---|
userValidate | アカウント作成前のサインアップ試行時。不正なサインアップはここでブロックします。 |
userSignup | サインアップ完了時(有効にしている場合はメール確認後)。ロールの割り当て、同期、ウェルカム処理を行います。 |
userLogin | ユーザーのログイン時。追跡、最終アクセスの記録、ブロックを行います。 |
userModified | プロフィールの更新時。 |
userDeleted | ユーザーの削除時(通知のみ)。 |
イベントの user フィールドはキャメルケースです(appMetadata、userMetadata、confirmedAt)。
// netlify/functions/identity.mts — deny a signup
import type { UserValidateEvent } from "@netlify/functions"
export default {
userValidate(event: UserValidateEvent) {
if (!event.user.email?.endsWith("@example.com")) return event.deny()
},
}
// netlify/functions/identity.mts — assign roles at signup
import type { UserSignupEvent } from "@netlify/functions"
export default {
userSignup(event: UserSignupEvent) {
return { user: { ...event.user, appMetadata: { ...event.user.appMetadata, roles: ["member"] } } }
},
}
event.deny()— アクションを拒否します。エンドユーザーには401が返され、監視対象のエラーにはなりません。最初にこれを呼び出したハンドラーがチェーンを中断し、後続のサブスクライバーは呼び出されません。(従来のファイル名を使う関数では、代わりに 2xx 以外のResponseを返して拒否を示します。){ user: {...} }を返すと、永続化の前にレコードを変更できます(サインアップ時にロールを設定する標準的な方法です)。ロールは JWT に含まれるため、ロールの変更が反映されるのはユーザーの次回のログインまたはトークン更新時であり、即時ではありません。以下の「ロールと JWT」を参照してください。- バックグラウンドモード:
export const config: Config = { background: true }— アクションはすぐに完了し、ハンドラーは非同期で実行されます。
ロールと JWT
user.rolesは、JWT(Cookienf_jwt。nf_refreshで更新)に含まれるapp_metadata.rolesから読み取られます。user_metadataはユーザーが編集できるプロフィール(full_name、email)です。app_metadataは、ユーザーが編集できないrolesなどのアプリデータです。
ロールの変更はすぐには反映されません。 次回のログインまたはトークンの更新時に反映されます。ロールを変更しても、現在の JWT は無効になりません。強制的に反映するには
refreshSession()を実行してください。
既存ユーザーのロールは Netlify Function 内で admin.updateUser() を使って設定します。サインアップ時は、上記の userSignup イベントハンドラーを使って設定します。
SSR/セッションのハイドレーションと認可に関する詳細なガイドは、references/advanced-patterns.md と references/authorization-and-sessions.md にあります。
CDN エッジの RBAC(リダイレクトルール)
オリジンへの往復通信なしで、エッジで適用されます。ロールが一致しない場合、フォールバックを追加しない限り 404 が返されます — ロールで制限するルールには、必ずフォールバックを組み合わせてください。
_redirects:
/admin/* /admin/:splat 200! Role=admin
/admin/* /login 401!
# Multiple roles chained with commas:
/private/* /private/:splat 200! Role=editor,admin
netlify.toml:
[[redirects]]
from = "/admin/*"
to = "/admin/:splat"
force = true
status = 200
conditions = {Role = ["editor", "admin"]}
パスベースの制限にはリダイレクトルールを使い、カスタム認可ロジックには関数内で user.roles を確認してください。
設定(ダッシュボードのみ)
ベース URL:https://app.netlify.com/projects/{site_name}/identity。Enable Identity を有効にしてください。Identity には HTTPS が必要です。カスタムドメインで連携する前に、SSL を設定してください。
- Registration(
?tab=registration#registration-preferences):Open(デフォルト。誰でもサインアップできます)または Invite only(外部プロバイダーでのログインを含むすべてのユーザーについて、事前の招待が必要です)。 - Confirmation / autoconfirm(
?tab=emails#confirmation-template):メール認証を省略するには、チェックボックスをオンにしてください。 - External providers(
?tab=registration#external-providers):Google/GitHub/GitLab/Bitbucket。ブランド名を表示する OAuth(「Netlify Identity」ではなくアプリ名を表示する場合)では、プロバイダーにアプリを登録してクライアント ID とシークレットを取得し、コードではなく Netlify の設定 UI に入力してください。 - Invitations(
?tab=users):招待を送るアドレスを入力します。リンクにはinvite_tokenが含まれます。 - パスワードの復旧:ユーザーページ → Send reset password email。リンクには
recovery_tokenが含まれます。
メール(Pro プラン以上)
デフォルトの送信元は [email protected] です。カスタム SMTP 送信元とカスタムテンプレートは、どちらも Pro プラン以上が必要です。
テンプレート変数(Go 構文):{{ .Email }}、{{ .NewEmail }}(メールアドレス変更時のみ)、{{ .SiteURL }}、{{ .ConfirmationURL }}、{{ .Token }}。
アクションごとのカスタムリンクのハッシュフラグメント:
{{ .SiteURL }}/path/#invite_token={{ .Token }}
{{ .SiteURL }}/path/#confirmation_token={{ .Token }}
{{ .SiteURL }}/path/#recovery_token={{ .Token }}
{{ .SiteURL }}/path/#email_change_token={{ .Token }}
カスタムテンプレートの制約:インライン CSS のみ使用できます。画像リンクには絶対 URL を指定してください。<html>/<head>/<body> タグは使用できません。ビルドによって Go テンプレート変数が変更されないようにしてください。
監査ログ(Pro プラン以上)
?tab=audit-log。範囲を指定して検索します:author:[string] または action:[string]。アクション名:login、logout、user_signedup、user_deleted、user_modified、token_revoked、token_refreshed、user_recovery_requested、user_invited。
外部 JWT プロバイダー(Enterprise)
Enterprise プランで利用できます。Netlify Identity または外部 JWT プロバイダーのいずれかを使用できます — 同時には使用できません。Netlify Identity が有効な場合、サードパーティの JWT で認証することはできません。
- ロールのパス:Netlify Identity は
app_metadata.roles、外部プロバイダーはapp_metadata.authorization.rolesです。カスタムパスについてはサポートにお問い合わせください。 - JWT ヘッダーは
{"alg": "HS256", "typ": "JWT"}である必要があります(HS256 が必須です)。ペイロードのexpは必須で、未来の Unix Epoch 時刻である必要があります。 - JWT シークレットは
Project configuration > General > Visitor access > JWT secretで設定してください。プロジェクトレベルの設定は、チームレベルのデフォルト設定より優先されます。
失敗した場合 — 推測せずに停止する
コールバックが 404 を返す場合、/.netlify/identity/* に到達できない場合、または OAuth フローから戻らない場合は、エラー、ダッシュボードの URL(https://app.netlify.com/projects/{site_name}/identity)、確認すべき設定(登録方法、外部プロバイダーの設定、確認/自動確認)を提示してください。その後、停止してください。復旧コマンドを作り出さないでください。Identity は netlify dev では動作しません — デプロイ環境でテストしていることを確認してください。
サイトへのアクセス制限に関するリクエスト(「このサイトを自社専用にする」、従業員限定など)は、まず netlify-access-control スキルに案内してください — Identity はアプリレベルのユーザーレイヤーのみを担います。
Netlify の基本ルール(Identity)
これらはドキュメント上の事実ではなく、組織内の規約です。ctx-gen によってレンダリング済みスキルに統合され、生成されることはありません。スキルのメンテナーが管理しています。
- 詳細ガイドはこのスキル内にあります:
references/advanced-patterns.md(SSR/セッションのハイドレーション)とreferences/authorization-and-sessions.md。 - Identity は
netlify devでは動作しません — 認証フローはデプロイ環境でテストしてください (Deploy Preview も利用できます)。 - Identity の設定にパブリック API はありません — ダッシュボードでのみ設定できます。Identity の設定を変更または確認するために
api.netlify.comを curl しないでください。~/Library/Preferences/netlify/config.jsonから認証トークンを読み取らないでください。ドキュメントにないエンドポイントを探らないでください。 - 失敗した場合(コールバックが 404 を返す、
/.netlify/identity/*に到達できない、OAuth フローから戻らない場合)は、エラー、ダッシュボードの URL、確認すべき設定を提示し、その後停止してください。復旧コマンドを作り出さないでください。 - Identity を使用する場合、サードパーティの OAuth フローを一から構築しないでください — プロバイダーアプリの登録、コードへの
client_id/secretの記述、カスタムのコールバックトークン交換は禁止です。oauthLogin()+handleAuthCallback()を使用してください。Identity と並行して生の OAuth を使うことは、手戻りの最も一般的な原因です。 - サーバーサイドの
getUser()/login()/admin.*には、モダンな v2 関数(export default)が必要です — v1 のexport { handler }はサポートされていません。型付き Identity イベントハンドラー(UserSignupEvent、event.deny())には@netlify/functions≥ 5.2.0 が必要です。それより古いインストールでは、従来のファイル名を使用してください。 - 利用できる認証プロバイダーをハードコードしないでください — 起動時に
getSettings()を呼び出し、その戻り値に基づいて登録フォームと OAuth ボタンを表示してください。 - サイトへのアクセス制限に関するリクエスト(「このサイトを自社専用にする」、従業員限定など)は、まず netlify-access-control スキルに案内してください — Identity はアプリレベルのユーザーレイヤーのみを担います。
- 登録時、
admin.*経由、またはダッシュボードでロールを割り当てたり変更したりする回答では、変更が有効になるのはユーザーの次回ログイン時またはトークンの更新時であり、直ちに反映されるわけではないと説明する必要があります。その説明は、ロールを設定するコードのすぐ近くに記載してください。JWT の説明セクションだけに記載しないでください。登録に関する質問に答えるエージェントは登録例を読んだところで確認を終えるため、反映の遅延を省いた回答を実際に公開してしまった例があります。