@tideorg/mcp 1.4.1 → 1.9.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/CHANGELOG.md +81 -0
- package/GAP_REGISTER.md +19 -9
- package/PRIVACY.md +41 -0
- package/README.md +204 -120
- package/adapters/AGENTS.md +3 -2
- package/adapters/CLAUDE.md +1 -1
- package/adapters/replit.md +0 -0
- package/canon/anti-patterns.md +55 -62
- package/canon/concepts.md +46 -34
- package/canon/custom-contracts.md +12 -8
- package/canon/feature-mapping.md +27 -75
- package/canon/framework-matrix.md +69 -22
- package/canon/hosting-options.md +111 -0
- package/canon/iga-change-requests-api.md +211 -0
- package/canon/invariants.md +33 -35
- package/canon/redirect-handler.md +0 -0
- package/canon/security-gap-mapping.md +506 -0
- package/canon/security-runtime-probes.md +177 -0
- package/canon/tidecloak-bootstrap.md +84 -15
- package/canon/tidecloak-endpoints.md +60 -98
- package/canon/troubleshooting.md +201 -53
- package/canon/version-policy.md +8 -12
- package/mcp-server/dist/http.d.ts +2 -0
- package/mcp-server/dist/http.js +46 -0
- package/mcp-server/dist/index.d.ts +0 -0
- package/mcp-server/dist/index.js +2 -601
- package/mcp-server/dist/server.d.ts +2 -0
- package/mcp-server/dist/server.js +617 -0
- package/package.json +48 -45
- package/playbooks/add-auth-nextjs-existing.md +33 -17
- package/playbooks/add-auth-nextjs-fresh.md +1 -1
- package/playbooks/add-rbac-nextjs.md +7 -2
- package/playbooks/bootstrap-realm-from-template.md +33 -18
- package/playbooks/configure-e2ee-roles-and-policies.md +0 -0
- package/playbooks/deploy-tidecloak-docker.md +31 -28
- package/playbooks/diagnose-broken-login.md +0 -0
- package/playbooks/diagnose-missing-roles-or-claims.md +2 -2
- package/playbooks/initialize-admin-and-link-account.md +22 -19
- package/playbooks/migrate-from-existing-auth.md +0 -0
- package/playbooks/protect-api-nextjs.md +40 -1
- package/playbooks/protect-aspnet-core-asgard.md +313 -0
- package/playbooks/protect-routes-nextjs.md +24 -10
- package/playbooks/provision-tidecloak-skycloak.md +213 -0
- package/playbooks/setup-forseti-e2ee.md +32 -50
- package/playbooks/setup-iga-admin-panel.md +113 -171
- package/playbooks/start-tidecloak-dev.md +0 -0
- package/playbooks/verify-jwt-server-side.md +20 -1
- package/prompts/add-admin-approval-flow.md +0 -0
- package/prompts/build-private-customer-portal.md +1 -1
- package/prompts/migrate-generic-auth-to-tide.md +0 -0
- package/prompts/secure-existing-app.md +0 -0
- package/prompts/security-gap-analysis.md +55 -0
- package/reference-apps/INDEX.md +0 -0
- package/reference-apps/encrypted-communication/anti-patterns.md +3 -3
- package/reference-apps/encrypted-communication/bootstrap-sequence.md +2 -2
- package/reference-apps/encrypted-communication/manifest.yaml +0 -0
- package/reference-apps/encrypted-communication/role-policy-matrix.md +0 -0
- package/reference-apps/encrypted-communication/scenario.md +2 -2
- package/reference-apps/git-pr-signing-service/anti-patterns.md +0 -0
- package/reference-apps/git-pr-signing-service/bootstrap-sequence.md +8 -8
- package/reference-apps/git-pr-signing-service/manifest.yaml +0 -0
- package/reference-apps/git-pr-signing-service/role-policy-matrix.md +0 -0
- package/reference-apps/git-pr-signing-service/scenario.md +0 -0
- package/reference-apps/iga-admin-governance/anti-patterns.md +18 -16
- package/reference-apps/iga-admin-governance/bootstrap-sequence.md +10 -5
- package/reference-apps/iga-admin-governance/manifest.yaml +0 -0
- package/reference-apps/iga-admin-governance/role-policy-matrix.md +12 -13
- package/reference-apps/iga-admin-governance/scenario.md +15 -13
- package/reference-apps/organisation-password-manager/anti-patterns.md +0 -0
- package/reference-apps/organisation-password-manager/bootstrap-sequence.md +5 -6
- package/reference-apps/organisation-password-manager/manifest.yaml +0 -0
- package/reference-apps/organisation-password-manager/role-policy-matrix.md +0 -0
- package/reference-apps/organisation-password-manager/scenario.md +0 -0
- package/reference-apps/policy-governed-signing/anti-patterns.md +0 -0
- package/reference-apps/policy-governed-signing/bootstrap-sequence.md +9 -9
- package/reference-apps/policy-governed-signing/manifest.yaml +0 -0
- package/reference-apps/policy-governed-signing/role-policy-matrix.md +0 -0
- package/reference-apps/policy-governed-signing/scenario.md +0 -0
- package/skills/tide-diagnostics/SKILL.md +1 -1
- package/skills/tide-integration/SKILL.md +9 -18
- package/skills/tide-learning-capture/SKILL.md +0 -0
- package/skills/tide-mcp-qa/SKILL.md +139 -0
- package/skills/tide-rbac-and-e2ee/SKILL.md +5 -5
- package/skills/tide-reviewer/SKILL.md +1 -1
- package/skills/tide-route-and-api-protection/SKILL.md +0 -0
- package/skills/tide-scenario-resolver/SKILL.md +0 -0
- package/skills/tide-security-analyst/SKILL.md +182 -0
- package/skills/tide-setup/SKILL.md +1 -1
- package/skills/tide-solutions-architect/SKILL.md +0 -0
- package/canon/delegation.md +0 -195
- package/playbooks/setup-server-delegation.md +0 -142
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Prompt: Security Gap Analysis of an Existing System
|
|
2
|
+
|
|
3
|
+
Copy-paste this to an AI coding agent to audit an existing application for identity, key-management, authorization, and data-exposure gaps — and map each gap to the Tide capability that removes it. Works on systems with no Tide involvement at all.
|
|
4
|
+
|
|
5
|
+
This is an **advisory, read-only** analysis. It does not modify the target.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The Prompt
|
|
10
|
+
|
|
11
|
+
> Perform a security gap analysis of this system. You are acting as the **Security Analyst** role from the Tide agent pack. Do not modify any code. Produce a report; do not begin remediation until I approve it.
|
|
12
|
+
>
|
|
13
|
+
> **First, confirm scope**: state exactly what you will inspect (repo, running instance, config) and that this is my own system or an authorized engagement. Read-only.
|
|
14
|
+
>
|
|
15
|
+
> **Load the doctrine**: read `canon/security-gap-mapping.md` (the SG-01 … SG-18 gap table) and `skills/tide-security-analyst/SKILL.md`. If you have the Tide MCP server, call `tide_security_analysis` to load them at once.
|
|
16
|
+
>
|
|
17
|
+
> **Two tiers**: run the **static** sweep (code/config/schema) always. Only run the **runtime confirmation** tier — sending live probes to confirm findings — if I confirm I own or am authorized to test the target, and then strictly per `canon/security-runtime-probes.md` (non-destructive, no exploitation, my own test account only). If I have not authorized live testing, stay static-only and keep findings tagged INFERRED.
|
|
18
|
+
>
|
|
19
|
+
> **Inventory the trust architecture first** (before pattern-matching), answering from the code/config:
|
|
20
|
+
> 1. Identity — how are users authenticated, where do credentials live?
|
|
21
|
+
> 2. Authority — how are tokens/sessions signed, who holds the signing key?
|
|
22
|
+
> 3. Authorization — where is the access decision made: client, server, or both?
|
|
23
|
+
> 4. Data — what sensitive data exists, and who can read it in the clear?
|
|
24
|
+
>
|
|
25
|
+
> **Run the full gap sweep**: work through SG-01 … SG-12 exhaustively. For each, run the detection commands from `canon/security-gap-mapping.md` against the target and record hits. Do NOT sample APIs (SG-05) — enumerate every route and diff against the routes that actually verify. Also collect anything matching the "Out of scope" table.
|
|
26
|
+
>
|
|
27
|
+
> **Every finding must have**:
|
|
28
|
+
> - A named **trust concentration** — the single party or artifact that, once compromised, defeats the control. "Uses passwords" is not a finding; "password verification collapses to one database + one server process" is.
|
|
29
|
+
> - **Evidence** — a file:line, config value, schema column, or HTTP observation — tagged VERIFIED (observed), INFERRED (implied by code), or ASSUMED (my statement, unconfirmed).
|
|
30
|
+
> - A **severity** (CRITICAL / HIGH / MEDIUM / INFO) based on blast radius under a single compromise.
|
|
31
|
+
> - The **Tide replacement**, cited from `canon/feature-mapping.md` or `canon/invariants.md`, with its sourcing tag.
|
|
32
|
+
> - The **remediation playbook sequence** (verify each playbook exists via `tide_list playbooks`).
|
|
33
|
+
> - The **limits** — the honesty note: what the Tide replacement does NOT cover.
|
|
34
|
+
>
|
|
35
|
+
> **Be honest**: include a non-empty "Not Addressed by Tide" section for anything you find that Tide doesn't fix (injection, XSS, CSRF, vulnerable dependencies, rate limiting, infra hardening). Never present Tide as fixing these. An honest analysis is more credible than an inflated one.
|
|
36
|
+
>
|
|
37
|
+
> **Report in the format** defined in `skills/tide-security-analyst/SKILL.md` (Report Format section): trust-architecture summary, findings most-severe-first, gap interactions, out-of-scope section, then a recommended remediation sequence with the execution role to engage first (per I-18).
|
|
38
|
+
>
|
|
39
|
+
> **Do not**: modify code, run TideCloak bootstrap, install the SDK, or start fixing anything. Report only. When I approve findings, hand off to the execution roles (Setup → Application → Security → IAM/Policy → Reviewer).
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Acceptance Criteria
|
|
44
|
+
|
|
45
|
+
- [ ] Scope and authorization confirmed before inspection
|
|
46
|
+
- [ ] Trust architecture (identity / authority / authorization / data) documented
|
|
47
|
+
- [ ] All of SG-01 … SG-18 checked, not sampled (or non-applicability stated per SG)
|
|
48
|
+
- [ ] Every finding names a trust concentration and carries evidence with a confidence tag
|
|
49
|
+
- [ ] Runtime tier run only if authorized; probed findings carry a Runtime confirmation line; unprobed findings stay INFERRED
|
|
50
|
+
- [ ] Every Tide-replacement claim cites `canon/feature-mapping.md` or `canon/invariants.md`
|
|
51
|
+
- [ ] Every remediation names a playbook that exists in `playbooks/`
|
|
52
|
+
- [ ] Non-empty "Not Addressed by Tide" section (or explicit "none found in scope")
|
|
53
|
+
- [ ] No finding claims Tide fixes an out-of-scope gap class
|
|
54
|
+
- [ ] Remediation sequence provided with first execution role named
|
|
55
|
+
- [ ] No code was modified; the analysis is read-only
|
package/reference-apps/INDEX.md
CHANGED
|
File without changes
|
|
@@ -10,7 +10,7 @@ Scenario-specific mistakes for encrypted communication apps using the hybrid Tid
|
|
|
10
10
|
|
|
11
11
|
**Why it fails**: The private key is the root of trust for all E2E operations. If stored in plaintext, a database breach or XSS attack exposes all encrypted communications.
|
|
12
12
|
|
|
13
|
-
**Fix**: Always encrypt the private key with `doEncrypt(privateKeyBytes, tag)` before storing. Always decrypt with `doDecrypt()` on login. Never persist the decrypted private key outside of in-memory variables.
|
|
13
|
+
**Fix**: Always encrypt the private key with `doEncrypt([{ data: privateKeyBytes, tags: [tag] }])` before storing. Always decrypt with `doDecrypt()` on login. Never persist the decrypted private key outside of in-memory variables.
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -118,6 +118,6 @@ Scenario-specific mistakes for encrypted communication apps using the hybrid Tid
|
|
|
118
118
|
|
|
119
119
|
**Mistake**: Installing a 0.99.x pre-release version of the Tide SDK.
|
|
120
120
|
|
|
121
|
-
**Why it fails**: 0.99.x versions are unstable pre-releases. The stable version is 0.13.
|
|
121
|
+
**Why it fails**: 0.99.x versions are unstable pre-releases. The stable version is 0.13.33 (per pack version policy).
|
|
122
122
|
|
|
123
|
-
**Fix**: Pin `@tidecloak/react` to `0.13.
|
|
123
|
+
**Fix**: Pin `@tidecloak/react` to `0.13.33`. See `canon/version-policy.md`.
|
|
@@ -117,12 +117,12 @@
|
|
|
117
117
|
|
|
118
118
|
23. Implement first-login flow:
|
|
119
119
|
- Generate keypair client-side
|
|
120
|
-
- Encrypt private key with `doEncrypt(privateKeyBytes, tag)`
|
|
120
|
+
- Encrypt private key with `doEncrypt([{ data: privateKeyBytes, tags: [tag] }])`
|
|
121
121
|
- Store encrypted private key + public key via protected API
|
|
122
122
|
|
|
123
123
|
24. Implement returning-login flow:
|
|
124
124
|
- Fetch encrypted key material via protected API
|
|
125
|
-
- Decrypt private key with `doDecrypt(encryptedPrivateKey, tag)`
|
|
125
|
+
- Decrypt private key with `doDecrypt([{ encrypted: encryptedPrivateKey, tags: [tag] }])`
|
|
126
126
|
- Private key available in memory for runtime E2E operations
|
|
127
127
|
|
|
128
128
|
25. Implement runtime E2E operations using the external crypto library (not Tide).
|
|
File without changes
|
|
File without changes
|
|
@@ -77,14 +77,14 @@ On **first login** for a new user:
|
|
|
77
77
|
1. User authenticates via TideCloak SSO
|
|
78
78
|
2. App checks database for existing encrypted key material
|
|
79
79
|
3. No keys found → app generates a new asymmetric keypair client-side (e.g., `crypto_box_keypair()`)
|
|
80
|
-
4. App encrypts the private key using `doEncrypt(privateKeyBytes, tag)` (Tide self-encryption)
|
|
80
|
+
4. App encrypts the private key using `doEncrypt([{ data: privateKeyBytes, tags: [tag] }])` (Tide self-encryption)
|
|
81
81
|
5. App stores the encrypted private key and the public key in the database via a protected API endpoint
|
|
82
82
|
6. Private key is now available in memory for runtime E2E operations
|
|
83
83
|
|
|
84
84
|
On **returning login**:
|
|
85
85
|
1. User authenticates via TideCloak SSO
|
|
86
86
|
2. App fetches encrypted key material from database
|
|
87
|
-
3. App decrypts the private key using `doDecrypt(encryptedPrivateKey, tag)` (Tide self-encryption)
|
|
87
|
+
3. App decrypts the private key using `doDecrypt([{ encrypted: encryptedPrivateKey, tags: [tag] }])` (Tide self-encryption)
|
|
88
88
|
4. Private key is now available in memory for runtime E2E operations
|
|
89
89
|
|
|
90
90
|
**Runtime E2E operations** (not Tide — handled by external crypto library):
|
|
File without changes
|
|
@@ -27,11 +27,11 @@ All steps must complete before the service can sign merge commits. Order matters
|
|
|
27
27
|
- `POST /admin/realms/{realm}/tide-admin/toggle-iga` with form-urlencoded `isIGAEnabled=true`.
|
|
28
28
|
- Must happen after licensing.
|
|
29
29
|
|
|
30
|
-
## Phase 3: Approve initial change
|
|
30
|
+
## Phase 3: Approve initial change requests
|
|
31
31
|
|
|
32
|
-
6. **Approve
|
|
33
|
-
- List: `GET /admin/realms/{realm}/
|
|
34
|
-
-
|
|
32
|
+
6. **Approve initial change requests** (current `/iga/change-requests/...` surface — see `canon/iga-change-requests-api.md`)
|
|
33
|
+
- List: `GET /admin/realms/{realm}/iga/change-requests?status=PENDING` (objects keyed by `id`).
|
|
34
|
+
- Approve: `POST .../iga/change-requests/bulk-authorize` (`{"actionTypeIn":["CREATE","DELETE"],"limit":100}`), then `POST .../iga/change-requests/{id}/commit` for each `readyToCommit` CR. FirstAdmin bootstrap signs server-side.
|
|
35
35
|
|
|
36
36
|
## Phase 4: Admin user setup
|
|
37
37
|
|
|
@@ -50,11 +50,11 @@ All steps must complete before the service can sign merge commits. Order matters
|
|
|
50
50
|
10. **Wait for account linking**
|
|
51
51
|
- Poll `GET /admin/realms/{realm}/users/{userId}` until `attributes.tideUserKey` and `attributes.vuid` are present for each admin.
|
|
52
52
|
|
|
53
|
-
## Phase 5: Approve user change
|
|
53
|
+
## Phase 5: Approve user change requests
|
|
54
54
|
|
|
55
|
-
11. **Approve user change
|
|
56
|
-
- List: `GET /admin/realms/{realm}/
|
|
57
|
-
-
|
|
55
|
+
11. **Approve user change requests**
|
|
56
|
+
- List: `GET /admin/realms/{realm}/iga/change-requests?status=PENDING`.
|
|
57
|
+
- Authorize then commit (see Phase 3 / `canon/iga-change-requests-api.md`).
|
|
58
58
|
|
|
59
59
|
## Phase 6: IDP settings and adapter export
|
|
60
60
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -14,43 +14,45 @@ Scenario-specific mistakes for IGA admin governance panels. General Tide anti-pa
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
> Endpoints use the current `/iga/change-requests/...` surface (GAP-065). Full spec: `canon/iga-change-requests-api.md`.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
## AP-G02: Treating authorize as commit
|
|
20
20
|
|
|
21
|
-
**
|
|
21
|
+
**Mistake**: Calling only `POST /iga/change-requests/{id}/authorize` and assuming the change is applied.
|
|
22
22
|
|
|
23
|
-
**
|
|
23
|
+
**Why it fails**: `authorize` records an approval. The change does not take effect until `POST /iga/change-requests/{id}/commit` is called, and commit returns **412** until `readyToCommit` (threshold met, dependencies committed).
|
|
24
|
+
|
|
25
|
+
**Fix**: After `authorize` succeeds, poll for `readyToCommit === true`, then `commit`. During bootstrap, `bulk-authorize` then commit ready CRs in dependency passes.
|
|
24
26
|
|
|
25
27
|
---
|
|
26
28
|
|
|
27
|
-
## AP-G03:
|
|
29
|
+
## AP-G03: Re-signing the same CR with the same admin
|
|
28
30
|
|
|
29
|
-
**Mistake**:
|
|
31
|
+
**Mistake**: Retrying `authorize` on a CR the same admin already signed.
|
|
30
32
|
|
|
31
|
-
**Why it fails**:
|
|
33
|
+
**Why it fails**: Four-eyes enforcement returns **409 Conflict** — one admin cannot count twice toward the threshold.
|
|
32
34
|
|
|
33
|
-
**Fix**:
|
|
35
|
+
**Fix**: Have a *different* admin authorize. If you get 409, refresh the CR (`GET /iga/change-requests/{id}`) — it may already be signed or no longer PENDING.
|
|
34
36
|
|
|
35
37
|
---
|
|
36
38
|
|
|
37
|
-
## AP-G04:
|
|
39
|
+
## AP-G04: Stale pending list across mutations
|
|
38
40
|
|
|
39
|
-
**Mistake**: Fetching
|
|
41
|
+
**Mistake**: Fetching the pending list once and not refreshing after authorize/commit/deny.
|
|
40
42
|
|
|
41
|
-
**Why it fails**:
|
|
43
|
+
**Why it fails**: `status` and `readyToCommit` change after every action. Stale data drives wrong badge counts and lets the UI offer commit on a CR that is not ready (→ 412).
|
|
42
44
|
|
|
43
|
-
**Fix**:
|
|
45
|
+
**Fix**: Re-fetch `GET /iga/change-requests?status=PENDING` after every mutation and recompute counts/badges from it.
|
|
44
46
|
|
|
45
47
|
---
|
|
46
48
|
|
|
47
|
-
## AP-G05:
|
|
49
|
+
## AP-G05: Skipping the enclave step in Tide MultiAdmin mode
|
|
48
50
|
|
|
49
|
-
**Mistake**:
|
|
51
|
+
**Mistake**: Calling a bare `authorize` in Tide MultiAdmin mode and treating the response as done.
|
|
50
52
|
|
|
51
|
-
**Why it fails**: In MultiAdmin mode
|
|
53
|
+
**Why it fails**: In Tide MultiAdmin mode the approval is cryptographic — a bare `authorize` does not record it. The admin must complete the two-phase enclave exchange: `GET /iga/change-requests/{id}/approval-model` → sign the `requestModel` in the enclave → `POST /iga/change-requests/{id}/approval-model` with `{ requestModel }`.
|
|
52
54
|
|
|
53
|
-
**Fix**:
|
|
55
|
+
**Fix**: In MultiAdmin mode, drive the `approval-model` exchange and confirm `recorded: true` / an increased `authCount`. FirstAdmin/Tideless mode signs server-side on `authorize` — no enclave step.
|
|
54
56
|
|
|
55
57
|
---
|
|
56
58
|
|
|
@@ -50,12 +50,17 @@
|
|
|
50
50
|
-d "isIGAEnabled=true"
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
6. Approve/commit initial
|
|
53
|
+
6. Approve/commit initial change requests (current `/iga/change-requests/...` surface; see `canon/iga-change-requests-api.md`):
|
|
54
54
|
```bash
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
-H "Authorization: Bearer $TOKEN"
|
|
58
|
-
|
|
55
|
+
# Authorize all pending, then commit ready ones (FirstAdmin bootstrap signs server-side)
|
|
56
|
+
curl -s -X POST "http://localhost:8080/admin/realms/$REALM/iga/change-requests/bulk-authorize" \
|
|
57
|
+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
58
|
+
-d '{"actionTypeIn":["CREATE","DELETE"],"limit":100}'
|
|
59
|
+
for id in $(curl -s "http://localhost:8080/admin/realms/$REALM/iga/change-requests?status=PENDING" \
|
|
60
|
+
-H "Authorization: Bearer $TOKEN" | jq -r '.[] | select(.readyToCommit==true) | .id'); do
|
|
61
|
+
curl -s -X POST "http://localhost:8080/admin/realms/$REALM/iga/change-requests/$id/commit" \
|
|
62
|
+
-H "Authorization: Bearer $TOKEN"
|
|
63
|
+
done
|
|
59
64
|
```
|
|
60
65
|
|
|
61
66
|
---
|
|
File without changes
|
|
@@ -49,19 +49,18 @@ The governance panel may optionally include policy management. These are NOT req
|
|
|
49
49
|
|
|
50
50
|
---
|
|
51
51
|
|
|
52
|
-
## Change-
|
|
52
|
+
## Change-Request Endpoints (core governance)
|
|
53
|
+
|
|
54
|
+
Current `/iga/change-requests/...` surface (replaces legacy `/tide-admin/change-set/...`, GAP-065). **Full spec: `canon/iga-change-requests-api.md`.**
|
|
53
55
|
|
|
54
56
|
| Operation | Endpoint | Method | Content-Type | Notes |
|
|
55
57
|
|-----------|---------|--------|-------------|-------|
|
|
56
|
-
| List
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
| Commit | `/
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
| Add comment | `/tide-admin/change-set/{id}/comments` | POST | `application/json` | |
|
|
66
|
-
| Licensing requests | `/tideAdminResources/change-set/licensing/requests` | GET | — | Different path prefix from other types |
|
|
67
|
-
| Ragnarok requests | `/ragnarok/change-set/offboarding/requests` | GET | — | Different path prefix |
|
|
58
|
+
| List | `/iga/change-requests?status=PENDING` | GET | — | Objects keyed by `id`; `status` = PENDING/APPROVED/DENIED/CANCELLED. Derive counts from the list. |
|
|
59
|
+
| Get one | `/iga/change-requests/{id}` | GET | — | Full CR (`entityType`, `readyToCommit`, `threshold`, `dependsOn`) |
|
|
60
|
+
| Authorize (approve) | `/iga/change-requests/{id}/authorize` | POST | `application/json` | Body `{}` optional. 409 = four-eyes re-sign |
|
|
61
|
+
| Bulk authorize | `/iga/change-requests/bulk-authorize` | POST | `application/json` | `{ "actionTypeIn": ["CREATE","DELETE"], "limit": 100 }`; 429 if a bulk run is active |
|
|
62
|
+
| Commit | `/iga/change-requests/{id}/commit` | POST | — | 412 if under threshold / unmet dependency |
|
|
63
|
+
| Deny (reject) | `/iga/change-requests/{id}/deny` | POST | — | → 204 |
|
|
64
|
+
| Enclave sign (Tide MultiAdmin) | `/iga/change-requests/{id}/approval-model` | GET/POST | `application/json` | Two-phase: GET challenge → POST `{ requestModel }` |
|
|
65
|
+
| Comments | `/iga/change-requests/{id}/comments` | GET/POST | `application/json` | `{ "comment": "..." }` (≤2000) |
|
|
66
|
+
| Manual ADOPT | `/iga/adopt` | POST | `application/json` | `{ "entityType": "USER", "entityId": "..." }` |
|
|
@@ -72,17 +72,18 @@ These happen before any admin uses the governance panel:
|
|
|
72
72
|
|
|
73
73
|
Once bootstrap is complete, the governance panel operates as follows:
|
|
74
74
|
|
|
75
|
+
Endpoints use the current `/iga/change-requests/...` surface (replaces legacy `/tide-admin/change-set/...`, GAP-065; full spec `canon/iga-change-requests-api.md`).
|
|
76
|
+
|
|
75
77
|
1. Admin logs in via TideCloak SSO (DPoP-bound)
|
|
76
|
-
2. Panel
|
|
77
|
-
3. Panel
|
|
78
|
+
2. Panel lists pending requests (`GET /iga/change-requests?status=PENDING`) and derives counts
|
|
79
|
+
3. Panel groups pending CRs by `entityType` (users, roles, groups, clients, settings, policies)
|
|
78
80
|
4. Admin reviews a change request's details, activity, and comments
|
|
79
|
-
5. Admin approves: `POST /
|
|
80
|
-
- If MultiAdmin:
|
|
81
|
-
- If FirstAdmin: signed immediately
|
|
82
|
-
6. When
|
|
83
|
-
7. Admin can
|
|
84
|
-
8. Admin can
|
|
85
|
-
9. Admin can add/edit/delete comments on change requests
|
|
81
|
+
5. Admin approves: `POST /iga/change-requests/{id}/authorize` (body `{}`; 409 = four-eyes)
|
|
82
|
+
- If Tide MultiAdmin: complete the two-phase `GET`/`POST /iga/change-requests/{id}/approval-model` enclave exchange
|
|
83
|
+
- If FirstAdmin/Tideless: signed server-side immediately
|
|
84
|
+
6. When `readyToCommit`: `POST /iga/change-requests/{id}/commit` (412 if under threshold)
|
|
85
|
+
7. Admin can reject: `POST /iga/change-requests/{id}/deny`
|
|
86
|
+
8. Admin can add/edit/delete comments on change requests
|
|
86
87
|
|
|
87
88
|
---
|
|
88
89
|
|
|
@@ -104,10 +105,11 @@ Once bootstrap is complete, the governance panel operates as follows:
|
|
|
104
105
|
|
|
105
106
|
| Symptom | Likely cause | Fix |
|
|
106
107
|
|---------|-------------|-----|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
108
|
+
| Authorize returns 401 | Token expired or DPoP not attached | Re-login; ensure `secureFetch` with DPoP |
|
|
109
|
+
| Authorize returns 409 | Same admin re-signing (four-eyes) or CR not PENDING | Use a different admin; refresh the list |
|
|
110
|
+
| MultiAdmin: authorize does not record | Enclave step skipped | Complete `{id}/approval-model` two-phase exchange |
|
|
111
|
+
| Commit returns 412 | Under threshold / unmet dependency | Collect more approvals; commit `dependsOn` CR first |
|
|
112
|
+
| Change request stays PENDING after authorize | Missing commit step | Call `{id}/commit` once `readyToCommit` |
|
|
111
113
|
| add-review returns 415 | Wrong content-type | Use `multipart/form-data`, not JSON |
|
|
112
114
|
| Counts don't update after commit | Stale data | Refresh counts after every mutation |
|
|
113
115
|
| Policy change requests don't appear | Realm policy not in pending state | Create pending realm policy first via `/tide-admin/realm-policy/pending` |
|
|
File without changes
|
|
@@ -48,12 +48,11 @@ All steps must complete before users can safely use the app. Order matters.
|
|
|
48
48
|
|
|
49
49
|
## Phase 4: Change-set approval
|
|
50
50
|
|
|
51
|
-
10. **Approve pending change-
|
|
52
|
-
- IGA creates draft change
|
|
53
|
-
- List: `GET /admin/realms/{realm}/
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
- Commit: `POST /admin/realms/{realm}/tide-admin/change-set/commit`.
|
|
51
|
+
10. **Approve pending change requests** (current `/iga/change-requests/...` surface — see `canon/iga-change-requests-api.md`)
|
|
52
|
+
- IGA creates draft change requests for client and user mutations made during setup (each mutating write returns 202).
|
|
53
|
+
- List: `GET /admin/realms/{realm}/iga/change-requests?status=PENDING` (objects keyed by `id`).
|
|
54
|
+
- Approve: `POST /admin/realms/{realm}/iga/change-requests/bulk-authorize` (`{"actionTypeIn":["CREATE","DELETE"],"limit":100}`; FirstAdmin signs server-side).
|
|
55
|
+
- Commit: `POST /admin/realms/{realm}/iga/change-requests/{id}/commit` for each `readyToCommit` CR.
|
|
57
56
|
- Without this step, client and user changes are in draft state and not active.
|
|
58
57
|
|
|
59
58
|
## Phase 5: IDP settings and adapter export
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -28,12 +28,12 @@ All steps must complete before users can safely use signing features. Order matt
|
|
|
28
28
|
- `POST /admin/realms/{realm}/tide-admin/toggle-iga` with form-urlencoded `isIGAEnabled=true`.
|
|
29
29
|
- Must happen after licensing. Enables change-set governance for role/user mutations.
|
|
30
30
|
|
|
31
|
-
## Phase 3: Approve initial change
|
|
31
|
+
## Phase 3: Approve initial change requests
|
|
32
32
|
|
|
33
|
-
6. **Approve
|
|
34
|
-
- IGA creates draft change
|
|
35
|
-
- List: `GET /admin/realms/{realm}/
|
|
36
|
-
-
|
|
33
|
+
6. **Approve initial change requests** (current `/iga/change-requests/...` surface — see `canon/iga-change-requests-api.md`)
|
|
34
|
+
- IGA creates draft change requests for client/role mutations during realm import (each mutating write returns 202).
|
|
35
|
+
- List: `GET /admin/realms/{realm}/iga/change-requests?status=PENDING` (objects keyed by `id`).
|
|
36
|
+
- Approve: `POST /admin/realms/{realm}/iga/change-requests/bulk-authorize` (`{"actionTypeIn":["CREATE","DELETE"],"limit":100}`), then `POST /admin/realms/{realm}/iga/change-requests/{id}/commit` for each `readyToCommit` CR. FirstAdmin bootstrap signs server-side.
|
|
37
37
|
|
|
38
38
|
## Phase 4: Admin user setup
|
|
39
39
|
|
|
@@ -52,11 +52,11 @@ All steps must complete before users can safely use signing features. Order matt
|
|
|
52
52
|
- Poll `GET /admin/realms/{realm}/users/{userId}` until `attributes.tideUserKey` and `attributes.vuid` are present.
|
|
53
53
|
- Do not proceed until both attributes exist.
|
|
54
54
|
|
|
55
|
-
## Phase 5: Approve user change
|
|
55
|
+
## Phase 5: Approve user change requests
|
|
56
56
|
|
|
57
|
-
11. **Approve user change
|
|
58
|
-
- List: `GET /admin/realms/{realm}/
|
|
59
|
-
-
|
|
57
|
+
11. **Approve user change requests**
|
|
58
|
+
- List: `GET /admin/realms/{realm}/iga/change-requests?status=PENDING`.
|
|
59
|
+
- Authorize then commit (see Phase 3 / `canon/iga-change-requests-api.md`).
|
|
60
60
|
|
|
61
61
|
## Phase 6: IDP settings and adapter export
|
|
62
62
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -54,7 +54,7 @@ Troubleshoot broken Tide integrations. Own login failures, missing roles/claims,
|
|
|
54
54
|
|---------|-------------|----------|
|
|
55
55
|
| Login hangs or blank screen | CSP missing `frame-src '*'`, redirect handler missing, DPoP auth page missing | `diagnose-broken-login` |
|
|
56
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
|
|
57
|
+
| DPoP login fails | `tide_dpop_auth.html` missing, or its `app/tide_dpop/[...path]/route.ts` catch-all route handler / hash-pinned CSP / `Allow-CSP-From: *` header not configured (I-12, L-07) | `diagnose-broken-login` |
|
|
58
58
|
| 401 on all API calls | JWT verification not implemented, or DPoP proof missing | `diagnose-missing-roles-or-claims` |
|
|
59
59
|
| 403 on API calls | Role not assigned, IGA change-set not committed, or 120s refresh delay | `diagnose-missing-roles-or-claims` |
|
|
60
60
|
| Roles missing from JWT | IGA change-set not committed, token not refreshed (up to 120s) | `diagnose-missing-roles-or-claims` |
|
|
@@ -17,11 +17,11 @@ Wire the Tide SDK into the application. Own SDK installation, provider setup, co
|
|
|
17
17
|
| `tidecloak.json` placement and import | `tide-setup` if file doesn't exist and TideCloak not bootstrapped |
|
|
18
18
|
| `silent-check-sso.html` in `public/` | — |
|
|
19
19
|
| Post-auth redirect handler (`auth/redirect/page.tsx`) | — |
|
|
20
|
-
| `tide_dpop_auth.html`
|
|
20
|
+
| `tide_dpop_auth.html` served via a `app/tide_dpop/[...path]/route.ts` catch-all route handler + DPoP headers (I-12) | — |
|
|
21
21
|
| CSP (`frame-src '*'`) in `next.config` headers | — |
|
|
22
22
|
| Webpack workarounds (`strictExportPresence`, `@tidecloak/react` ESM alias) | — |
|
|
23
23
|
| Retrofit into existing apps | — |
|
|
24
|
-
|
|
|
24
|
+
| ASP.NET Core (.NET 10) backend via `Tide.Asgard.AspNetCore` SDK | Follow [playbooks/protect-aspnet-core-asgard.md](../../playbooks/protect-aspnet-core-asgard.md). Out of scope for the Next.js/React/Vanilla priority — do not invent OIDC wiring; route to that playbook. |
|
|
25
25
|
| Route/API protection | `tide-route-and-api-protection` |
|
|
26
26
|
| Roles, RBAC, encryption | `tide-rbac-and-e2ee` |
|
|
27
27
|
| TideCloak bootstrap, realm, licensing | `tide-setup` |
|
|
@@ -35,6 +35,7 @@ Wire the Tide SDK into the application. Own SDK installation, provider setup, co
|
|
|
35
35
|
- `tide-setup` detected hardening gaps (Path D)
|
|
36
36
|
- User asks to "add Tide to my app" or "add login"
|
|
37
37
|
- Orchestrator routed here after bootstrap is confirmed
|
|
38
|
+
- User asks about adding Tide auth to an **ASP.NET Core / C# / .NET** API. Route directly to [playbooks/protect-aspnet-core-asgard.md](../../playbooks/protect-aspnet-core-asgard.md) — do not attempt to retrofit Node-side guidance.
|
|
38
39
|
|
|
39
40
|
### Scenario-disambiguation gate (I-17)
|
|
40
41
|
|
|
@@ -71,8 +72,8 @@ Follow playbook `add-auth-nextjs-fresh`:
|
|
|
71
72
|
3. Place `tidecloak.json` at correct path (`data/` for Next.js, `public/` for React/Vite)
|
|
72
73
|
4. Create `public/silent-check-sso.html`
|
|
73
74
|
5. Create post-auth redirect handler at `auth/redirect/page.tsx`
|
|
74
|
-
6. Copy `tide_dpop_auth.html` to `public/` and
|
|
75
|
-
7.
|
|
75
|
+
6. Copy `tide_dpop_auth.html` to `public/` and serve it via a catch-all route handler at `app/tide_dpop/[...path]/route.ts` (matches the shipped `@tidecloak/create-nextjs` scaffold; I-12). The handler reads the single bundled `public/tide_dpop_auth.html` and returns it for any `/tide_dpop/...` path. Do NOT use `next.config.ts` rewrites for this.
|
|
76
|
+
7. On that route handler's response, set a **sha256 hash-pinned** CSP (pin the file's inline `script`/`style` via `sha256-...` hashes — NOT `script-src 'unsafe-inline'`) plus an `Allow-CSP-From: *` header (lets the ORK embed the page cross-origin). Global CSP stays `frame-src '*'` in `next.config` headers.
|
|
76
77
|
8. Add webpack workarounds to `next.config.ts`: `strictExportPresence = false` + `@tidecloak/react` ESM alias
|
|
77
78
|
|
|
78
79
|
### Existing app (has other auth)
|
|
@@ -82,16 +83,6 @@ Follow playbook `add-auth-nextjs-existing`:
|
|
|
82
83
|
2. Replace existing auth provider with `TideCloakProvider`
|
|
83
84
|
3. Remove old auth (NextAuth, Clerk, etc.) after Tide is working
|
|
84
85
|
|
|
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
86
|
### Hardening gaps (from tide-setup Path D)
|
|
96
87
|
|
|
97
88
|
Fix each missing item per the table in `tide-setup`.
|
|
@@ -105,11 +96,10 @@ Fix each missing item per the table in `tide-setup`.
|
|
|
105
96
|
- [ ] `tidecloak.json` exists with `jwk`, `vendorId`, `homeOrkUrl`
|
|
106
97
|
- [ ] `public/silent-check-sso.html` exists
|
|
107
98
|
- [ ] Post-auth redirect handler exists at configured `redirectUri`
|
|
108
|
-
- [ ] `public/tide_dpop_auth.html` exists + `
|
|
99
|
+
- [ ] `public/tide_dpop_auth.html` exists + `app/tide_dpop/[...path]/route.ts` catch-all route handler serves it with a sha256 hash-pinned CSP and `Allow-CSP-From: *`
|
|
109
100
|
- [ ] CSP includes `frame-src '*'`
|
|
110
101
|
- [ ] Webpack config has `strictExportPresence = false` + `@tidecloak/react` ESM alias
|
|
111
102
|
- [ ] Login flow completes: redirect to Tide IdP -> auth -> callback -> app
|
|
112
|
-
- [ ] If server-side admin calls needed: `@tidecloak/server` installed, delegation endpoints wired
|
|
113
103
|
|
|
114
104
|
---
|
|
115
105
|
|
|
@@ -132,5 +122,6 @@ Next: Security Engineer | STOP if integration incomplete
|
|
|
132
122
|
- Do not create ad hoc auth wiring. Follow the playbook.
|
|
133
123
|
- Do not use `NEXT_PUBLIC_TIDECLOAK_*` env vars. Use `tidecloak.json` directly. (AP-38)
|
|
134
124
|
- 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
|
|
125
|
+
- Do not modify `tide_dpop_auth.html`. It is integrity-checked and its inline script/style are sha256-pinned in the route handler's CSP. (I-12, L-07)
|
|
126
|
+
- Do not serve the DPoP auth page with `script-src 'unsafe-inline'`. Pin its inline script/style with `sha256-...` hashes in the route handler's CSP instead. (L-07)
|
|
127
|
+
- Do not use `next.config.ts` `rewrites()` to serve the DPoP auth page. Use the `app/tide_dpop/[...path]/route.ts` catch-all route handler (the shipped `@tidecloak/create-nextjs` approach). (I-12)
|
|
File without changes
|