@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,254 @@
1
+ # Tide Post-Auth Redirect Handler
2
+
3
+ Tide auth uses OIDC authorization code flow. After authentication at TideCloak, the browser is redirected back to the application at the configured `redirectUri`. A real page or route must exist at that URI. Without it, the user lands on a 404 or blank page and login completion fails.
4
+
5
+ ---
6
+
7
+ ## Rule
8
+
9
+ **Every Tide-enabled app must have a working page or route at its configured `redirectUri`.** The Tide SDK provider must be active on that page to process the OIDC callback (extract the auth code and exchange it for tokens).
10
+
11
+ This applies whether using the default redirect path or a custom one.
12
+
13
+ **Default redirect path**: `/auth/redirect`
14
+
15
+ **ASSUMED**: The default redirect URI path convention is `/auth/redirect`. If a different path is used, the corresponding route must exist.
16
+
17
+ ---
18
+
19
+ ## Why This Matters
20
+
21
+ 1. TideCloak redirects the browser to `redirectUri?code=...&state=...` after authentication.
22
+ 2. The Tide SDK on the target page reads the URL parameters and completes the token exchange.
23
+ 3. If no page exists at the redirect URI, the browser shows a 404. The SDK never runs. Login appears to fail silently.
24
+ 4. If the page exists but the SDK provider is not active there, the auth code is ignored.
25
+
26
+ ---
27
+
28
+ ## Framework-Specific Guidance
29
+
30
+ ### Vanilla JS / Vite (Static)
31
+
32
+ **Default redirect path**: `/auth/redirect`
33
+
34
+ **Required file**: `public/auth/redirect.html`
35
+
36
+ This file must include the Tide SDK initialization script so the SDK can process the callback.
37
+
38
+ ```html
39
+ <!-- public/auth/redirect.html -->
40
+ <!DOCTYPE html>
41
+ <html lang="en">
42
+ <head>
43
+ <meta charset="UTF-8" />
44
+ <title>Completing login...</title>
45
+ </head>
46
+ <body>
47
+ <p>Completing login...</p>
48
+ <script type="module" src="/auth.js"></script>
49
+ </body>
50
+ </html>
51
+ ```
52
+
53
+ **If using a custom redirectUri**: the corresponding HTML file must exist in `public/` at the matching path, and it must load the SDK.
54
+
55
+ **Verification**:
56
+ ```bash
57
+ # Check the file exists
58
+ test -f public/auth/redirect.html && echo "Found" || echo "Missing"
59
+
60
+ # Check it is accessible
61
+ curl http://localhost:3000/auth/redirect.html
62
+ ```
63
+
64
+ ---
65
+
66
+ ### React SPA (Vite)
67
+
68
+ **Default redirect path**: `/auth/redirect`
69
+
70
+ **Required**: A route that renders at `/auth/redirect` within the SPA.
71
+
72
+ React SPAs serve `index.html` for all paths when the dev server or production server has SPA fallback enabled. If SPA fallback is configured (Vite dev server does this by default), the SDK provider on the root page handles the callback automatically.
73
+
74
+ **For production builds** served by a static file server without SPA fallback, create a physical file or configure server-side rewrite rules.
75
+
76
+ **Option A — React Router route** (recommended if using React Router):
77
+
78
+ ```tsx
79
+ // src/pages/AuthRedirect.tsx
80
+ export default function AuthRedirect() {
81
+ return <p>Completing login...</p>;
82
+ }
83
+
84
+ // In your router config:
85
+ // <Route path="/auth/redirect" element={<AuthRedirect />} />
86
+ ```
87
+
88
+ **Option B — Verify SPA fallback** (if not using React Router):
89
+
90
+ The Vite dev server serves `index.html` for all unmatched routes. The SDK provider on the root page processes the callback. For production, ensure your static host is configured for SPA fallback (e.g., `_redirects` file for Netlify, `vercel.json` rewrites, or nginx `try_files`).
91
+
92
+ **If using a custom redirectUri**: the matching route or SPA fallback path must resolve to a page where the SDK provider is active.
93
+
94
+ **Verification**:
95
+ ```bash
96
+ # In dev mode, verify the path resolves (should return HTML, not 404)
97
+ curl http://localhost:5173/auth/redirect
98
+ ```
99
+
100
+ ---
101
+
102
+ ### Next.js App Router
103
+
104
+ **Default redirect path**: `/auth/redirect`
105
+
106
+ **Required file**: `app/auth/redirect/page.tsx` (or `src/app/auth/redirect/page.tsx` if the project uses `src/`)
107
+
108
+ This page processes the OIDC callback using the SDK's `useAuthCallback` hook, then redirects the user:
109
+ - On success: to the `returnUrl` (where the user was before login) or home (`/`)
110
+ - On error or missing PKCE verifier (e.g. page refresh): back to home
111
+ - On direct navigation (no callback params): back to home
112
+
113
+ ```tsx
114
+ // app/auth/redirect/page.tsx
115
+ "use client";
116
+
117
+ import { useAuthCallback } from "@tidecloak/nextjs";
118
+ import { useEffect, useState } from "react";
119
+
120
+ // Separated so useAuthCallback only runs after hydration (avoids SSR window error).
121
+ function RedirectHandler() {
122
+ const { isProcessing, isSuccess, error } = useAuthCallback({
123
+ onSuccess: (returnUrl) => {
124
+ window.location.assign(returnUrl || "/");
125
+ },
126
+ onError: () => {
127
+ window.location.assign("/");
128
+ },
129
+ onMissingVerifierRedirectTo: "/",
130
+ });
131
+
132
+ useEffect(() => {
133
+ const params = new URLSearchParams(window.location.search);
134
+ if (!params.has("code") && !params.has("error")) {
135
+ window.location.assign("/");
136
+ }
137
+ }, []);
138
+
139
+ if (error) {
140
+ return <p>Authentication failed: {error.message}</p>;
141
+ }
142
+
143
+ if (isProcessing || !isSuccess) {
144
+ return <p>Completing login...</p>;
145
+ }
146
+
147
+ return <p>Redirecting...</p>;
148
+ }
149
+
150
+ export default function AuthRedirectPage() {
151
+ const [mounted, setMounted] = useState(false);
152
+ useEffect(() => setMounted(true), []);
153
+ if (!mounted) return <p>Loading...</p>;
154
+ return <RedirectHandler />;
155
+ }
156
+ ```
157
+
158
+ **Do not** use a bare placeholder page (e.g., `return <p>Completing login...</p>` with no callback handling). The page must actively process the OIDC callback and redirect the user.
159
+
160
+ **If using a custom redirectUri**: the corresponding App Router page must exist at the matching path.
161
+
162
+ **Verification**:
163
+ ```bash
164
+ # Check the file exists (adjust for src/ if needed)
165
+ test -f app/auth/redirect/page.tsx && echo "Found" || echo "Missing"
166
+
167
+ # Check the route resolves
168
+ curl http://localhost:3000/auth/redirect
169
+ # Should return HTML, not 404
170
+ ```
171
+
172
+ ---
173
+
174
+ ### Next.js Pages Router
175
+
176
+ **Default redirect path**: `/auth/redirect`
177
+
178
+ **Required file**: `pages/auth/redirect.tsx` (or `src/pages/auth/redirect.tsx` if the project uses `src/`)
179
+
180
+ The SDK provider in `_app.tsx` covers all pages.
181
+
182
+ ```tsx
183
+ // pages/auth/redirect.tsx
184
+ export default function AuthRedirectPage() {
185
+ return <p>Completing login...</p>;
186
+ }
187
+ ```
188
+
189
+ **If using a custom redirectUri**: the corresponding Pages Router file must exist at the matching path.
190
+
191
+ **Verification**:
192
+ ```bash
193
+ test -f pages/auth/redirect.tsx && echo "Found" || echo "Missing"
194
+ curl http://localhost:3000/auth/redirect
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Diagnostic: Missing Redirect Handler
200
+
201
+ **Symptom**: Login at TideCloak succeeds (credentials accepted) but the user lands on a 404 page or a blank page instead of returning to the app authenticated.
202
+
203
+ **Diagnostic steps**:
204
+
205
+ 1. Check the configured `redirectUri`:
206
+ ```bash
207
+ # Next.js
208
+ grep 'REDIRECT_URI' .env.local .env
209
+ grep 'redirectUri' app/providers.tsx app/layout.tsx pages/_app.tsx 2>/dev/null
210
+
211
+ # React/Vite
212
+ cat public/tidecloak.json | grep redirect 2>/dev/null
213
+
214
+ # Vanilla JS
215
+ grep 'redirectUri' public/auth.js public/*.js 2>/dev/null
216
+ ```
217
+
218
+ 2. Check the handler exists at the redirect path:
219
+ ```bash
220
+ # Next.js App Router
221
+ test -f app/auth/redirect/page.tsx || test -f src/app/auth/redirect/page.tsx
222
+
223
+ # Next.js Pages Router
224
+ test -f pages/auth/redirect.tsx || test -f src/pages/auth/redirect.tsx
225
+
226
+ # React/Vite (check SPA fallback or physical file)
227
+ curl -s -o /dev/null -w "%{http_code}" http://localhost:5173/auth/redirect
228
+
229
+ # Vanilla JS
230
+ test -f public/auth/redirect.html
231
+ ```
232
+
233
+ 3. Verify the TideCloak client allows the redirect URI:
234
+ - TideCloak Admin → Clients → {client} → Settings → Valid Redirect URIs
235
+ - Must include the full redirect URI (e.g., `http://localhost:3000/auth/redirect`)
236
+
237
+ **Fix**: Create the missing handler file or route using the examples above. Update TideCloak client settings to include the redirect URI.
238
+
239
+ ---
240
+
241
+ ## Anti-Patterns
242
+
243
+ - **AP-REDIR-01**: Setting `redirectUri` to a path that does not exist in the app. Login completes at TideCloak but the user sees a 404.
244
+ - **AP-REDIR-02**: Creating the redirect page but not including the SDK provider. The page renders but the auth code is never processed.
245
+ - **AP-REDIR-03**: Assuming the redirect handler is optional. Without it, every login attempt fails to complete.
246
+ - **AP-REDIR-04**: Using `redirectUri: window.location.origin` (root) without verifying the SDK is active on the landing page. This works when the root page has the SDK but breaks if the root redirects elsewhere.
247
+
248
+ ---
249
+
250
+ ## Relation to Other Invariants
251
+
252
+ - **I-06 (CSP)**: Even with a correct redirect handler, CSP violations block the SWE iframe and cause login to hang.
253
+ - **I-07 (Silent SSO)**: The `silent-check-sso.html` file handles silent token refresh, not the post-auth redirect. Both are required.
254
+ - **Redirect URI mismatch**: If the URI configured in the SDK does not match the TideCloak client's Valid Redirect URIs list, TideCloak rejects the request before the redirect handler is even reached. See `diagnose-broken-login`.
@@ -0,0 +1,287 @@
1
+ # TideCloak Bootstrap — Canon
2
+
3
+ Canonical reference for starting TideCloak and preparing a realm before any app-level Tide integration begins.
4
+
5
+ Bootstrap is infrastructure work. It produces a running TideCloak with a configured realm, a linked admin, and an exported adapter JSON. App integration (SDK wiring, route protection, API auth) is a separate concern covered by the app-level canon and playbooks.
6
+
7
+ ---
8
+
9
+ ## Bootstrap Paths
10
+
11
+ | Path | When to use | How |
12
+ |------|-------------|-----|
13
+ | **Generated app** (default) | New project from template | `npm run init` runs the bundled init script. Handles everything below automatically. |
14
+ | **Manual / BYO TideCloak** (advanced) | Existing TideCloak instance, custom realm, or non-template project | Follow the playbook chain: `start-tidecloak-dev` → `bootstrap-realm-from-template` → `initialize-admin-and-link-account`. |
15
+
16
+ ### Generated app flow
17
+
18
+ Templates include `scripts/init-tidecloak.sh` and a `"init"` script in package.json. The dev workflow is:
19
+
20
+ ```bash
21
+ npm install
22
+ npm run init # starts TideCloak, creates realm, exports tidecloak.json
23
+ npm run dev
24
+ ```
25
+
26
+ The init script:
27
+ 1. Starts TideCloak dev container (Docker required)
28
+ 2. Creates realm from bundled template
29
+ 3. Runs Tide licensing + IGA setup
30
+ 4. Creates admin user with `tide-realm-admin` role
31
+ 5. Prints an invite link (admin must open in browser to link Tide account)
32
+ 6. Waits for account linking
33
+ 7. Approves change requests
34
+ 8. Exports `data/tidecloak.json` with Tide extensions
35
+
36
+ After init, the app is ready. No manual TideCloak configuration needed.
37
+
38
+ **Bootstrap order rule**: Always run bootstrap before writing app code. If the app imports `tidecloak.json` at compile time (e.g., TypeScript `import tcConfig from '../../data/tidecloak.json'`), create an empty placeholder file (`echo '{}' > data/tidecloak.json`) before the first build. The init script overwrites it with the real adapter. Add `data/tidecloak.json` to `.gitignore`.
39
+
40
+ ### Manual / BYO TideCloak flow
41
+
42
+ For projects that do not use the init script, follow the manual sequence below. This is also the path for connecting to an existing TideCloak instance.
43
+
44
+ ---
45
+
46
+ ## Scope Boundary
47
+
48
+ | Concern | Covered here | Covered elsewhere |
49
+ |---------|-------------|-------------------|
50
+ | Docker container lifecycle | Yes | — |
51
+ | Realm creation from template | Yes | — |
52
+ | Tide licensing + IGA enablement | Yes | — |
53
+ | Admin user creation + account linking | Yes | — |
54
+ | Change request approval (bootstrap phase) | Yes | `setup-iga-admin-panel` for runtime |
55
+ | Adapter JSON export | Yes | — |
56
+ | E2EE role + policy setup | Yes (realm prep) | `setup-forseti-e2ee` for app-level |
57
+ | SDK wiring, provider, CSP | No | `add-auth-nextjs-fresh` et al. |
58
+ | JWT verification, DPoP | No | `verify-jwt-server-side` |
59
+
60
+ ---
61
+
62
+ ## Docker Images
63
+
64
+ | Image | Use when | Forseti support | `tide-roles-mapper` | ORK env vars required |
65
+ |-------|----------|----------------|---------------------|-----------------------|
66
+ | `tideorg/tidecloak-dev:latest` | Standard development, full Tide protocol | Yes | **Yes** | **No** — built-in defaults |
67
+ | `tideorg/tidecloak-stg-dev:latest` | Staging, testing pre-release features | Yes | **No** — silently dropped on import | **Yes** — must be provided |
68
+
69
+ **Staging mapper gap**: The `tide-roles-mapper` protocolMapper provider exists on the production image (`tidecloak-dev`) but not staging (`tidecloak-stg-dev`). Realm import silently drops the mapper with no warning. Include standard Keycloak role mappers (`realm roles`, `client roles`) as fallback in the template alongside the Tide-specific mapper. VERIFIED (learning-batch-004, L-06).
70
+
71
+ Use `tidecloak-dev` for standard development. It has built-in ORK/threshold defaults and does not need `KC_HOSTNAME`, `SYSTEM_HOME_ORK`, `USER_HOME_ORK`, `THRESHOLD_T`, `THRESHOLD_N`, or `PAYER_PUBLIC`. Use `tidecloak-stg-dev` only when testing against pre-release Tide features.
72
+
73
+ **Do not append `start-dev` or any command** to `docker run`. TideCloak images have a pre-configured entrypoint — appending `start-dev` (a vanilla Keycloak convention) breaks Tide initialization. See AP-39.
74
+
75
+ ### Dev image docker run (tidecloak-dev)
76
+
77
+ ```bash
78
+ sudo docker run -d --name tidecloak \
79
+ -v ./data:/opt/keycloak/data/h2 \
80
+ -p 8080:8080 \
81
+ -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
82
+ -e KC_BOOTSTRAP_ADMIN_PASSWORD=password \
83
+ tideorg/tidecloak-dev:latest
84
+ ```
85
+
86
+ ### Staging image docker run (tidecloak-stg-dev)
87
+
88
+ ```bash
89
+ sudo docker run -d --name tidecloak \
90
+ -v ./data:/opt/keycloak/data/h2 \
91
+ -p 8080:8080 \
92
+ -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
93
+ -e KC_BOOTSTRAP_ADMIN_PASSWORD=password \
94
+ -e KC_HOSTNAME=http://localhost:8080 \
95
+ -e SYSTEM_HOME_ORK=https://sork1.tideprotocol.com \
96
+ -e USER_HOME_ORK=https://sork1.tideprotocol.com \
97
+ -e THRESHOLD_T=3 \
98
+ -e THRESHOLD_N=5 \
99
+ -e PAYER_PUBLIC=20000011d6a0e8212d682657147d864b82d10e92776c15ead43dcfdc100ebf4dcfe6a8 \
100
+ tideorg/tidecloak-stg-dev:latest
101
+ ```
102
+
103
+ ---
104
+
105
+ ## Required Environment Variables
106
+
107
+ ### Core (both images)
108
+
109
+ | Variable | Purpose | Example |
110
+ |----------|---------|---------|
111
+ | `KC_BOOTSTRAP_ADMIN_USERNAME` | Initial admin user | `admin` |
112
+ | `KC_BOOTSTRAP_ADMIN_PASSWORD` | Initial admin password | `password` |
113
+
114
+ ### Tide protocol (staging image only — tidecloak-stg-dev)
115
+
116
+ The dev image (`tidecloak-dev`) has these built in. Only set these for `tidecloak-stg-dev`.
117
+
118
+ | Variable | Purpose | Example |
119
+ |----------|---------|---------|
120
+ | `KC_HOSTNAME` | Public-facing URL | `http://localhost:8080` |
121
+ | `SYSTEM_HOME_ORK` | Tide network entry point | `https://sork1.tideprotocol.com` |
122
+ | `USER_HOME_ORK` | User-facing ORK URL | `https://sork1.tideprotocol.com` |
123
+ | `THRESHOLD_T` | Signing threshold | `3` |
124
+ | `THRESHOLD_N` | Total ORK nodes | `5` |
125
+ | `PAYER_PUBLIC` | Payer ORK public key | hex string |
126
+
127
+ **Anti-pattern:** Omitting Tide env vars. Without `SYSTEM_HOME_ORK`, `USER_HOME_ORK`, `THRESHOLD_T`, `THRESHOLD_N`, and `PAYER_PUBLIC`, the Tide IdP provider does not initialize. Required actions like `link-tide-account-action` never register, and the init script fails with "Could not find configuration for Required Action". VERIFIED.
128
+
129
+ ---
130
+
131
+ ## Initialization Sequence
132
+
133
+ Order matters. Do not skip or reorder steps.
134
+
135
+ | # | Step | API / action | Produces |
136
+ |---|------|-------------|----------|
137
+ | 1 | Clean previous state | `docker rm`, clear `data/keycloakdb*`, `chown 1000:1000 data/` | Clean slate |
138
+ | 2 | Start container | `docker run` with correct image + env vars | Running TideCloak |
139
+ | 3 | Wait for readiness | Poll `GET /` until 200 | Reachable server |
140
+ | 4 | Get master admin token | `POST /realms/master/protocol/openid-connect/token` | Bearer token |
141
+ | 5 | Create realm | `POST /admin/realms` with realm.json template | Realm + client |
142
+ | 6 | Initialize Tide + enable IGA | `POST /admin/realms/{realm}/vendorResources/setUpTideRealm` then `POST /admin/realms/{realm}/tide-admin/toggle-iga` | License activated, VRK generated, IGA enabled |
143
+ | 7 | Approve client + role change requests | `sign` + `commit` on `/tide-admin/change-set/clients/requests` AND `/roles/requests`. **Roles must be approved here** — `setUpTideRealm` creates `tide-realm-admin` as a draft when IGA is enabled. Without approval, role lookups in Step 8c fail. | Client config + roles committed |
144
+ | 8 | Create admin user | `POST /admin/realms/{realm}/users` | User creation change request created |
145
+ | 8b | Approve user creation | `sign` + `commit` on `/tide-admin/change-set/users/requests` | User queryable. **Must happen before role assignment.** |
146
+ | 8c | Assign tide-realm-admin role | Assign `tide-realm-admin` client role on `realm-management`. Validate role lookup returns a role, not an error. | Admin user has role |
147
+ | 9 | Generate invite link | `POST /tideAdminResources/get-required-action-link` with `["link-tide-account-action"]` | URL for admin to link Tide account |
148
+ | 10 | Wait for account linking | Poll user `tideUserKey` attribute until non-empty | Admin has Tide identity |
149
+ | 11 | Approve role assignment change requests | `sign` + `commit` on `/tide-admin/change-set/users/requests` and `/roles/requests` | Admin roles committed |
150
+ | 12 | Update CustomAdminUIDomain | `PUT /identity-provider/instances/tide` then `POST /vendorResources/sign-idp-settings` | Enclave approval popups work from app origin |
151
+ | 13 | Export adapter JSON | `GET /vendorResources/get-installations-provider?clientId={uuid}&providerId=keycloak-oidc-keycloak-json` | `tidecloak.json` with `jwk`, `vendorId`, `homeOrkUrl` |
152
+
153
+ ---
154
+
155
+ ## Critical Endpoint Details
156
+
157
+ ### setUpTideRealm
158
+
159
+ - Path: `POST /admin/realms/{realm}/vendorResources/setUpTideRealm`
160
+ - Content-Type: `application/x-www-form-urlencoded` (NOT JSON)
161
+ - Body: `email=admin@yourorg.com` (required, URL-encoded)
162
+ - Handles license activation automatically. No manual "Manage License" step needed.
163
+
164
+ **Anti-pattern:** Using `/tide-admin/setUpTideRealm`. Wrong path. Returns 404. VERIFIED.
165
+
166
+ **Anti-pattern:** Sending JSON to this endpoint. Causes "Could not create tide realm" (`email is null or empty`). VERIFIED.
167
+
168
+ ### toggle-iga
169
+
170
+ - Path: `POST /admin/realms/{realm}/tide-admin/toggle-iga`
171
+ - Content-Type: `application/x-www-form-urlencoded`
172
+ - Body: `isIGAEnabled=true`
173
+
174
+ ### Approve/commit change requests
175
+
176
+ - Sign: `POST /admin/realms/{realm}/tide-admin/change-set/sign`
177
+ - Commit: `POST /admin/realms/{realm}/tide-admin/change-set/commit`
178
+ - Both accept JSON: `{ "changeSetId": "...", "changeSetType": "...", "actionType": "..." }`
179
+ - For batch: use `/sign/batch` and `/commit/batch` with `{ "changeSets": [...] }`
180
+
181
+ ### Adapter config export
182
+
183
+ - Path: `GET /admin/realms/{realm}/vendorResources/get-installations-provider`
184
+ - Query: `clientId={uuid}&providerId=keycloak-oidc-keycloak-json`
185
+ - The `jwk` field is only present when IGA is enabled.
186
+
187
+ ---
188
+
189
+ ## Realm Template Requirements
190
+
191
+ The realm.json template must include ALL of the following. Missing any section causes silent failures.
192
+
193
+ | Section | Required for | Failure if missing |
194
+ |---------|-------------|-------------------|
195
+ | `requiredActions` with `link-tide-account-action` | Admin invite links | Invite link generation fails |
196
+ | `authenticationFlows` with `tidebrowser` | Tide login flow | Login uses default Keycloak flow, not Tide |
197
+ | `authenticatorConfig` with `defaultProvider: tide` | IdP redirect | Users not redirected to Tide IdP |
198
+ | `browserFlow: "tidebrowser"` | Flow binding | Auth flow not activated |
199
+ | `protocolMappers` (Tide User Key, IGA Role Mapper, vuid) | JWT claims | Missing `tideuserkey`, `vuid`, roles in tokens |
200
+ | `components` (user profile) | User attributes | Attribute storage fails |
201
+ | `roles.realm` with `_tide_enabled` in default composite | Voucher system | Users cannot perform Tide operations |
202
+ | `UPDATE_PASSWORD` disabled | Tide auth model | Password update prompt conflicts with PRISM |
203
+
204
+ **Anti-pattern:** Creating a minimal realm.json. Every section above is mandatory. VERIFIED.
205
+
206
+ **Anti-pattern:** Including `identityProviders` in realm template when `setUpTideRealm` runs after import. `setUpTideRealm` creates the Tide IDP internally. A duplicate `tide` IDP in the template causes `ModelDuplicateException`, which breaks licensing and prevents `tide-realm-admin` from being created. Remove `identityProviders` from the template. VERIFIED (LEARNINGS-batch-006 L-01).
207
+
208
+ **Anti-pattern:** Placing `unmanagedAttributePolicy` at realm top level. Keycloak 26+ expects it inside `components.org.keycloak.userprofile.UserProfileProvider[0].config.kc.user.profile.config` as part of the embedded JSON string. Top-level placement causes HTTP 400 on import or silently drops `tideUserKey`/`vuid` attributes during account linking. VERIFIED (LEARNINGS-batch-006 L-02).
209
+
210
+ **Duplicate default role warning**: TideCloak may create a duplicate default role during IGA-enabled realm setup (e.g., `default-roles-myapp-1` alongside `default-roles-myapp`). The duplicate is empty — new users assigned to it get none of the `_tide_*` voucher roles. After user creation, explicitly verify the user has `_tide_*` roles. If missing, assign them via admin API. With IGA enabled, role assignment change-sets require browser enclave approval (`requiresApprovalPopup: true`). VERIFIED (learning-batch-004, L-08).
211
+
212
+ ### Manual realm creation (without template)
213
+
214
+ If creating a realm without the full template (e.g., `POST /admin/realms` with `{"realm":"myapp","enabled":true}`), you must manually register `link-tide-account-action`:
215
+
216
+ ```bash
217
+ curl -X POST "$TIDECLOAK_URL/admin/realms/$REALM_NAME/authentication/register-required-action" \
218
+ -H "Authorization: Bearer $TOKEN" \
219
+ -H "Content-Type: application/json" \
220
+ -d '{"providerId":"link-tide-account-action","name":"Link Tide Account"}'
221
+ ```
222
+
223
+ Without this, invite links redirect to VERIFY_PROFILE or the default login flow instead of Tide account linking. VERIFIED (session-001).
224
+
225
+ ### Admin user profile requirements
226
+
227
+ When creating the admin user, always set `firstName` and `lastName`:
228
+
229
+ ```json
230
+ {"username":"admin","email":"admin@yourorg.com","firstName":"Admin","lastName":"User","enabled":true}
231
+ ```
232
+
233
+ If these fields are empty, TideCloak's `VERIFY_PROFILE` required action fires before the Tide account linking flow, blocking bootstrap. Alternatively, disable `VERIFY_PROFILE` as a default required action on the realm. VERIFIED (session-001).
234
+
235
+ ### Bootstrap script fail-fast rule
236
+
237
+ The bootstrap/init script must check the HTTP status of every critical step and abort on failure. In particular:
238
+
239
+ - Realm import (`POST /admin/realms`) must return 2xx. If it returns 400/409/500, stop. Do not continue to licensing or IGA.
240
+ - `setUpTideRealm` must return 200. If it fails, the realm is unlicensed and all subsequent steps are invalid.
241
+
242
+ **Anti-pattern:** Continuing bootstrap after realm import failure. Later steps (licensing, IGA, user creation) either fail silently or produce garbage state. Agent wastes multiple rounds debugging cascaded failures. VERIFIED (session-001).
243
+
244
+ ---
245
+
246
+ ## Data Directory Rules
247
+
248
+ - Mount `./data:/opt/keycloak/data/h2`, never the project root.
249
+ - Run `mkdir -p ./data && sudo chown -R 1000:1000 ./data` before starting.
250
+ - Clear stale DB files between fresh setups: `sudo rm -f ./data/keycloakdb*`
251
+ - Never mount a docker-compose named volume on a standalone `docker run`.
252
+
253
+ **Failure mode:** Mounting `.:/opt/keycloak/data/h2` (project root) causes `AccessDeniedException` because Docker writes DB files as UID 1000. VERIFIED.
254
+
255
+ **Failure mode:** Stale DB files cause "Could not open file keycloakdb.mv.db". VERIFIED.
256
+
257
+ ---
258
+
259
+ ## Dev vs Production Separation
260
+
261
+ | Aspect | Dev (this canon) | Production |
262
+ |--------|-----------------|------------|
263
+ | Database | H2 embedded | External PostgreSQL (not documented — contact Tide) |
264
+ | Image | `tidecloak-dev` (prod) or `tidecloak-stg-dev` (staging) | `tidecloak-dev` is production-grade |
265
+ | Threshold | T=3/N=5 minimum | T=14/N=20 on live network |
266
+ | SSL | `sslRequired: external` (HTTP on localhost OK) | HTTPS required everywhere |
267
+ | Admin password | Hardcoded in script | Secret management system |
268
+ | VRK keys | Per-environment, never shared | Per-environment, never shared |
269
+
270
+ **Anti-pattern:** Using `THRESHOLD_T=1` in any environment. Single-ORK compromise breaks security. VERIFIED.
271
+
272
+ **Anti-pattern:** Sharing VRK keys between environments. Breaks rotation lifecycle. VERIFIED.
273
+
274
+ ---
275
+
276
+ ## Verification
277
+
278
+ Bootstrap is complete when:
279
+
280
+ - [ ] TideCloak container running, `curl http://localhost:8080` returns 200
281
+ - [ ] Realm exists with Tide IdP configured
282
+ - [ ] IGA is enabled
283
+ - [ ] Admin user has `tide-realm-admin` client role on `realm-management`
284
+ - [ ] Admin has linked their Tide account (`tideUserKey` attribute non-empty)
285
+ - [ ] All bootstrap change requests approved and committed
286
+ - [ ] CustomAdminUIDomain set to app origin
287
+ - [ ] Adapter JSON exported with `jwk`, `vendorId`, `homeOrkUrl` fields present