@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,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
|