@tideorg/mcp 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/GAP_REGISTER.md +117 -0
  2. package/README.md +38 -0
  3. package/adapters/AGENTS.md +241 -0
  4. package/adapters/CLAUDE.md +146 -0
  5. package/adapters/replit.md +224 -0
  6. package/canon/anti-patterns.md +2133 -0
  7. package/canon/concepts.md +816 -0
  8. package/canon/custom-contracts.md +533 -0
  9. package/canon/delegation.md +195 -0
  10. package/canon/feature-mapping.md +637 -0
  11. package/canon/framework-matrix.md +1125 -0
  12. package/canon/invariants.md +851 -0
  13. package/canon/redirect-handler.md +254 -0
  14. package/canon/tidecloak-bootstrap.md +287 -0
  15. package/canon/tidecloak-endpoints.md +294 -0
  16. package/canon/troubleshooting.md +1494 -0
  17. package/canon/version-policy.md +89 -0
  18. package/mcp-server/dist/index.d.ts +2 -0
  19. package/mcp-server/dist/index.js +605 -0
  20. package/package.json +45 -0
  21. package/playbooks/add-auth-nextjs-existing.md +799 -0
  22. package/playbooks/add-auth-nextjs-fresh.md +654 -0
  23. package/playbooks/add-rbac-nextjs.md +190 -0
  24. package/playbooks/bootstrap-realm-from-template.md +170 -0
  25. package/playbooks/configure-e2ee-roles-and-policies.md +196 -0
  26. package/playbooks/deploy-tidecloak-docker.md +792 -0
  27. package/playbooks/diagnose-broken-login.md +234 -0
  28. package/playbooks/diagnose-missing-roles-or-claims.md +253 -0
  29. package/playbooks/initialize-admin-and-link-account.md +235 -0
  30. package/playbooks/migrate-from-existing-auth.md +198 -0
  31. package/playbooks/protect-api-nextjs.md +451 -0
  32. package/playbooks/protect-routes-nextjs.md +544 -0
  33. package/playbooks/setup-forseti-e2ee.md +756 -0
  34. package/playbooks/setup-iga-admin-panel.md +344 -0
  35. package/playbooks/setup-server-delegation.md +142 -0
  36. package/playbooks/start-tidecloak-dev.md +130 -0
  37. package/playbooks/verify-jwt-server-side.md +439 -0
  38. package/prompts/add-admin-approval-flow.md +50 -0
  39. package/prompts/build-private-customer-portal.md +85 -0
  40. package/prompts/migrate-generic-auth-to-tide.md +67 -0
  41. package/prompts/secure-existing-app.md +80 -0
  42. package/reference-apps/INDEX.md +87 -0
  43. package/reference-apps/encrypted-communication/anti-patterns.md +123 -0
  44. package/reference-apps/encrypted-communication/bootstrap-sequence.md +152 -0
  45. package/reference-apps/encrypted-communication/manifest.yaml +100 -0
  46. package/reference-apps/encrypted-communication/role-policy-matrix.md +80 -0
  47. package/reference-apps/encrypted-communication/scenario.md +134 -0
  48. package/reference-apps/git-pr-signing-service/anti-patterns.md +61 -0
  49. package/reference-apps/git-pr-signing-service/bootstrap-sequence.md +157 -0
  50. package/reference-apps/git-pr-signing-service/manifest.yaml +80 -0
  51. package/reference-apps/git-pr-signing-service/role-policy-matrix.md +99 -0
  52. package/reference-apps/git-pr-signing-service/scenario.md +169 -0
  53. package/reference-apps/iga-admin-governance/anti-patterns.md +133 -0
  54. package/reference-apps/iga-admin-governance/bootstrap-sequence.md +153 -0
  55. package/reference-apps/iga-admin-governance/manifest.yaml +87 -0
  56. package/reference-apps/iga-admin-governance/role-policy-matrix.md +67 -0
  57. package/reference-apps/iga-admin-governance/scenario.md +126 -0
  58. package/reference-apps/organisation-password-manager/anti-patterns.md +71 -0
  59. package/reference-apps/organisation-password-manager/bootstrap-sequence.md +127 -0
  60. package/reference-apps/organisation-password-manager/manifest.yaml +86 -0
  61. package/reference-apps/organisation-password-manager/role-policy-matrix.md +59 -0
  62. package/reference-apps/organisation-password-manager/scenario.md +107 -0
  63. package/reference-apps/policy-governed-signing/anti-patterns.md +67 -0
  64. package/reference-apps/policy-governed-signing/bootstrap-sequence.md +128 -0
  65. package/reference-apps/policy-governed-signing/manifest.yaml +78 -0
  66. package/reference-apps/policy-governed-signing/role-policy-matrix.md +62 -0
  67. package/reference-apps/policy-governed-signing/scenario.md +113 -0
  68. package/skills/tide-diagnostics/SKILL.md +99 -0
  69. package/skills/tide-integration/SKILL.md +136 -0
  70. package/skills/tide-learning-capture/SKILL.md +174 -0
  71. package/skills/tide-rbac-and-e2ee/SKILL.md +214 -0
  72. package/skills/tide-reviewer/SKILL.md +133 -0
  73. package/skills/tide-route-and-api-protection/SKILL.md +201 -0
  74. package/skills/tide-scenario-resolver/SKILL.md +81 -0
  75. package/skills/tide-setup/SKILL.md +218 -0
  76. package/skills/tide-solutions-architect/SKILL.md +130 -0
