@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.
- package/GAP_REGISTER.md +117 -0
- package/README.md +38 -0
- package/adapters/AGENTS.md +241 -0
- package/adapters/CLAUDE.md +146 -0
- package/adapters/replit.md +224 -0
- package/canon/anti-patterns.md +2133 -0
- package/canon/concepts.md +816 -0
- package/canon/custom-contracts.md +533 -0
- package/canon/delegation.md +195 -0
- package/canon/feature-mapping.md +637 -0
- package/canon/framework-matrix.md +1125 -0
- package/canon/invariants.md +851 -0
- package/canon/redirect-handler.md +254 -0
- package/canon/tidecloak-bootstrap.md +287 -0
- package/canon/tidecloak-endpoints.md +294 -0
- package/canon/troubleshooting.md +1494 -0
- package/canon/version-policy.md +89 -0
- package/mcp-server/dist/index.d.ts +2 -0
- package/mcp-server/dist/index.js +605 -0
- package/package.json +45 -0
- package/playbooks/add-auth-nextjs-existing.md +799 -0
- package/playbooks/add-auth-nextjs-fresh.md +654 -0
- package/playbooks/add-rbac-nextjs.md +190 -0
- package/playbooks/bootstrap-realm-from-template.md +170 -0
- package/playbooks/configure-e2ee-roles-and-policies.md +196 -0
- package/playbooks/deploy-tidecloak-docker.md +792 -0
- package/playbooks/diagnose-broken-login.md +234 -0
- package/playbooks/diagnose-missing-roles-or-claims.md +253 -0
- package/playbooks/initialize-admin-and-link-account.md +235 -0
- package/playbooks/migrate-from-existing-auth.md +198 -0
- package/playbooks/protect-api-nextjs.md +451 -0
- package/playbooks/protect-routes-nextjs.md +544 -0
- package/playbooks/setup-forseti-e2ee.md +756 -0
- package/playbooks/setup-iga-admin-panel.md +344 -0
- package/playbooks/setup-server-delegation.md +142 -0
- package/playbooks/start-tidecloak-dev.md +130 -0
- package/playbooks/verify-jwt-server-side.md +439 -0
- package/prompts/add-admin-approval-flow.md +50 -0
- package/prompts/build-private-customer-portal.md +85 -0
- package/prompts/migrate-generic-auth-to-tide.md +67 -0
- package/prompts/secure-existing-app.md +80 -0
- package/reference-apps/INDEX.md +87 -0
- package/reference-apps/encrypted-communication/anti-patterns.md +123 -0
- package/reference-apps/encrypted-communication/bootstrap-sequence.md +152 -0
- package/reference-apps/encrypted-communication/manifest.yaml +100 -0
- package/reference-apps/encrypted-communication/role-policy-matrix.md +80 -0
- package/reference-apps/encrypted-communication/scenario.md +134 -0
- package/reference-apps/git-pr-signing-service/anti-patterns.md +61 -0
- package/reference-apps/git-pr-signing-service/bootstrap-sequence.md +157 -0
- package/reference-apps/git-pr-signing-service/manifest.yaml +80 -0
- package/reference-apps/git-pr-signing-service/role-policy-matrix.md +99 -0
- package/reference-apps/git-pr-signing-service/scenario.md +169 -0
- package/reference-apps/iga-admin-governance/anti-patterns.md +133 -0
- package/reference-apps/iga-admin-governance/bootstrap-sequence.md +153 -0
- package/reference-apps/iga-admin-governance/manifest.yaml +87 -0
- package/reference-apps/iga-admin-governance/role-policy-matrix.md +67 -0
- package/reference-apps/iga-admin-governance/scenario.md +126 -0
- package/reference-apps/organisation-password-manager/anti-patterns.md +71 -0
- package/reference-apps/organisation-password-manager/bootstrap-sequence.md +127 -0
- package/reference-apps/organisation-password-manager/manifest.yaml +86 -0
- package/reference-apps/organisation-password-manager/role-policy-matrix.md +59 -0
- package/reference-apps/organisation-password-manager/scenario.md +107 -0
- package/reference-apps/policy-governed-signing/anti-patterns.md +67 -0
- package/reference-apps/policy-governed-signing/bootstrap-sequence.md +128 -0
- package/reference-apps/policy-governed-signing/manifest.yaml +78 -0
- package/reference-apps/policy-governed-signing/role-policy-matrix.md +62 -0
- package/reference-apps/policy-governed-signing/scenario.md +113 -0
- package/skills/tide-diagnostics/SKILL.md +99 -0
- package/skills/tide-integration/SKILL.md +136 -0
- package/skills/tide-learning-capture/SKILL.md +174 -0
- package/skills/tide-rbac-and-e2ee/SKILL.md +214 -0
- package/skills/tide-reviewer/SKILL.md +133 -0
- package/skills/tide-route-and-api-protection/SKILL.md +201 -0
- package/skills/tide-scenario-resolver/SKILL.md +81 -0
- package/skills/tide-setup/SKILL.md +218 -0
- 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)
|