認証・DB・APIをAIと一緒に実装するとき、サービスの接続手順から考えるより「誰が、どのDataへ、どのActionを許可されるか」を先に決める方が安全です。Authenticationは本人確認、Authorizationは操作権限で、ログイン済みだから全Dataへアクセスできるわけではありません。
この記事では、架空のProject管理アプリを例に、Access Contract、DB構造、Auth、Server側Authorization、API、Deny Case、Loggingまでの順序を整理します。最終的には、成功ケースだけでなく「拒否すべきアクセスが拒否される」ことを検証できる状態を目指します。
目次
最初にAccess Contractを書く
コードを書く前にRole / Resource / Action / Allow Condition / Deny Caseを表にします。
表は横にスクロールできます
| Role | Resource | Action | Allow Condition | Deny Case |
|---|---|---|---|---|
| User | 自分のProject | Read / Update | owner_id一致 | 他人のProject |
| Member | Team Project | Read | membershipあり | 未所属Team |
| Admin | 管理対象 | Manage | admin role | roleなし |
| Anonymous | Public Project | Read | is_public=true | private Project |
この表がBackend実装の契約になります。UIの表示・非表示とは別に、Server側で同じ条件を守ります。
AuthenticationとAuthorizationを分ける
Authenticationは「このRequestを送った人は誰か」を確認する処理です。Authorizationは「その人がこのResourceへこのActionをしてよいか」を決める処理です。
ログイン済みUserがURLのIDを書き換えて他人のProjectへアクセスできるなら、Authenticationは成功していてもAuthorizationが失敗しています。この区別をAIへの実装指示でも明示します。
DBはAccess Contractを表現できる形にする
Project tableならid、owner_id、team_id、is_publicなど、Access判定に必要なFieldを持たせます。Team membershipがあるならUserとTeamのRelationも必要です。
権限を後から文字列だけで判定するより、DB上の所有関係やmembershipを明示できる方が、API側で一貫したRuleを書きやすくなります。
架空Schemaで考える
例:
users(id)
projects(id, owner_id, team_id, is_public, title)
team_members(team_id, user_id, role)
project_items(id, project_id, content)
この構造なら、Project owner、Team member、Public accessを別々に判定できます。
実際のSchemaはProduct要件で変わりますが、「Authorizationに必要なRelationをDBが持っているか」を先に確認します。
DB制約も最初に考える
Authorizationとは別に、Data Integrityを守る制約も必要です。Required Field、Foreign Key、Unique制約、StatusのAllowed Valueなどです。
AIが生成したAPI codeだけで不正Dataを防ぐのではなく、DB側でも守れる条件は守ります。どの層で何を保証するかを分けると、実装漏れを減らせます。
Authを接続したらUser IDをServerで確定する
Browserから送られたuser_idをそのまま信用しません。認証済みSessionやTokenからServer側でUserを確定し、そのIDをAccess判定に使います。
Clientから「owner_id=自分」と送られてきても、Server側で認証Identityと一致するか確認します。
最初のAPIはRead 1本だけ通す
複数Endpointを一気に作るより、まず「自分のProjectを1件読む」など最小Flowを通します。
成功ケース:Login済みUserが自分のProjectをGETして200。
Denyケース:他人のProject IDを指定して403または設計上適切な拒否。
Not Found:存在しないIDで404。
Anonymous:Private ResourceへAccessして拒否。
この4ケースを確認してからUpdateやDeleteへ進みます。
Write APIはValidation→Authorization→Writeの順で考える
Update APIでは、入力が正しいか、UserがResourceを変更できるかを確認し、その後Writeします。
どの順が適切かはFrameworkやThreat Modelで変わる部分がありますが、少なくとも「Clientが送った値だけを根拠に権限判定しない」「権限確認なしにWriteしない」を守ります。
外部APIは内部Access Controlの後に追加する
外部AI API、メール、決済、Storageなどを先につなぐと、権限設計が曖昧なまま副作用が増えます。
まずAuth→Authorization→DB Read/Writeの最小Flowを安定させ、その後に外部APIを追加します。外部処理の前にも「このUserがこのActionを実行できるか」を確認します。
秘密情報をBrowserへ置かない
Service KeyやSecret API Keyなど、公開してはいけないCredentialはServer側で扱います。Frontend bundleやpublic environment variableへ置かないようにします。
AIに実装させるときも、環境変数名と利用場所を明示し、Client ComponentからSecretを参照しないことをTestします。
Row Level Securityを使う場合もRuleを設計する
DB側のRow Level Securityなどを使える場合、Access ContractをPolicyへ落とせます。ただしPolicyを有効にしただけでは十分ではありません。
owner一致、membership、public readなど、必要なConditionをPolicyとして確認し、Server APIのAuthorizationと責務が重複・矛盾しないよう整理します。利用中のDB製品の現行仕様に従ってください。
Deny CaseをSuccessより先に一覧化する
Security上は「通るべきものが通る」だけでなく、「通ってはいけないものが通らない」が重要です。
最低限:
-
未ログイン
-
他人のResource ID
-
role不足
-
Team未所属
-
private resource
-
invalid input
-
retired/deleted resource
-
expired session
-
forged client field
各CaseでHTTP status、Response body、DB変更有無、Logを確認します。
Updateの途中失敗を考える
複数のWriteや外部API呼び出しがある処理では、途中で失敗するとDataが中途半端になる場合があります。
DB transaction、idempotency、retry方針など、処理内容に応じたFailure設計を入れます。たとえば同じRequestをRetryして二重作成されないかを確認します。
Error Responseに内部情報を出しすぎない
Clientへ返すErrorとServer logへ残す情報を分けます。
DB内部構造、Secret、Stack TraceなどをUser向けResponseへ出さないようにします。一方、運用側ではrequest_idやerror codeで原因を追えるようにします。
Loggingは誰が何をしたか追える粒度にする
重要なWriteでは、user_id、action、resource_id、result、timestamp、request_idなどを必要に応じて記録します。
ただしPasswordやSecret、不要な個人情報をLogへ残しません。Logの保存範囲もProductのSecurity / Privacy方針に合わせます。
AIへの実装依頼はContractを先に渡す
依頼例:
以下のAccess ContractをSource of Truthとして、最小のGET /projects/:idを実装してください。
要件:
-
Server側で認証Userを確定
-
owner_id一致または許可されたmembershipのみRead
-
Clientから送られたuser_idを信用しない
-
Anonymous / other user / not foundのTestを追加
-
SecretをClientへ露出しない
-
既存Architectureを維持
実装前に必要なDB FieldとUnknownを列挙してください。
最初から認証・全CRUD・外部APIまで頼まず、Access Contractごとに小さく通します。
接続順の一例
-
User / Role / Resource / Actionを定義。
-
DB Relationと制約を設計。
-
Authenticationを接続。
-
Read APIでServer側Authorization。
-
Deny Testを通す。
-
Write APIとIntegrity確認。
-
RLS等のDB Policyを確認。
-
外部APIを追加。
-
Failure / Retry / Loggingを追加。
-
End-to-Endで再検証。
これは特定Stackの絶対順ではなく、権限条件を先に固定するための実務順です。
MVPでも省かないもの
小さなアプリでも、認証Userの確定、Resource ownership、Server側Authorization、Secret管理、Deny Testは省かない方がよい領域です。
Admin画面、細かなRole、Audit UIなどはLaterにできる場合がありますが、他人のDataへアクセスできないことはMVPでもCoreです。
実装後Checklist
-
Access Contractがある
-
AuthenticationとAuthorizationを分けた
-
DBがOwnership / Membershipを表現できる
-
SecretがServer側
-
Read / Write双方で権限確認
-
他User IDでDeny Test済み
-
Invalid InputでDataが壊れない
-
Retryで二重処理しない
-
Errorに内部情報を出しすぎない
-
必要なLogからRequestを追える
AIものさしの判断
認証・DB・APIの接続順で最初に固定すべきなのは、技術サービスの順番ではなくAccess Contractです。「誰が何をできるか」が決まれば、DB Relation、Auth Identity、Server Authorization、API Testへ落とせます。
まずRead 1本で、自分のDataは読める・他人のDataは拒否される状態を作ってください。その後Write、外部API、Automationへ広げる。Success CaseとDeny Caseを同時に通す進め方なら、AIが生成したコードを使っても権限漏れを見つけやすくなります。
引用・データ出典
公式情報を編集部が見た内容です。Hands-on未実施の記述は本文かここに分けています。
確認日:2026-10-07
Supabase Docs:Auth
Supabase Docs:Row Level Security
Supabase Docs:Securing your data
Supabase Docs:Data REST API