@@ -0,0 +1,128 @@
1
+ # Bootstrap Sequence — Policy-Governed Signing
2
+
3
+ All steps must complete before users can safely use signing features. Order matters.
4
+
5
+ ## Phase 1: TideCloak infrastructure
6
+
7
+ 1. **Start TideCloak container**
8
+ - Use `tidecloak-dev` (development) or `tidecloak-stg-dev` (staging with ORK env vars).
9
+ - Staging requires `SYSTEM_HOME_ORK`, `USER_HOME_ORK`, `THRESHOLD_T`, `THRESHOLD_N`.
10
+ - Wait for readiness: `curl http://localhost:8080/health/ready` returns 200.
11
+
12
+ 2. **Obtain bootstrap admin token**
13
+ - `POST /realms/master/protocol/openid-connect/token` with `KC_BOOTSTRAP_ADMIN_USERNAME` / `KC_BOOTSTRAP_ADMIN_PASSWORD`.
14
+
15
+ ## Phase 2: Realm and client setup
16
+
17
+ 3. **Import realm template**
18
+ - `POST /admin/realms` with `realm.json`.
19
+ - Template must declare: realm name, OIDC client, `_tide_enabled` role, default-roles composite, protocol mappers.
20
+ - Template should include redirect URIs for all clients.
21
+
22
+ 4. **License the realm**
23
+ - `POST /admin/realms/{realm}/vendorResources/setUpTideRealm` with admin email.
24
+ - Content-Type: `application/x-www-form-urlencoded`. Body: `email=admin@example.com`.
25
+ - Returns licensing JSON as `text/plain`.
26
+
27
+ 5. **Enable IGA**
28
+ - `POST /admin/realms/{realm}/tide-admin/toggle-iga` with form-urlencoded `isIGAEnabled=true`.
29
+ - Must happen after licensing. Enables change-set governance for role/user mutations.
30
+
31
+ ## Phase 3: Approve initial change-sets
32
+
33
+ 6. **Approve client change-sets**
34
+ - IGA creates draft change-sets for client mutations during realm import.
35
+ - List: `GET /admin/realms/{realm}/tide-admin/change-set/clients/requests`.
36
+ - For each: sign (`POST .../change-set/sign`) then commit (`POST .../change-set/commit`).
37
+
38
+ ## Phase 4: Admin user setup
39
+
40
+ 7. **Create admin user**
41
+ - `POST /admin/realms/{realm}/users` with username, email, enabled=true.
42
+
43
+ 8. **Assign `tide-realm-admin` role**
44
+ - Get role ID: `GET /admin/realms/{realm}/clients/{realm-mgmt-client-id}/roles` and find `tide-realm-admin`.
45
+ - Assign: `POST /admin/realms/{realm}/users/{userId}/role-mappings/clients/{realm-mgmt-client-id}`.
46
+
47
+ 9. **Generate account-linking invite**
48
+ - `POST /admin/realms/{realm}/tideAdminResources/get-required-action-link?userId={userId}&lifespan=43200` with body `["link-tide-account-action"]`.
49
+ - Admin must complete this link in a browser to bind their identity to the Tide Fabric.
50
+
51
+ 10. **Wait for account linking**
52
+ - Poll `GET /admin/realms/{realm}/users/{userId}` until `attributes.tideUserKey` and `attributes.vuid` are present.
53
+ - Do not proceed until both attributes exist.
54
+
55
+ ## Phase 5: Approve user change-sets
56
+
57
+ 11. **Approve user change-sets**
58
+ - List: `GET /admin/realms/{realm}/tide-admin/change-set/users/requests`.
59
+ - For each: sign then commit.
60
+
61
+ ## Phase 6: IDP settings and adapter export
62
+
63
+ 12. **Configure IDP settings (optional)**
64
+ - Upload branding (logo, background) if desired.
65
+ - Set `CustomAdminUIDomain` if a separate app hosts the approval/admin UI.
66
+
67
+ 13. **Sign IDP settings**
68
+ - `POST /admin/realms/{realm}/vendorResources/sign-idp-settings`.
69
+ - Required after any IDP config change. Without it, the enclave rejects settings as unsigned.
70
+
71
+ 14. **Export adapter JSON**
72
+ - `GET /admin/realms/{realm}/vendorResources/get-installations-provider?clientId={clientUUID}&providerId=keycloak-oidc-keycloak-json`.
73
+ - Save to app config path (e.g., `data/tidecloak.json`).
74
+ - Verify `jwk`, `vendorId`, `homeOrkUrl`, `client-origin-auth-*` fields are present.
75
+ - If `jwk` is missing: IGA was not enabled before export. Re-enable IGA and re-export.
76
+
77
+ ## Phase 7: Signing role and policy setup (admin-driven)
78
+
79
+ 15. **Create signing roles**
80
+ - Admin creates client roles via app UI or TideCloak admin API.
81
+ - Role names follow app-specific prefix pattern (e.g., `ssh:<username>`).
82
+ - Role creation goes through IGA change-set when IGA is enabled.
83
+ - Approve and commit role change-sets.
84
+
85
+ 16. **Assign signing roles to users**
86
+ - Admin assigns roles to users via app UI or TideCloak admin API.
87
+ - Role assignment goes through IGA change-set.
88
+ - Approve and commit.
89
+
90
+ 17. **Create and approve signing policies**
91
+ - Admin creates a PolicySignRequest with:
92
+ - Forseti contract source code (C# implementing `IAccessPolicy`)
93
+ - Policy parameters (`Role`, `Resource`, `threshold`, `approval_type`, `execution_type`)
94
+ - Model ID (e.g., `BasicCustom<SSH>:BasicCustom<1>`)
95
+ - Contract transport (source + entry type)
96
+ - PolicyApproval must be signed and committed so `signed_policy_data` is populated.
97
+ - Until committed, signing requests for that role will fail.
98
+
99
+ ## Phase 8: App readiness
100
+
101
+ 18. **Place adapter JSON in app**
102
+ - Express/Node: `data/tidecloak.json`
103
+ - Next.js: `data/tidecloak.json`
104
+ - React/Vite or Vanilla: `public/tidecloak.json`
105
+
106
+ 19. **Configure CSP**
107
+ - Add `frame-src '*'` to Content-Security-Policy. Required for ORK enclave iframe.
108
+
109
+ 20. **Start app server**
110
+ - App must be able to reach TideCloak at the URL in `auth-server-url`.
111
+ - App must serve the redirect handler at the configured `redirectUri` path.
112
+ - App must serve `silent-check-sso.html` in `public/` for session refresh.
113
+
114
+ ## Pre-user checklist
115
+
116
+ Before any user accesses signing features, verify:
117
+
118
+ - [ ] TideCloak healthy (`/health/ready` returns 200)
119
+ - [ ] Realm licensed and IGA enabled
120
+ - [ ] At least one admin with linked Tide account
121
+ - [ ] All pending change-sets approved and committed (clients, users, roles)
122
+ - [ ] At least one signing role created and assigned to a user
123
+ - [ ] Signing PolicyApproval committed with non-empty `signed_policy_data` for each role
124
+ - [ ] Adapter JSON exported with `jwk`, `vendorId`, `homeOrkUrl`
125
+ - [ ] `sign-idp-settings` called
126
+ - [ ] App server running with JWT + DPoP verification on protected endpoints
127
+ - [ ] Redirect handler present at `redirectUri` path
128
+ - [ ] CSP includes `frame-src '*'`
@@ -0,0 +1,78 @@
1
+ # Policy-Governed Signing — Scenario Manifest
2
+
3
+ id: policy-governed-signing
4
+ title: Policy-Governed Signing
5
+ category: threshold-signing
6
+ description: Cryptographic signing authorized by Forseti contracts on the ORK network; no single entity holds the signing key
7
+
8
+ frameworks:
9
+ - nextjs
10
+ - react-vite
11
+ - vanilla
12
+
13
+ core_patterns:
14
+ - forseti
15
+ - doken
16
+ - dpop
17
+ - iga
18
+ - oidc
19
+ - threshold-signing
20
+ - policy-signing
21
+ - custom-request
22
+ - basic-custom-request
23
+ - dynamic-custom-request
24
+ - policy-sign-request
25
+ - client-roles
26
+ - signing
27
+ - ssh
28
+ - keyless
29
+
30
+ match_keywords:
31
+ - policy signing
32
+ - threshold signing
33
+ - keyless ssh
34
+ - keyless signing
35
+ - ssh signing
36
+ - challenge signing
37
+ - document signing
38
+ - transaction signing
39
+ - forseti signing
40
+ - ork signing
41
+ - decentralised signing
42
+ - decentralized signing
43
+ - policy-governed
44
+ - sign with tide
45
+ - blockchain signing
46
+ - cryptocurrency wallet
47
+ - wallet signing
48
+ - blockchain transaction
49
+ - crypto wallet
50
+ - tide signing
51
+
52
+ bootstrap_required: true
53
+ requires_admin_preapproval: true
54
+ requires_iga: true
55
+ requires_e2ee: false
56
+ signing_mode: policy-governed
57
+
58
+ default_roles:
59
+ - _tide_enabled
60
+
61
+ policy_roles: []
62
+
63
+ signing_role_pattern: "<prefix>:<name>"
64
+
65
+ default_playbooks:
66
+ - start-tidecloak-dev
67
+ - bootstrap-realm-from-template
68
+ - initialize-admin-and-link-account
69
+ - add-auth-nextjs-fresh
70
+ - protect-routes-nextjs
71
+ - protect-api-nextjs
72
+ - verify-jwt-server-side
73
+ - add-rbac-nextjs
74
+
75
+ discriminating_question: Does the app produce cryptographic signatures (SSH challenges, document signing, transaction approval)? If the app encrypts/decrypts data instead, use an encryption scenario.
76
+ valid_only_when: App needs ORK-mediated threshold signing, not encryption.
77
+
78
+ notes: No encryption layer. Signing roles and policies are created by admin at runtime via app UI or API. Forseti contracts validate data, approvers, and executor before ORKs produce signature. Uses BasicCustomRequest or DynamicCustomRequest pattern. Replace <prefix>:<name> with app-specific pattern (e.g., ssh:root, sign:document, tx:payment).
@@ -0,0 +1,62 @@
1
+ # Role-Policy Matrix — Policy-Governed Signing
2
+
3
+ ## Tide bootstrap roles
4
+
5
+ | Role | Purpose | Attached policy | Created by | Approved by | Required before first use | Default / optional | Notes |
6
+ |------|---------|----------------|------------|-------------|--------------------------|-------------------|-------|
7
+ | `_tide_enabled` | Enables Tide operations for user | None (gate role) | Realm template | N/A (declared in realm.json) | Yes | Default | Must be in realm.json. Not auto-created. |
8
+ | `tide-realm-admin` | Full realm administration | N/A | Bootstrap script | N/A (first admin) | Yes (at least one) | Required | Client role on `realm-management`, not a realm role. |
9
+
10
+ ## Signing roles (Forseti contract-backed)
11
+
12
+ | Role | Purpose | Attached policy | Created by | Approved by | Required before first use | Default / optional | Notes |
13
+ |------|---------|----------------|------------|-------------|--------------------------|-------------------|-------|
14
+ | `<prefix>:<name>` (e.g., `ssh:root`) | Authorizes signing operations for a specific resource | Forseti contract with `signed_policy_data`; validates data, approvers, executor | Admin via app UI | Tide realm admin(s) via IGA | Yes (for that resource) | Per-resource | PolicyApproval must be committed with `signed_policy_data` before signing works for this role. |
15
+
16
+ ## Key rules
17
+
18
+ 1. `_tide_enabled` must be declared in `realm.json`. It is not auto-created by `setUpTideRealm`.
19
+ 2. Signing roles are client roles on the app's OIDC client, not realm roles.
20
+ 3. Each signing role requires a committed PolicyApproval with `signed_policy_data` before the ORKs will authorize signing for that role.
21
+ 4. Role assignment changes go through IGA change-sets when IGA is enabled. Roles appear in JWT/doken after next token refresh (up to 120s delay).
22
+ 5. `tide-realm-admin` is a client role on `realm-management`, not a realm role.
23
+ 6. The Forseti contract's `ValidateExecutor` must check that the executor's doken contains the required signing role.
24
+ 7. The Forseti contract's `ValidateApprovers` checks that approvers hold appropriate roles (e.g., `tide-realm-admin` or the signing role itself).
25
+ 8. The Forseti contract's `ValidateData` validates the data being signed (e.g., SSH challenge structure, document hash format).
26
+
27
+ ## Forseti contract structure
28
+
29
+ The signing contract implements `IAccessPolicy` with three validators:
30
+
31
+ | Validator | What it checks |
32
+ |-----------|---------------|
33
+ | `ValidateData` | Validates the data payload being signed. App-specific: SSH contracts parse SSHv2 publickey challenge; document contracts check hash format. |
34
+ | `ValidateApprovers` | Checks that approvers hold the required role on the correct resource. Uses `DokenDto.WrapAll()` and `Decision.RequireAnyWithRole()`. |
35
+ | `ValidateExecutor` | Checks that the executor's doken is not expired and holds the required signing role. Uses `Decision.RequireNotExpired()` and `Decision.RequireRole()`. |
36
+
37
+ ## Policy parameters
38
+
39
+ Forseti contracts use `[PolicyParam]` attributes for automatic parameter binding from the policy `params` map:
40
+
41
+ | Parameter | Type | Required | Purpose |
42
+ |-----------|------|----------|---------|
43
+ | `Role` | string | Yes | The client role required for signing (e.g., `ssh:root`) |
44
+ | `Resource` | string | Yes | The client/resource ID for role lookup |
45
+ | `threshold` | number | Yes | Minimum number of approvers required |
46
+ | `approval_type` | string | Yes | `implicit` (doken-only) or `explicit` (requires operator approval popup) |
47
+ | `execution_type` | string | Yes | `public` or `private` |
48
+
49
+ ## Request patterns
50
+
51
+ | Pattern | Model ID format | When to use |
52
+ |---------|----------------|-------------|
53
+ | `BasicCustomRequest` | `BasicCustom<Name>:BasicCustom<Version>` | Data to sign is known at request creation time and does not change |
54
+ | `DynamicCustomRequest` | `DynamicCustom<Name>:DynamicCustom<Version>` | Data to sign may change between authorization and signing |
55
+
56
+ ## Contract transport structure [OBSERVED_PATTERN]
57
+
58
+ PolicySignRequest draft contains:
59
+ 1. Policy bytes (serialized `Policy` object)
60
+ 2. Contract transport: `[contractType("forseti"), [emptyBytes, [sourceCode, entryType("Contract")]]]`
61
+
62
+ This is constructed via `TideMemory.CreateFromArray` nesting. The contract ID is the SHA-512 hash of the source code.
@@ -0,0 +1,113 @@
1
+ # Policy-Governed Signing
2
+
3
+ ## What this is
4
+
5
+ An application where cryptographic signing operations are authorized by Forseti contracts running on the ORK network. The user authenticates via TideCloak OIDC, receives a doken, and when the app needs a signature (e.g., SSH challenge, document signing, transaction approval), the ORKs validate the request against a Forseti contract before collaboratively producing the signature.
6
+
7
+ No single entity holds the signing key. The key is mathematically split across independent ORKs via threshold cryptography.
8
+
9
+ ## When to use this scenario
10
+
11
+ Use when the user describes:
12
+ - an app that signs data using Tide threshold cryptography
13
+ - SSH access control with policy-based signing
14
+ - keyless SSH or keyless signing
15
+ - document signing with multi-admin approval
16
+ - transaction signing governed by smart contracts
17
+ - any app where cryptographic signatures are produced by ORKs after policy validation
18
+
19
+ Do NOT use when:
20
+ - the user needs only authentication (no signing)
21
+ - the user needs encryption/decryption (use `organisation-password-manager` or self-encryption patterns)
22
+ - the user describes a password manager or credential vault
23
+
24
+ ## Core Tide capabilities used
25
+
26
+ 1. **TideCloak OIDC authentication** — zero-knowledge login via threshold PRISM
27
+ 2. **DPoP token binding** — access tokens bound to device/session
28
+ 3. **Doken** — delegation token authorizing ORK-mediated operations
29
+ 4. **Forseti contracts** — C# smart contracts executed in ORK sandboxes; validate data, approvers, and executor before signing
30
+ 5. **Policy:1 auth flow** — policy-based authorization; ORKs check contract before producing signature
31
+ 6. **IGA (Identity Governance)** — role and policy changes require multi-admin approval via change-sets
32
+ 7. **BasicCustomRequest / DynamicCustomRequest** — request patterns for submitting signing operations to ORKs
33
+ 8. **PolicySignRequest** — creates signing policies with contract code, parameters, and model IDs
34
+ 9. **Client roles** — prefixed pattern (e.g., `ssh:<username>`) for per-resource access control
35
+
36
+ ## What must exist before first user access
37
+
38
+ 1. TideCloak running with a realm for the app
39
+ 2. Realm licensed (`setUpTideRealm`) and IGA enabled (`toggle-iga`)
40
+ 3. Admin user created, Tide account linked, `tide-realm-admin` role assigned
41
+ 4. Initial client and user change-sets approved and committed
42
+ 5. `sign-idp-settings` called after IDP config changes
43
+ 6. Adapter JSON exported to app (`tidecloak.json`) with `jwk`, `vendorId`, `homeOrkUrl`, `client-origin-auth-*`
44
+ 7. At least one signing role created (e.g., `ssh:<username>`) via admin UI
45
+ 8. Signing policy created, approved, and committed for each role (Forseti contract + `signed_policy_data`)
46
+ 9. App server running with JWT + DPoP verification on protected endpoints
47
+
48
+ ## Admin/bootstrap-only steps
49
+
50
+ - Start TideCloak container
51
+ - Import realm template
52
+ - Call `setUpTideRealm` and `toggle-iga`
53
+ - Create admin user and generate account-linking invite
54
+ - Approve pending change-sets (client, user)
55
+ - Upload branding / configure IDP settings + `sign-idp-settings`
56
+ - Set `CustomAdminUIDomain` if a separate app hosts the approval UI
57
+ - Export adapter JSON
58
+ - Create signing roles via admin UI
59
+ - Create and approve signing policies via admin UI (or policy template system)
60
+
61
+ ## Runtime user flow
62
+
63
+ 1. User visits app
64
+ 2. App redirects to TideCloak for OIDC login
65
+ 3. TideCloak authenticates via threshold PRISM (zero-knowledge)
66
+ 4. TideCloak returns access token + refresh token + doken + id token
67
+ 5. App server validates JWT (signature + claims + DPoP)
68
+ 6. When a signing operation is needed (e.g., SSH authentication):
69
+ - Client fetches the committed policy (`signed_policy_data`) for the target role
70
+ - Client creates a `BasicCustomRequest` or `DynamicCustomRequest` with the data to sign
71
+ - Client attaches doken as authorizer and policy bytes
72
+ - Client calls `createTideRequest` then `executeSignRequest`
73
+ - ORKs execute the Forseti contract: validate data, check approver/executor roles, enforce thresholds
74
+ - If policy allows, ORKs collaboratively produce the Ed25519 signature
75
+ 7. Signature exists only in client memory; signing key never materializes anywhere
76
+
77
+ ## Default playbook sequence
78
+
79
+ 1. `start-tidecloak-dev`
80
+ 2. `bootstrap-realm-from-template`
81
+ 3. `initialize-admin-and-link-account`
82
+ 4. `add-auth-nextjs-fresh` (or framework-appropriate equivalent)
83
+ 5. `protect-routes-nextjs`
84
+ 6. `protect-api-nextjs`
85
+ 7. `verify-jwt-server-side`
86
+ 8. `add-rbac-nextjs`
87
+
88
+ ## Key diagnostics
89
+
90
+ | Symptom | Likely cause |
91
+ |---------|-------------|
92
+ | Login hangs or blank screen | CSP missing `frame-src '*'`, or redirect handler missing |
93
+ | Signing fails with "No doken available" | User not authenticated, or doken expired, or `IAMService._tc` not initialized |
94
+ | Forseti contract rejects with `PolicyDecision.Deny` | Data validation failed (check contract logic), or executor lacks required role |
95
+ | `BadPolicy.ForbiddenCall` | Contract uses a blocked namespace (e.g., `System.IO`) |
96
+ | `OutOfGasException` | Contract exceeds 50,000 gas limit; simplify logic |
97
+ | Policy fetch returns null | PolicyApproval not committed, or role name mismatch |
98
+ | Roles missing from JWT/doken | IGA change-set not committed, or token not refreshed (up to 120s delay) |
99
+ | Adapter JSON missing `jwk` | IGA not enabled on realm before export |
100
+ | `client-origin-auth-*` mismatch | `sign-idp-settings` not called after origin change |
101
+ | Signature length unexpected | Check algorithm; Ed25519 signatures are 64 bytes |
102
+
103
+ ## Intentionally configurable
104
+
105
+ - **Role naming pattern**: Apps define their own prefix (e.g., `ssh:<user>`, `sign:<resource>`, `tx:<type>`)
106
+ - **Forseti contract logic**: Apps write custom `ValidateData`, `ValidateApprovers`, `ValidateExecutor` methods
107
+ - **Request pattern**: Choose `BasicCustomRequest` (static data) or `DynamicCustomRequest` (data can change between auth and signing)
108
+ - **Approval type**: Implicit (doken-only, no popup) or explicit (requires operator approval popup)
109
+ - **Execution type**: Public or private
110
+ - **Policy parameters**: `[PolicyParam]` attributes in the contract are filled from the policy `params` map
111
+ - **Model ID**: Custom `BasicCustom<Name>:BasicCustom<Version>` or `DynamicCustom<Name>:DynamicCustom<Version>` patterns
112
+ - **Approval thresholds**: IGA admin quorum and contract thresholds are deployment-configurable
113
+ - **Contract entry type**: Must be `Contract` implementing `IAccessPolicy`
@@ -0,0 +1,99 @@
1
+ # Role: Learnings / Pack Curator
2
+
3
+ ---
4
+
5
+ ## Purpose
6
+
7
+ Troubleshoot broken Tide integrations. Own login failures, missing roles/claims, auth errors, and finding extraction. This skill does NOT build new features — it fixes broken ones.
8
+
9
+ ---
10
+
11
+ ## Boundary
12
+
13
+ | This subagent owns | Hand off to |
14
+ |-------------------|-------------|
15
+ | Login broken, hangs, blank screen | — |
16
+ | Roles missing from JWT/doken | — |
17
+ | CSP violations blocking SWE iframe | — |
18
+ | DPoP verification failures | — |
19
+ | Policy commit failures ("Policy supplied has not been signed") | — |
20
+ | E2EE failures ("User has not been given any access") | — |
21
+ | Redirect mismatch errors | — |
22
+ | Finding extraction and learnings | — |
23
+ | Regression test proposals | — |
24
+ | Building new features | `tide-integration`, `tide-route-and-api-protection`, `tide-rbac-and-e2ee` |
25
+ | Bootstrap/realm issues | `tide-setup` |
26
+
27
+ ---
28
+
29
+ ## When to Trigger
30
+
31
+ - User reports login issues (hangs, blank screen, redirect loop)
32
+ - User reports 401/403 errors on protected APIs
33
+ - User reports missing roles or claims in JWT
34
+ - User reports E2EE failures
35
+ - User reports policy signing failures
36
+ - Orchestrator detected a broken state during inspection
37
+ - After a build session, to extract reusable learnings
38
+
39
+ ---
40
+
41
+ ## When NOT to Trigger
42
+
43
+ - App has no Tide integration at all → `tide-setup` then `tide-integration`
44
+ - User wants to add new features → route to appropriate subagent
45
+ - User wants to set up TideCloak → `tide-setup`
46
+
47
+ ---
48
+
49
+ ## Execution
50
+
51
+ ### Symptom-based routing
52
+
53
+ | Symptom | Likely cause | Playbook |
54
+ |---------|-------------|----------|
55
+ | Login hangs or blank screen | CSP missing `frame-src '*'`, redirect handler missing, DPoP auth page missing | `diagnose-broken-login` |
56
+ | Login redirect loop | `@tidecloak/react` ESM alias missing (AP-42), provider not wired | `diagnose-broken-login` |
57
+ | DPoP login fails | `tide_dpop_auth.html` missing or dynamic route not configured (I-12, L-07) | `diagnose-broken-login` |
58
+ | 401 on all API calls | JWT verification not implemented, or DPoP proof missing | `diagnose-missing-roles-or-claims` |
59
+ | 403 on API calls | Role not assigned, IGA change-set not committed, or 120s refresh delay | `diagnose-missing-roles-or-claims` |
60
+ | Roles missing from JWT | IGA change-set not committed, token not refreshed (up to 120s) | `diagnose-missing-roles-or-claims` |
61
+ | E2EE fails "User has not been given any access" | Self-encryption role missing, tag mismatch, IGA not approved | See T-13 in `tide-rbac-and-e2ee` |
62
+ | Policy commit fails "Policy supplied has not been signed" | Admin policy not fetched, not base64-decoded, or wrong attachment order | See T-14 in `tide-rbac-and-e2ee` |
63
+ | Encrypted data can't be shared | Using self-encryption instead of policy-governed (AP-24) | Route to `tide-rbac-and-e2ee` sharing gate |
64
+
65
+ ### Finding extraction
66
+
67
+ After resolving an issue, determine whether it is:
68
+ - **App-specific** (local machine state, one-off mistake) → do not promote to pack
69
+ - **Reusable** (pack gap, missing guidance, wrong instruction) → create a finding note in `notes/test-findings/`
70
+
71
+ For reusable findings, include:
72
+ - What the pack implied
73
+ - What was actually needed
74
+ - Root cause
75
+ - Lowest correct pack layer to patch
76
+ - Regression test
77
+
78
+ ---
79
+
80
+ ## Handoff Trace
81
+
82
+ ```
83
+ [TRACE]
84
+ Scenario: <scenario or "diagnostics">
85
+ Role: Learnings / Pack Curator
86
+ Reason: <what broke | what needs extraction>
87
+ Preconditions: Build complete or issue reported
88
+ Next: <specialist to fix | STOP if learning-only>
89
+ [/TRACE]
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Do Not Do This
95
+
96
+ - Do not treat UI gating failures as auth failures. `hasRealmRole()` / `hasClientRole()` are UX only.
97
+ - Do not rename self-encryption roles to fix sharing failures (AP-26).
98
+ - Do not treat policy commit failure as a role issue (T-14).
99
+ - Do not add `createRemoteJWKSet` as a fallback when `jwk` is missing — fix the adapter export instead (I-04).
@@ -0,0 +1,136 @@
1
+ # Role: Application Engineer
2
+
3
+ ---
4
+
5
+ ## Purpose
6
+
7
+ Wire the Tide SDK into the application. Own SDK installation, provider setup, config loading, redirect handler, CSP, silent SSO, DPoP auth page, and webpack workarounds. This is app-level work, not infrastructure.
8
+
9
+ ---
10
+
11
+ ## Boundary
12
+
13
+ | This subagent owns | Hand off to |
14
+ |-------------------|-------------|
15
+ | SDK install (`@tidecloak/nextjs` or `@tidecloak/react`) | — |
16
+ | TideCloakProvider wiring with `useDPoP` in config object | — |
17
+ | `tidecloak.json` placement and import | `tide-setup` if file doesn't exist and TideCloak not bootstrapped |
18
+ | `silent-check-sso.html` in `public/` | — |
19
+ | Post-auth redirect handler (`auth/redirect/page.tsx`) | — |
20
+ | `tide_dpop_auth.html` + `next.config.ts` rewrites + DPoP headers (I-12) | — |
21
+ | CSP (`frame-src '*'`) in `next.config` headers | — |
22
+ | Webpack workarounds (`strictExportPresence`, `@tidecloak/react` ESM alias) | — |
23
+ | Retrofit into existing apps | — |
24
+ | Server-side delegation setup (`@tidecloak/server`, `createTideFetch`) | — |
25
+ | Route/API protection | `tide-route-and-api-protection` |
26
+ | Roles, RBAC, encryption | `tide-rbac-and-e2ee` |
27
+ | TideCloak bootstrap, realm, licensing | `tide-setup` |
28
+ | Login broken, diagnostics | `tide-diagnostics` |
29
+
30
+ ---
31
+
32
+ ## When to Trigger
33
+
34
+ - `tide-setup` detected that SDK or provider is missing (Path A/B)
35
+ - `tide-setup` detected hardening gaps (Path D)
36
+ - User asks to "add Tide to my app" or "add login"
37
+ - Orchestrator routed here after bootstrap is confirmed
38
+
39
+ ### Scenario-disambiguation gate (I-17)
40
+
41
+ | Branch | How to resolve |
42
+ |--------|---------------|
43
+ | Fresh app vs existing app | Check for existing auth (NextAuth, Clerk, custom JWT) in the repo |
44
+ | Provider missing vs not wired | Check `package.json` for SDK, layout for `TideCloakProvider` |
45
+ | Config missing vs present | Check `data/tidecloak.json` or `public/tidecloak.json` |
46
+
47
+ ---
48
+
49
+ ## When NOT to Trigger
50
+
51
+ - TideCloak is not running and not bootstrapped → `tide-setup` first
52
+ - App already has working Tide auth (provider wired, adapter loaded, login functional) → route to `tide-route-and-api-protection` or `tide-rbac-and-e2ee`
53
+ - Something is broken → `tide-diagnostics`
54
+
55
+ ---
56
+
57
+ ## Preconditions
58
+
59
+ - TideCloak is bootstrapped and `tidecloak.json` exists with `jwk`, `vendorId`, `homeOrkUrl`
60
+ - A Next.js (or React/Vite) project exists
61
+
62
+ ---
63
+
64
+ ## Execution
65
+
66
+ ### Fresh app (no auth)
67
+
68
+ Follow playbook `add-auth-nextjs-fresh`:
69
+ 1. Install `@tidecloak/nextjs` (or `@tidecloak/react` for non-Next.js)
70
+ 2. Configure provider with `useDPoP` inside config object (not as JSX prop)
71
+ 3. Place `tidecloak.json` at correct path (`data/` for Next.js, `public/` for React/Vite)
72
+ 4. Create `public/silent-check-sso.html`
73
+ 5. Create post-auth redirect handler at `auth/redirect/page.tsx`
74
+ 6. Copy `tide_dpop_auth.html` to `public/` and add `rewrites()` + DPoP-specific `headers()` in `next.config.ts` (I-12). Do NOT use a route handler.
75
+ 7. Configure CSP: `frame-src '*'` in `next.config` headers (global); `script-src 'unsafe-inline'` on `/tide_dpop/:path*` only
76
+ 8. Add webpack workarounds to `next.config.ts`: `strictExportPresence = false` + `@tidecloak/react` ESM alias
77
+
78
+ ### Existing app (has other auth)
79
+
80
+ Follow playbook `add-auth-nextjs-existing`:
81
+ 1. Same steps as fresh but preserve existing app behavior
82
+ 2. Replace existing auth provider with `TideCloakProvider`
83
+ 3. Remove old auth (NextAuth, Clerk, etc.) after Tide is working
84
+
85
+ ### Server-side delegation
86
+
87
+ Follow playbook `setup-server-delegation`:
88
+ 1. Install `@tidecloak/server`
89
+ 2. Create `TideDelegation` singleton with TideCloak config
90
+ 3. Wire `/api/delegation` POST endpoint with `handleDelegation()`
91
+ 4. Add `requireDelegation()` middleware to admin routes
92
+ 5. Wrap browser fetch with `createTideFetch` from `@tidecloak/js`
93
+ 6. Optionally scope delegation roles via `requireDelegation({ roles: { ... } })`
94
+
95
+ ### Hardening gaps (from tide-setup Path D)
96
+
97
+ Fix each missing item per the table in `tide-setup`.
98
+
99
+ ---
100
+
101
+ ## Verification Checklist
102
+
103
+ - [ ] `@tidecloak/nextjs` (or equivalent) in `package.json`
104
+ - [ ] `TideCloakProvider` wraps the app with `useDPoP` in config object
105
+ - [ ] `tidecloak.json` exists with `jwk`, `vendorId`, `homeOrkUrl`
106
+ - [ ] `public/silent-check-sso.html` exists
107
+ - [ ] Post-auth redirect handler exists at configured `redirectUri`
108
+ - [ ] `public/tide_dpop_auth.html` exists + `next.config.ts` has `rewrites()` for `/tide_dpop/:path*` and DPoP-specific `headers()`
109
+ - [ ] CSP includes `frame-src '*'`
110
+ - [ ] Webpack config has `strictExportPresence = false` + `@tidecloak/react` ESM alias
111
+ - [ ] Login flow completes: redirect to Tide IdP -> auth -> callback -> app
112
+ - [ ] If server-side admin calls needed: `@tidecloak/server` installed, delegation endpoints wired
113
+
114
+ ---
115
+
116
+ ## Handoff Trace
117
+
118
+ ```
119
+ [TRACE]
120
+ Scenario: <scenario>
121
+ Role: Application Engineer
122
+ Reason: <SDK not installed | provider not wired | config missing | hardening gaps>
123
+ Preconditions: TideCloak bootstrapped, tidecloak.json exists
124
+ Next: Security Engineer | STOP if integration incomplete
125
+ [/TRACE]
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Do Not Do This
131
+
132
+ - Do not create ad hoc auth wiring. Follow the playbook.
133
+ - Do not use `NEXT_PUBLIC_TIDECLOAK_*` env vars. Use `tidecloak.json` directly. (AP-38)
134
+ - Do not pass `useDPoP` as a JSX prop. It goes inside the config object. (AP-42, session-002)
135
+ - Do not modify `tide_dpop_auth.html`. It is integrity-checked. (I-12, L-07)
136
+ - Do not apply `script-src 'unsafe-inline'` globally. Only on the DPoP auth route. (L-07)