diff --git a/CLAUDE.md b/CLAUDE.md index 5d75feb..bdb2b4e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -18,6 +18,8 @@ The repository ships a Claude skills library at [plugin/skills/](plugin/skills/) The library's default "build me an app" entry point is [`skills/formio-application/`](skills/formio-application/) — a framework-agnostic orchestrator that runs the full pipeline from plain-language intent through `formio-resource-planner`, the `project_import` MCP tool, and handoff to a framework-specific scaffolding skill. Today the only framework implementor is [`skills/formio-angular/`](skills/formio-angular/) (with its sub-skill [`skills/formio-angular/resources/`](skills/formio-angular/resources/) for per-resource NgModule work); `formio-angular` is no longer a top-level build-an-app skill — it is the Angular-specific implementor that `formio-application` delegates to. Future framework skills (`formio-react`, etc.) add themselves as rows in `skills/formio-application/FRAMEWORK.md`'s registry table; no other change to the orchestrator is required. +Authentication and authorization are owned by a stand-alone peer skill at [`skills/formio-auth/`](plugin/skills/formio-auth/). The planner ↔ auth handoff contract is explicit: `formio-resource-planner` owns the data model (roles, the `user` Resource, login/registration forms, group joins) and emits the canonical `template.json` shapes for the Login Action, Role Assignment Action, Group Assignment Action, `access` arrays, `submissionAccess` arrays, and field-based `submissionAccess` on group-reference selects. `formio-auth` owns the auth configuration that runs on top of that model — SSO (OIDC / OAuth, SAML, LDAP) with provider Role Mapping, Token Swap from an external OIDC token, Custom JWT (Enterprise / on-prem, signed with `JWT_SECRET`), email-token (passwordless) authentication, JWT and session mechanics (the `x-jwt-token` header, `jti` Session ID, logout semantics, 2FA, reCAPTCHA), and RBAC tuning beyond default roles. Action JSON shapes are NOT duplicated across the two skills; `formio-auth` references the planner's `references/template-json.md` by file path. When a planner-produced Resource Map's `Users & Auth` section emits a non-`none` `SSO` field, a `Custom JWT: yes`, or any other auth concern beyond resource-backed login plus Role Assignment plus Group Assignment, hand off to `formio-auth` immediately after the Resource Map is approved. + The library also ships [`skills/formio-sdk/`](plugin/skills/formio-sdk/) — a source-derived reference for the `@formio/js` SDK and `@formio/js/utils` Utilities, authored directly from the Form.io source code (`packages/core/src/sdk`, `packages/core/src/utils`, `packages/formio.js/src/Formio.js`, `packages/formio.js/src/utils`) rather than from drift-prone online docs. Reference docs cover SDK setup, auth, forms, submissions, projects, roles, files, plugins, VanillaJS rendering (`Formio.createForm`), and the Utils surface (Evaluator, form traversal, conditions, logic, JSONLogic, mask/sanitize, misc). The skill mandates ESM imports (`import { Formio } from '@formio/js'`, `import { Utils } from '@formio/js/utils'`) and explicit Hosted-vs-SaaS URL configuration. The router skill's `description` follows a three-clause template: capability statement, a "Use when the user asks to …" trigger clause, and a "Not for: …" negative-trigger clause disambiguating from `formio-application` (orchestrator) and `formio-resource-planner` (planner). Each reference document includes a `## MCP Tool Preference` section instructing Claude to prefer the MCP server's first-party tools (`form_*`, `role_*`, `project_*`, `authenticate`) when they cover the requested operation. diff --git a/openspec/changes/archive/2026-05-22-add-formio-auth-skill/.openspec.yaml b/openspec/changes/archive/2026-05-22-add-formio-auth-skill/.openspec.yaml new file mode 100644 index 0000000..a5aaf30 --- /dev/null +++ b/openspec/changes/archive/2026-05-22-add-formio-auth-skill/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-tdd +created: 2026-05-22 diff --git a/openspec/changes/archive/2026-05-22-add-formio-auth-skill/design.md b/openspec/changes/archive/2026-05-22-add-formio-auth-skill/design.md new file mode 100644 index 0000000..645970b --- /dev/null +++ b/openspec/changes/archive/2026-05-22-add-formio-auth-skill/design.md @@ -0,0 +1,143 @@ +## Context + +Today, Form.io auth knowledge sits inside `plugin/skills/formio-resource-planner/`: + +- `SKILL.md` lines 38–90, 122–129, 150–152, 184–209, 263, 270–295 — role taxonomy, `access` vs `submissionAccess`, action ordering, group-based access "two halves" model +- `references/template-json.md` lines 34–81, 102–158, 297–376, 504–590 — JSON shapes for roles, top-level access, `submissionAccess` patterns, Login / Role Assignment / Group Assignment actions, field-based `submissionAccess` on group-reference selects, transitive group-access mirrors +- `references/template-md.md` lines 68–114, 211–270 — Resource Map "Roles" and "Users & Auth" sections, Access Matrix vocabulary, Access Flow Diagram patterns +- `references/examples/task-manager/template.json` — working end-to-end auth wiring +- `references/examples/complex-crm-transitive/` — multi-level transitive group access + +What is **not** there today: SSO (OIDC, SAML, LDAP), Token Swap, Custom JWT, email-token, 2FA/reCAPTCHA, the full eight-permission RBAC matrix, JWT/session/`jti` semantics, the `x-jwt-token` header on the wire, project-level vs form-definition vs submission-data permission scoping as documented at https://help.form.io/developers/roles-and-permissions. + +The two top-level skills that border this work are: + +- **`formio-resource-planner`** — plans roles, login/registration forms, joins, and `submissionAccess` patterns as part of resource design; emits `template.json`. +- **`formio-application`** — full-stack orchestrator that runs planner → `project_import` → framework scaffolding (Angular today). It calls into auth only transitively. + +Neither is the right home for "explain OIDC Role Mapping" or "how do I forge a Custom JWT for on-prem". We need a peer skill — narrative, reference-driven — that owns auth end-to-end. + +The skills validator (`packages/mcp-server/src/skills-validator.ts`, 476 lines) is scoped only to `formio-api` (the router with `ROUTER_DIR = 'formio-api'`). It does not enforce shape rules on narrative skills, so adding `formio-auth` requires no validator change. Skills are auto-discovered from `plugin/skills/` — no plugin manifest update needed. + +Stakeholders: skill authors, agents using the plugin to build/extend Form.io apps, users with SSO or custom-JWT requirements that the planner cannot address. + +## Goals / Non-Goals + +**Goals:** + +- Stand up `plugin/skills/formio-auth/` as a first-class, activatable skill on auth-only triggers. +- Cover the full Form.io auth surface in topic-scoped reference docs: resource login + Login Action, Role Assignment Action, login/registration form shapes, RBAC (roles + the eight permission types across project/form/submission scopes), Group Permissions (single + transitive), SSO (OIDC, SAML, LDAP), Token Swap, Custom JWT, email-token, JWT/session/`jti` semantics, 2FA, reCAPTCHA. +- Make `formio-auth` and `formio-resource-planner` interoperable: each names the other in handoff prose, and `formio-resource-planner` stops claiming SSO/Token-Swap/Custom-JWT/email-token triggers it does not actually cover. +- Use the existing planner JSON shapes (Login Action, Role Assignment Action, Group Assignment Action, `submissionAccess` patterns) as the single source of truth for emitted `template.json` snippets — `formio-auth` references and reuses those, not forks them. +- Prefer first-party MCP tools (`authenticate`, `role_*`, `form_*`, `action_*`, `project_*`) in MCP Tool Preference sections, matching the convention in `formio-api`'s references. + +**Non-Goals:** + +- No new MCP tools. Auth is configured via existing tools and via the Form.io project portal where appropriate. +- No `formio-auth` eval harness in this change. Pattern is `formio-resource-planner` / `formio-angular`; can be added later under `plugin/skills/formio-auth/evals/`. +- No validator changes. The validator stays scoped to `formio-api`; narrative skills are unchecked for shape today and that stays true here. +- No Angular/React/etc. front-end auth wiring. Framework-specific auth UI is the job of `formio-angular` (and future framework skills), which can reference `formio-auth` for the Form.io side of the contract. +- No removal of auth content from `formio-resource-planner` that is load-bearing for resource emission (action JSON shapes, role objects, `submissionAccess` patterns stay where they are). Only narrative scoping and the trigger surface change. + +## Decisions + +### 1. Layout: SKILL.md + topic-scoped references/, mirroring `formio-resource-planner`, not `formio-api` + +`formio-api` is an endpoint catalog (one file per capability group, strict heading layout enforced by the validator). `formio-auth` is a narrative skill (concepts, configuration walkthroughs, decision trees) — closer in shape to `formio-resource-planner`. + +``` +plugin/skills/formio-auth/ +├── SKILL.md +└── references/ + ├── resource-auth.md + ├── login-forms.md + ├── roles-and-permissions.md + ├── group-permissions.md + ├── sso-oidc.md + ├── sso-saml.md + ├── sso-ldap.md + ├── token-swap.md + ├── custom-jwt.md + ├── email-auth.md + └── jwt-and-sessions.md +``` + +**Alternative considered:** Drop everything into a single big `SKILL.md`. Rejected — auth has eleven distinct sub-topics and an agent should be able to navigate to one without loading the others into context. + +**Alternative considered:** Add `formio-auth` as a sub-skill under `formio-resource-planner/`. Rejected — auth questions are common without a planning context (e.g., wiring SSO into an existing project), and forcing the planner to be the entry point makes activation worse, not better. + +### 2. Activation: three-clause description, auth-only triggers, explicit negative-triggers against planner + application + +Skills activate from `description` content. To avoid stealing planner traffic, `formio-auth`'s description follows the same three-clause template used elsewhere in this repo: + +> *Capability statement.* *Use when the user asks to …* *Not for: …* + +- **Use when** triggers (claimed): login flow, JWT, `x-jwt-token`, SSO, OIDC, OAuth, SAML, LDAP, Token Swap, Custom JWT, `JWT_SECRET`, email token, passwordless, roles, permissions, RBAC, group permissions, "who can read/update/delete", `read_own`/`read_all`/etc., 2FA, reCAPTCHA, Login Action, Role Assignment Action, Group Assignment Action. +- **Not for** (disambiguated): + - Resource/data modeling, building an app from scratch, planning the resource map → `formio-resource-planner`. + - Full-stack scaffolding (run planner → import → scaffold a framework) → `formio-application`. + - Looking up a specific REST endpoint → `formio-api`. + - Front-end UI wiring (Angular login screen, route guards) → `formio-angular`. + +**Alternative considered:** No negative-trigger clause, rely on positive triggers alone. Rejected — the planner today claims terms like "roles", "permissions", "login form" as part of resource design. Without explicit negative-triggers on the planner side AND positive auth-specific claims on the auth side, the two skills race. + +### 3. Cross-skill handoff contract + +Two directions: + +- **Planner → Auth**: After `formio-resource-planner` emits a Resource Map's "Users & Auth" line (`Login: