# Kuroco Auth Design

> Kurocoの会員認証・権限の設計判断を行う。会員グループ設計（権限の組み合わせによる昇格経路の回避）、登録フロー（即時登録/招待/仮登録）、コンテンツアクセス制限のスコープ（グループ制限/カスタム検索/自分の投稿のみ）、パスワードポリシー・2要素認証、代理ログイン、エンタープライズSSO（OAuth SP/SAML SP/IDaaS SP）・SCIMプロビジョニングを、将来の連結も見据えて決める。実装コードは kuroco-frontend-integration、既存設定の監査は kuroco-security-audit が担当。「会員機能を設計したい」「会員グループをどう分けるか」「登録フローをどうするか」「自分の投稿だけ見せたい」「代理ログインが必要か」「SSO/SAML/SCIMを後から繋げたい」等の設計相談で使用。

- Skill: `diverta/kuroco-auth-design` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add diverta/kuroco-auth-design`
- Raw SKILL.md: https://api.skillmd.com/api/skills/diverta/kuroco-auth-design/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: diverta (https://skillmd.com/u/diverta)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/diverta/kuroco-auth-design

---


# Kuroco 認証・会員設計

## 位置づけ

本スキルは**設計判断**を行う。関連スキルとの境界:

- `/kuroco-frontend-integration` — ここで決めた認証方式・フローを実装するコード（Cookie/トークンの送受信等）
- `/kuroco-security-audit` — 既存サイトの設定をチェックリストに照らして**読み取り専用で監査**する。本スキルの成果物は、この監査を通る設定になっていることが望ましい
- `/kuroco-admin-mcp` — **対象が異なる。** そちらはAIエージェント自身がKurocoの管理操作を行うためのOAuthスコープ（`mcp:admin`等）であり、本スキルが扱う「サイトの会員」の認証とは無関係。混同しない
- `/kuroco-app-builder` — フェーズ0「認証方式の決定」がAPI認証方式（Cookie/DynamicToken/StaticToken/なし）の4択までは決める。会員グループ・登録フロー・アクセス制限スコープ・パスワードポリシーなど、それより踏み込んだ設計が必要なら本スキルを使う

## 決めること

1. [API認証方式](#1-api認証方式)
2. [会員グループ設計](#2-会員グループ設計)
3. [登録フロー](#3-登録フロー)
4. [コンテンツアクセス制限のスコープ](#4-コンテンツアクセス制限のスコープ)
5. [パスワードポリシー・2要素認証](#5-パスワードポリシー2要素認証)
6. [代理ログインの要否](#6-代理ログインの要否)
7. [エンタープライズSSO・SCIM連携](#7-エンタープライズsso・scim連携)

## 1. API認証方式

| 条件 | 認証方式 |
|------|---------|
| 公開コンテンツのみ（会員機能なし） | 認証なし + キャッシュ |
| 会員機能あり + フロントとAPIを同一親ドメインに揃えられる | Cookie認証 |
| 会員機能あり + クロスドメインのSPA | 動的アクセストークン認証（`X-RCMS-API-ACCESS-TOKEN`ヘッダー） |
| サーバ間通信・公開情報の提供のみ | 静的アクセストークン。会員情報など非公開データには使わない |

**認証方式を決めただけでは会員機能は動かない。** 認証（誰がログインしているか）と認可（そのグループが何を見て・書けるか）は別の設定で、
**両方を設定して初めて通る**。トークン発行やログインが成功しているのに `403` になるのはこの片側漏れが原因で、
Cookie認証でも動的アクセストークンでも同じ。決めるべき権限の中身は[4. コンテンツアクセス制限のスコープ](#4-コンテンツアクセス制限のスコープ)で、
**認証方式の決定とセットで決める**（後回しにすると実装が権限エラーで止まる）。

判断根拠と実装詳細は `/kuroco-api-content`・`/kuroco-frontend-integration` を参照。**静的アクセストークンのうち`privileged_static_token`（無期限ログイン済み資格情報相当）は特に取り扱いに注意**——発行自体に`mcp:admin`スコープが必要で、漏洩時の影響が通常のトークンより大きい。

## 2. 会員グループ設計

会員の権限は、モジュール（`member` / `group` / `topics` 等）ごとの`group_kbn`（作成・更新・削除の可否）の組み合わせで決まる。

**権限昇格経路に注意**: `super_flg=0`の非管理者グループに、`member`と`group`の**両方**への更新・作成権限を与えると、そのグループのメンバーは自分を管理者グループへ追加したり強い権限の新グループを作ったりでき、**実質スーパーユーザーと同等**になる（`super_flg`だけを見ても検出できない）。会員管理を本当に担うグループにのみ、この組み合わせを与える。

**初期グループはフロントエンドから指定できない**（`Member::insert`の`default_group_id`はセキュリティ上、フロント発のリクエストでは設定不可）。ドメインなど条件によって登録時の所属グループを変えたい場合、フロントから直接は制御できない——各グループ固定の内部エンドポイントを複数用意し、公開エンドポイント側のカスタム処理（Smarty）が条件で振り分けて`api_internal`で内部エンドポイントを呼ぶ、という構成が必要。実装は`/kuroco-server-processing`を参照。

IPアドレス範囲でのみスーパーユーザー権限を有効にするグループ設定も存在する（社内ネットワークからのみ強い権限を許可したい場合）。詳細は`/kuroco-docs`の会員認証チュートリアルを参照。

## 3. 登録フロー

同じ`Member`モデルに対する操作の組み合わせで、UXの異なる3パターンを作れる。

| フロー | 操作 | 向くケース |
|--------|------|-----------|
| 即時登録（確認なし） | `Member::insert` | 会員限定コンテンツの敷居を下げたい、本人確認が不要 |
| 招待（管理者主導） | `Member::invite`（管理画面から実行） | 運営側が招待対象を把握・管理したい（社内向けサイト等） |
| 仮登録（セルフサービス＋メール確認） | `Member::invite`を**公開エンドポイントとして公開**（ユーザー自身がメールを投げ、確認リンクから本登録） | 一般消費者向けの会員登録で、メールアドレスの実在確認をしたい |

**仮登録は別の操作ではなく、`Member::invite`を一般公開しているだけ**という点を成果物に明記する。「即時登録」と「仮登録」は同じ`insert`/`invite`の使い分けで両方同時に用意することも可能（`/kuroco-docs`の会員認証チュートリアルに実例あり）。

即時登録を選ぶ場合、`login_ok_flg`の状態次第で登録直後にログイン可能かが変わる点を確認する。

## 4. コンテンツアクセス制限のスコープ

### 認証方式と権限はセットで設定する（片方だけでは通らない）

会員向けAPIが通るには、次の3層が**すべて**そのグループを許していなければならない。
どれか1つでも欠けると `403` になり、症状は「トークンは取れているのに読めない／書けない」という同じ形で出る。

| 層 | 設定するもの | 何を決めるか |
|----|------------|------------|
| API | 認証方式（`cookie` / `dynamic_token` 等） | **誰がログインしているか**を確立する。ここだけ設定しても、データを扱う権限は付かない |
| エンドポイント | APIリクエスト制限（GroupAuth / MemberCustomSearchAuth） | そのエンドポイントを**呼べる**グループ |
| コンテンツ定義（Topics Group） | `secure_level`（**参照**できるグループ）/ `writer_groups`（**追加・更新・削除**できるグループ） | そのグループが**そのデータを扱える**か |

- **参照と書き込みは別の設定。** 一覧・詳細が見えるからといって登録・更新できるとは限らない（逆も同じ）。
  会員が投稿するアプリでは `secure_level` と `writer_groups` の**両方**に対象グループを入れる
- **どちらも空＝制限なし**（`secure_level` が空配列なら誰でも参照可）。「まだ設定していない」と「全体公開」が同じ状態になるので、
  会員限定にする定義では明示的に設定する
- `non_public_flg: 1`（公開APIに出さない内部向け定義）にする場合は **`secure_level` の設定が必須**
- 認証方式によって必要な権限設定は**変わらない**。Cookie認証から動的アクセストークンへ切り替えても、
  コンテンツ定義側の権限はそのまま必要
- フィールド名と設定方法は `/kuroco-content-structure`、`403` の切り分け手順は `/kuroco-api-content` を参照

### 「誰に見せる/編集させるか」の3つの仕組み

会員限定コンテンツの絞り方には3つの独立した仕組みがある。

| 仕組み | 内容 | 向くケース |
|--------|------|-----------|
| GroupAuth | 静的なグループ所属チェック。API・エンドポイント・コンテンツ定義・カテゴリ・個別コンテンツの各レベルで設定でき、この順で優先される | 「このグループのメンバーだけ見せる」という固定的な制限 |
| MemberCustomSearchAuth | 保存済みの会員カスタム検索条件による動的な制限 | グループより柔軟な条件（属性ベース等）で絞りたい場合 |
| `self_only`（個別所有） | ログイン中の本人が作成したレコードのみに絞る。エンドポイントのパラメータとして、または`relation`型フィールドのプロパティとして存在する | 「自分の投稿・データだけ見せる／編集させる」 |

**`self_only`は本スキルと`/kuroco-content-structure`で役割が分かれる**: 「個別所有で絞る」という設計判断自体は本スキルが決め、`relation`フィールドの`self_only`プロパティとしてどう実装するかは`/kuroco-content-structure`が担当する。

**「同じグループのメンバーの投稿だけ見せる」は標準機能ではない。** 管理画面表示トリガー等のカスタム処理が必要で、実装は`/kuroco-server-processing`を参照。会員が複数グループに所属できる設計だと、この種のカスタム制限は意図せず対象外グループの情報まで見せてしまう漏れが起きやすいので、複数グループ所属を許可するかどうかを先に決めておく。

## 5. パスワードポリシー・2要素認証

いずれも[環境設定]→[サイト管理]→ログインで個別に設定するフラグ。**「パスワードポリシーを設定した」を1つの判断で済ませず、以下を1つずつ確認する:**

| 設定 | 内容 | 既定値 | 備考 |
|------|------|--------|------|
| `USE_HASHED_PASSWORD` | パスワードの暗号化保存 | **無効** | **最優先で確認する。** 無効のままだとパスワードが平文で保存される。他の多くの設定の前提でもある |
| `PASSWORD_MIN_LEN` | 最小文字数 | 8 | |
| 強度要件（3種類、個別フラグ） | 英数字・記号の組み合わせ要求 | 無効 | 3つは独立したフラグ。1つ設定して満足しない |
| `CHK_PWD_HISTORY` / `CHK_PWD_LAST_CHANGE` | 過去パスワードの再利用禁止／有効期限 | 無効 | |
| `PASSWORD_BLACKLIST` | 弱いパスワードの拒否リスト | 無効 | |
| `ChangePWDAtFirstLogin` | 初回ログイン時の変更強制 | 無効 | **`USE_HASHED_PASSWORD`が有効でないと機能しない。** 単独では効かない |
| `USE_PASSWORD_CHANGED_MAIL` | パスワード変更通知メール | 無効 | |
| `REMINDER_EXPIRE` | パスワード再設定リンクの有効期限 | 60分 | |

2要素認証は**管理画面向け**と**会員ログイン向け**で別物、混同しない:

- **管理画面2FA**（スタッフ・管理者向け）: `USE_LOGIN_ONETIME_PASSWORD`（TOTP）、`USE_PASSKEY`/`USE_PASSKEY_PASSWORDLESS`、`LOGIN_FORCE_ALL_TFA`。**「必須」にいきなり切り替えると未登録の既存ユーザーがログインできなくなる**——「任意」で全員に登録させてから「必須」にする、という2段階のロールアウトを設計に含める
- **会員ログイン向け2段階認証**: `Login`エンドポイントにEmail/認証アプリ(TOTP)/SMSの2段階認証パラメータが用意されている。ログイン画面・登録画面双方に組み込み可能。管理画面2FAとは設定面が別なので、要件が「会員に2段階認証させたい」なのか「管理画面担当者に2段階認証させたい」なのかを最初に切り分ける

パスワード再設定は`Login::reminder`（仮パスワード・トークンをメール送信）と`Login::reset_password`（現在＋新パスワードで更新）の2エンドポイント。**公開フォーム・パスワードリマインダーにはreCAPTCHAの設定を推奨**（総当たり・自動送信の悪用対策）。

## 6. 代理ログインの要否

サポート・運営担当者が会員になり代わってログインする機能（代理ログイン）が必要かを確認する。

- 用途: 問い合わせ対応時に会員の画面を運営側から再現・操作したい場合
- 設定: 対象会員の編集画面で権限を付与する必要があるが、**利用時（実際に代理ログインする時点）は管理画面へのアクセス権がなくてもフロントエンドの`Login::alias_login`系APIから利用できる**
- 注意: 権限は信頼できるメンバーにのみ付与し、不要になったら剥奪する。操作はログに残る

## 7. エンタープライズSSO・SCIM連携

法人向け・社内向けサイトでは、初期リリース時点でSSO/SCIMを実装しなくても、**「後で他システムと連結する」ことを前提に設計しておく**ケースが多い。今すぐ作るかどうかに関わらず、この節は毎回確認する。

### 何が用意されているか

Kurocoは[外部システム連携]→[ID連携]配下に4種類の仕組みを持つ。**SSOログインとSCIMプロビジョニングは別物**——混同しない。

| 仕組み | 役割 | 主な相手先の例 |
|---|---|---|
| OAuth SP | Kurocoがクライアントとなり、外部IdPでOAuth認証によるSSOログインを行う | GitHub、Microsoft |
| SAML SP | Kurocoがサービスプロバイダとなり、外部IdPとSAML認証でSSOログインを行う | Auth0、Google Workspace、GMOトラスト・ログイン |
| IDaaS SP | CIAM（消費者向けID管理）サービスと連携してSSOログインを行う | Microsoft Entra External ID（旧Azure AD B2C） |
| SCIM SP | **ログインではなく、外部IdPからのメンバー情報の自動同期（作成・更新・無効化）** | Microsoft Entra ID |

**同時に有効にできるSCIM SPは1サイトにつき1つだけ。** 複数のIdPからのプロビジョニングを両立させたい場合は事前に伝える。

### SSOのトークンは、既存の動的アクセストークン認証と同じ仕組みに乗る

SSO認証成功後の流れは、`grant_token`（1回限り・短命）→ tokenエンドポイントで`access_token`/`refresh_token`に交換 → `X-RCMS-API-ACCESS-TOKEN`ヘッダーでAPIを呼ぶ、という**動的アクセストークン認証と全く同じ`token`/`profile`エンドポイント**を使う。

**設計上の含意**: 「今回はCookie認証で作るが、将来SSOを足すかもしれない」という場合、**動的アクセストークン認証を選んでおく方がSSOの後付けと相性がよい**（ドキュメント化されたSSOフローは動的アクセストークンの仕組みの上に成り立っている）。Cookie認証でのSSO対応は一次資料で確認できていない——Cookie認証のまま進めるなら、その旨と後で認証方式ごと切り替えが必要になりうる可能性を成果物に明記する。1.のAPI認証方式の選択に、この理由を持ち込んでよい。

また、動的アクセストークン認証では**ログインセッションはAPI（`api_id`）単位でスコープされる**。SSO対応が必要なエンドポイントは、後から分割すると手戻りになるため、最初から同一の`api_id`にまとめておく。

### 「後で連結する」場合に今のうちにやっておくこと

| やること | 理由 |
|---|---|
| 認証方式を動的アクセストークンにしておく（上記） | Cookie認証だとSSO追加時に認証方式ごと見直す可能性がある |
| SSO対象エンドポイントを1つの`api_id`にまとめておく | 動的アクセストークンのセッションはAPI単位。後から分割すると手戻り |
| SCIMを見据えるなら、外部ID保存用のメンバー拡張項目（テキスト型）を先に1つ用意しておく | SCIMのメンバー紐付けは「①メンバーID→②外部ID保存用の拡張項目→③メールアドレス→④新規作成」の優先順位。②の項目が無いと初回プロビジョニングをメールアドレス一致に頼ることになる。メンバー拡張項目数の上限は`whoami`の`site.limits.member_max_extension`（`max`は999）で確認する |
| SCIM/SAMLで同期される属性（氏名・メールアドレス等）は、導入後に管理画面から直接編集しないという運用ルールを事前に共有する | 次回同期でIdP側の値に上書きされるため |
| グループの権限設計はKuroco側の責務として残ることを明確にしておく | SCIMはグループの作成・メンバー割り当てまでは同期するが、**グループの権限設定はKuroco側で個別に行う必要がある**（2.の会員グループ設計と地続き） |

### 判断が必要なとき

「今は使わないが後で連携する可能性がある」という要件が出たら、上記5点を成果物の「確認事項」または「今後の拡張ポイント」として明記し、**今すぐ実装するかどうか**をユーザーに確認する。実装する場合の具体的な手順（管理画面操作、フロントのgrant_token交換コード等）は`/kuroco-frontend-integration`および`/kuroco-docs`の該当チュートリアルに委譲する——本スキルは「どの方式を選ぶか」「今の設計にどう影響するか」までを扱う。

## 成果物テンプレート

```markdown
## 認証・会員設計
- API認証方式: （1.の選択と理由）
- 会員グループ: （階層・初期グループの決め方・昇格経路チェック済みか）
- 登録フロー: 即時登録 / 招待 / 仮登録（選択と理由）
- コンテンツアクセス制限: GroupAuth / MemberCustomSearchAuth / self_only（対象コンテンツごとに明記）
- パスワードポリシー: USE_HASHED_PASSWORD＝有効/無効、その他フラグの設定値
- 2要素認証: 管理画面（対象・ロールアウト計画）／会員ログイン（要否）
- 代理ログイン: 要否、必要なら付与対象
- SSO/SCIM: 今すぐ実装するか／将来のための布石か（動的アクセストークンの選択理由・外部ID拡張項目の有無・対象api_idのまとめ方）
```

## アンチパターン

| してはいけないこと | 理由 |
|------|------|
| 編集用グループに気づかず`member`＋`group`両方の書き込み権限を与える | 権限昇格経路になる（2.参照）。`super_flg`だけ確認しても検出できない |
| ドメインで初期グループを分けたいのにフロントから`default_group_id`を渡せると想定する | セキュリティ上フロントからは指定不可。内部エンドポイント＋振り分け処理が必要 |
| `USE_HASHED_PASSWORD`を確認せず`ChangePWDAtFirstLogin`だけ有効化する | 前提条件が満たされず機能しない |
| 管理画面2FAをいきなり「必須」にする | 未登録の既存ユーザーがログイン不能になる。任意→登録期間→必須の順で進める |
| 管理画面2FAと会員ログインの2段階認証を同じ設定だと思い込む | 設定面が完全に別。要件をどちらか切り分けてから設定する |
| 公開フォーム・パスワードリマインダーにreCAPTCHAを付けない | 総当たり・自動送信の標的になりやすい |
| 「将来SSOを足すかも」と言われてもCookie認証のまま設計を進める | SSOの文書化されたフローは動的アクセストークン認証の仕組みに乗っている。後から認証方式ごと見直す事態になりうる |
| SCIM連携を見据えず、外部ID保存用のメンバー拡張項目を用意しないまま進める | 初回プロビジョニングがメールアドレス一致だけに頼ることになる |
| SSOログインとSCIMプロビジョニングを同じものだと思い込む | 別機能。SCIMはメンバー情報の自動同期であり、ログイン方式ではない |

## 関連スキル

| スキル | 役割 |
|--------|------|
| `/kuroco-frontend-integration` | ここで決めた認証方式・フローの実装コード |
| `/kuroco-api-content` | 認証方式の設定詳細、閲覧/編集制限の優先順序 |
| `/kuroco-content-structure` | `self_only`等でスコープを個別所有にする場合のフィールド設計 |
| `/kuroco-server-processing` | ドメイン別グループ振り分け、同グループ限定表示などのカスタム処理 |
| `/kuroco-security-audit` | 本スキルで決めた設定が実際にチェックリストを通るか監査する（読み取り専用） |
| `/kuroco-admin-mcp` | （対象外）AIエージェント自身のAdmin MCP OAuthスコープ。会員認証とは別物 |
| `/kuroco-app-builder` | フェーズ0の認証方式決定を深掘りする場合に使う |

