@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,654 @@
1
+ # Add Tide Auth to Fresh Next.js Project
2
+
3
+ Manual setup for integrating Tide authentication into a new Next.js application.
4
+
5
+ ---
6
+
7
+ ## When to Use
8
+
9
+ - Starting a new Next.js project (App Router or Pages Router)
10
+ - Need threshold password authentication (BYOiD)
11
+ - Need threshold JWT signing (VVK)
12
+ - Need optional E2EE or IGA features later
13
+ - Have a running TideCloak instance
14
+
15
+ **Do not use** if you already have an existing Next.js app with auth. See [add-auth-nextjs-existing.md](add-auth-nextjs-existing.md) instead.
16
+
17
+ ---
18
+
19
+ ## Prerequisites
20
+
21
+ ### Running Services
22
+
23
+ - TideCloak instance accessible (local or remote)
24
+ - TideCloak realm created and configured
25
+ - TideCloak client created in realm
26
+ - IGA enabled on realm (see [canon/concepts.md](../canon/concepts.md#iga-identity-governance--administration))
27
+
28
+ ### Local Environment
29
+
30
+ - Node.js 18+
31
+ - Next.js 13+ installed. For automated/agent builds, prefer `npm init -y && npm install next react react-dom typescript @types/react @types/node` over `npx create-next-app@latest` — the latter has interactive prompts (React Compiler, etc.) that may block automation. VERIFIED (LEARNINGS-batch-009 L-04).
32
+ - TypeScript project recommended (all code examples use `.tsx`). If your project has no `tsconfig.json`, Next.js auto-generates one on first `npm run dev`.
33
+ - Package manager (npm, yarn, pnpm)
34
+
35
+ ### Required Information
36
+
37
+ - TideCloak URL (e.g., `https://tidecloak.example.com`)
38
+ - Realm name
39
+ - Client ID
40
+ - Adapter JSON exported from TideCloak
41
+
42
+ ---
43
+
44
+ ## Files to Inspect First
45
+
46
+ Before starting, confirm these exist:
47
+
48
+ ```bash
49
+ # Next.js project structure
50
+ ls -la
51
+ # Should show: package.json, next.config.js, app/ or pages/
52
+
53
+ # Check Next.js version
54
+ cat package.json | grep '"next"'
55
+ # Should be 13.0.0 or higher
56
+
57
+ # Check router type
58
+ ls -la app/ 2>/dev/null && echo "App Router" || echo "Pages Router"
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Files to Create/Edit
64
+
65
+ ### Step Overview
66
+
67
+ 1. Install SDK package
68
+ 2. Create adapter JSON storage location
69
+ 3. Add environment variables
70
+ 4. Create provider component (App Router) or wrap `_app` (Pages Router)
71
+ 5. Create silent SSO file
72
+ 6. Create post-auth redirect handler
73
+ 7. Configure CSP (observed requirement from keylessh)
74
+ 8. Verify login flow
75
+
76
+ ---
77
+
78
+ ## Exact Step Sequence
79
+
80
+ ### Step 1: Install Tide SDK
81
+
82
+ ```bash
83
+ npm install @tidecloak/nextjs
84
+ ```
85
+
86
+ **Verify version**: All `@tidecloak/*` packages are currently at `0.13.x`. Run `npm view @tidecloak/nextjs version` to confirm. Do not assume `1.0.0`.
87
+
88
+ **Next.js 16+ bundler**: Next.js 16 defaults to Turbopack. The Tide SDK requires webpack for `strictExportPresence = false` and `@tidecloak/react` ESM alias. Update `package.json` scripts:
89
+ ```json
90
+ "scripts": {
91
+ "dev": "next dev --webpack",
92
+ "build": "next build --webpack"
93
+ }
94
+ ```
95
+ Without `--webpack`, `next build` fails with: `"This build is using Turbopack, with a webpack config and no turbopack config"`. VERIFIED (LEARNINGS-session-003 L-02).
96
+
97
+ ---
98
+
99
+ ### Step 2: Export Adapter JSON from TideCloak
100
+
101
+ **Via Admin Console**:
102
+ 1. Login to TideCloak Admin Console
103
+ 2. Navigate to: Clients → {your-client} → Installation
104
+ 3. Select format: "Tide OIDC JSON" (NOT "Keycloak OIDC JSON")
105
+ 4. Download file
106
+
107
+ **Via API** (Tide vendor endpoint — NOT the standard Keycloak installation path):
108
+ ```bash
109
+ # First get the client UUID
110
+ CLIENT_UUID=$(curl -s "${TIDECLOAK_URL}/admin/realms/${REALM}/clients?clientId=${CLIENT_NAME}" \
111
+ -H "Authorization: Bearer ${ADMIN_TOKEN}" | jq -r '.[0].id')
112
+
113
+ # Export via vendorResources (returns jwk, vendorId, homeOrkUrl)
114
+ curl -s "${TIDECLOAK_URL}/admin/realms/${REALM}/vendorResources/get-installations-provider?clientId=${CLIENT_UUID}&providerId=keycloak-oidc-keycloak-json" \
115
+ -H "Authorization: Bearer ${ADMIN_TOKEN}" \
116
+ > data/tidecloak.json
117
+ ```
118
+
119
+ **Do NOT use** the standard Keycloak path (`/clients/{id}/installation/providers/keycloak-oidc-keycloak-json`) — it returns a minimal adapter missing `jwk`, `vendorId`, and `homeOrkUrl`. VERIFIED (LEARNINGS-batch-008 L-04).
120
+
121
+ **Store adapter JSON**:
122
+ ```bash
123
+ # Create data directory
124
+ mkdir -p data
125
+
126
+ # Move downloaded adapter to data/tidecloak.json
127
+ mv ~/Downloads/tidecloak.json data/
128
+
129
+ # Verify Tide extensions present
130
+ node -e "const c = require('./data/tidecloak.json'); console.log('Has jwk:', !!c.jwk); console.log('Has vendorId:', !!c.vendorId); console.log('Has homeOrkUrl:', !!c.homeOrkUrl);"
131
+ # Should output: Has jwk: true, Has vendorId: true, Has homeOrkUrl: true
132
+ ```
133
+
134
+ **Required**: The `jwk` field contains the embedded JWKS for local JWT verification. This field is present in Tide adapter exports due to Tide's non-rotating vendor-verifiable key (VVK) model. The system is locked to trust one pre-defined public key, ensuring that even if the IAM is compromised, it cannot forge valid tokens.
135
+
136
+ ---
137
+
138
+ ### Step 3: Store Adapter JSON
139
+
140
+ The adapter JSON exported in Step 2 is the provider's config. Store it where the app can import it:
141
+
142
+ ```bash
143
+ # Add to .gitignore
144
+ echo "data/tidecloak.json" >> .gitignore # Contains sensitive config
145
+ ```
146
+
147
+ **Note**: The `TideCloakProvider` takes the adapter JSON directly as a `config` prop. No environment variables are needed for the provider. Environment variables are only needed for the init script and server-side config loading.
148
+
149
+ ---
150
+
151
+ ### Step 4a: Provider Setup (App Router)
152
+
153
+ Create `app/providers.tsx`:
154
+ ```typescript
155
+ // app/providers.tsx
156
+ 'use client';
157
+
158
+ import { TideCloakProvider } from '@tidecloak/nextjs';
159
+ import tcConfig from '../../data/tidecloak.json';
160
+
161
+ export function Providers({ children }: { children: React.ReactNode }) {
162
+ return (
163
+ <TideCloakProvider
164
+ config={{ ...tcConfig, useDPoP: { mode: 'strict', alg: 'ES256' } }}
165
+ >
166
+ {children}
167
+ </TideCloakProvider>
168
+ );
169
+ }
170
+ ```
171
+
172
+ **`useDPoP` goes inside the config object**, not as a separate JSX prop. The `TideCloakProvider` only accepts `config` and `children`. VERIFIED (session-002).
173
+
174
+ **DPoP is a bidirectional lockstep requirement** (I-12):
175
+ 1. **Server-side**: Realm template sets client attribute `"dpop.bound.access.tokens": "true"`.
176
+ 2. **Client-side**: `useDPoP` in the config object tells the SDK to generate DPoP proofs.
177
+ 3. **Both must be set simultaneously.** Server-side without client-side → token endpoint returns 400 "DPoP proof is missing." Client-side without server-side → proofs generated but ignored.
178
+
179
+ **`tide_dpop_auth.html` required** (when DPoP is enabled):
180
+ - Copy `tide_dpop_auth.html` to `public/`. This file is loaded by the Tide enclave during login to prove DPoP key possession to the ORKs. **Do not modify it** — its content is integrity-checked. VERIFIED (learning-batch-004, L-07).
181
+ - **The HTML must match the SDK version.** The only source for this file is the pack template (`templates/*/public/tide_dpop_auth.html`). It is NOT shipped inside `@tidecloak/*` npm packages. If the pack template is stale and the enclave rejects it with `Popup DPoP verification failed to load`, contact the Tide team for the updated file. VERIFIED (LEARNINGS-batch-005 L-05, LEARNINGS-batch-007 L-03).
182
+ - The SDK requests it at `/tide_dpop/iss/<hex-issuer>/aud/<hex-client>/tide_dpop_auth.html` — a path that doesn't map to the static file in `public/`. Use `next.config.ts` `rewrites()` to map `/tide_dpop/:path*` → `/tide_dpop_auth.html`.
183
+ - **Do NOT use a route handler** (`app/tide_dpop/[...path]/route.ts`). Next.js 16 dev server injects its own hash-based CSP on route handler responses, overriding `script-src 'unsafe-inline'`. The DPoP page's inline script gets blocked. Static files served via rewrites are not affected. VERIFIED (LEARNINGS-batch-005 L-04).
184
+ - **Do NOT validate issuer/client hex params** in the handler. The enclave already integrity-checks the HTML. Server-side validation that fails (config loading, path resolution) returns 400 before the HTML loads, killing the popup. VERIFIED (LEARNINGS-batch-005 L-03).
185
+ - Set CSP via `next.config.ts` `headers()` targeting `/tide_dpop/:path*`: `Content-Security-Policy: default-src 'self'; script-src 'unsafe-inline'` and `Allow-CSP-From: *`.
186
+ - Without this file and rewrite, DPoP login fails with: `Tide user did not provided a dpop bound token but a dpop cnf claim was found in requested token`.
187
+
188
+ **`secureFetch` usage rules** (when `useDPoP` is enabled):
189
+ - Use `IAMService.secureFetch` from `@tidecloak/js` with `await IAMService.getToken()` for the managed token. **`getToken()` returns a Promise** — you must `await` it. Without `await`, the Authorization header becomes `Bearer [object Promise]` and the server rejects with `JWSInvalid: Invalid Compact JWS`. VERIFIED (LEARNINGS-batch-005 L-07).
190
+ - `secureFetch` requires **absolute URLs** — relative paths throw. Use `\`\${window.location.origin}/api/vault\``.
191
+ - **Recommended**: Create an `appFetch` wrapper. See canon/anti-patterns.md for the pattern.
192
+
193
+ Edit `app/layout.tsx`:
194
+ ```typescript
195
+ // app/layout.tsx
196
+ import { Providers } from './providers';
197
+
198
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
199
+ return (
200
+ <html lang="en">
201
+ <body>
202
+ <Providers>{children}</Providers>
203
+ </body>
204
+ </html>
205
+ );
206
+ }
207
+ ```
208
+
209
+ ---
210
+
211
+ ### Step 4b: Provider Setup (Pages Router)
212
+
213
+ Edit `pages/_app.tsx`:
214
+ ```typescript
215
+ // pages/_app.tsx
216
+ import type { AppProps } from 'next/app';
217
+ import { TideCloakProvider } from '@tidecloak/nextjs';
218
+ import tcConfig from '../data/tidecloak.json';
219
+
220
+ export default function App({ Component, pageProps }: AppProps) {
221
+ return (
222
+ <TideCloakProvider
223
+ config={{ ...tcConfig, useDPoP: { mode: 'strict', alg: 'ES256' } }}
224
+ >
225
+ <Component {...pageProps} />
226
+ </TideCloakProvider>
227
+ );
228
+ }
229
+ ```
230
+
231
+ ---
232
+
233
+ ### Step 5: Create Silent SSO File
234
+
235
+ **Required for silent token refresh** (VERIFIED):
236
+ ```bash
237
+ # Create public/silent-check-sso.html
238
+ mkdir -p public
239
+ cat > public/silent-check-sso.html << 'EOF'
240
+ <html>
241
+ <body>
242
+ <script>
243
+ parent.postMessage(location.href, location.origin);
244
+ </script>
245
+ </body>
246
+ </html>
247
+ EOF
248
+ ```
249
+
250
+ **Why required**: OIDC silent refresh uses hidden iframe. TideCloak redirects to this file during refresh. Without it, silent refresh fails and users are forced to re-login. See [canon/invariants.md I-07](../canon/invariants.md#i-07-silent-sso-file-required).
251
+
252
+ ---
253
+
254
+ ### Step 6: Create Post-Auth Redirect Handler
255
+
256
+ **Required for login completion** (I-16). After authentication at TideCloak, the browser redirects back to the app at the configured `redirectUri`. A real page must exist at that path. See [canon/redirect-handler.md](../canon/redirect-handler.md).
257
+
258
+ **App Router** — create `app/auth/redirect/page.tsx`:
259
+ ```typescript
260
+ // app/auth/redirect/page.tsx
261
+ "use client";
262
+
263
+ import { useAuthCallback } from "@tidecloak/nextjs";
264
+ import { useEffect, useState } from "react";
265
+
266
+ // Separated so useAuthCallback only runs after hydration (avoids SSR window error).
267
+ function RedirectHandler() {
268
+ const { isProcessing, isSuccess, error } = useAuthCallback({
269
+ onSuccess: (returnUrl) => {
270
+ window.location.assign(returnUrl || "/");
271
+ },
272
+ onError: () => {
273
+ window.location.assign("/");
274
+ },
275
+ onMissingVerifierRedirectTo: "/",
276
+ });
277
+
278
+ useEffect(() => {
279
+ const params = new URLSearchParams(window.location.search);
280
+ if (!params.has("code") && !params.has("error")) {
281
+ window.location.assign("/");
282
+ }
283
+ }, []);
284
+
285
+ if (error) return <p>Authentication failed: {error.message}</p>;
286
+ if (isProcessing || !isSuccess) return <p>Completing login...</p>;
287
+ return <p>Redirecting...</p>;
288
+ }
289
+
290
+ export default function AuthRedirectPage() {
291
+ const [mounted, setMounted] = useState(false);
292
+ useEffect(() => setMounted(true), []);
293
+ if (!mounted) return <p>Loading...</p>;
294
+ return <RedirectHandler />;
295
+ }
296
+ ```
297
+
298
+ The `useAuthCallback` hook processes the OIDC callback (code exchange) and calls `onSuccess` with the `returnUrl`. On error or missing PKCE verifier (page refresh during login), it redirects back to home.
299
+
300
+ **Do not** use a bare placeholder page with no callback handling. The page must actively process the callback and redirect.
301
+
302
+ **Pages Router** — create `pages/auth/redirect.tsx` (same pattern, adapted for Pages Router).
303
+
304
+ **Also update TideCloak client settings**:
305
+ - TideCloak Admin → Clients → {client} → Settings
306
+ - Valid Redirect URIs: add `http://localhost:3000/auth/redirect`
307
+
308
+ **Failure if missing**: Login completes at TideCloak but the user lands on a 404. The SDK never processes the auth code. See [canon/redirect-handler.md](../canon/redirect-handler.md) for diagnostics.
309
+
310
+ ---
311
+
312
+ ### Step 7: Configure CSP for SWE Iframe
313
+
314
+ **Required**: The SWE (Secure Web Enclave) iframe must be allowed to load from any Tide ORK host because users can re-home their sessions to their preferred ORK. By Tide's security design, while a platform vendor may designate a home ORK, users can override this choice and switch to any ORK they trust.
315
+
316
+ **For development**, use a permissive CSP:
317
+
318
+ Edit `next.config.js`:
319
+ ```javascript
320
+ // next.config.js
321
+ /** @type {import('next').NextConfig} */
322
+ const nextConfig = {
323
+ async headers() {
324
+ return [
325
+ {
326
+ source: '/:path*',
327
+ headers: [
328
+ {
329
+ key: 'Content-Security-Policy',
330
+ value: "frame-src 'self' *"
331
+ }
332
+ ]
333
+ }
334
+ ];
335
+ }
336
+ };
337
+
338
+ module.exports = nextConfig;
339
+ ```
340
+
341
+ **For production**, you may restrict to known Tide domains, but understand this limits user choice of ORK:
342
+ ```javascript
343
+ value: "frame-src 'self' https://*.tideprotocol.com https://*.dauth.me"
344
+ ```
345
+
346
+ **Failure symptom if missing**: Login hangs indefinitely. Browser console shows CSP violation: `Refused to frame 'https://...' because it violates the following Content Security Policy directive`. See [canon/troubleshooting.md T-01](../canon/troubleshooting.md#t-01-login-hangs-indefinitely).
347
+
348
+ ---
349
+
350
+ ### Step 8: Create Login Component
351
+
352
+ Create basic login UI:
353
+
354
+ **App Router** (`app/page.tsx`):
355
+ ```typescript
356
+ // app/page.tsx
357
+ 'use client';
358
+
359
+ import { useTideCloak } from '@tidecloak/nextjs';
360
+
361
+ export default function HomePage() {
362
+ const { authenticated, getValueFromIdToken, login, logout } = useTideCloak();
363
+
364
+ if (!authenticated) {
365
+ return (
366
+ <div>
367
+ <h1>Welcome</h1>
368
+ <button onClick={login}>Login with Tide</button>
369
+ </div>
370
+ );
371
+ }
372
+
373
+ return (
374
+ <div>
375
+ <h1>Welcome, {getValueFromIdToken("preferred_username")}</h1>
376
+ <button onClick={logout}>Logout</button>
377
+ </div>
378
+ );
379
+ }
380
+ ```
381
+
382
+ **Pages Router** (`pages/index.tsx`):
383
+ ```typescript
384
+ // pages/index.tsx
385
+ import { useTideCloak } from '@tidecloak/nextjs';
386
+
387
+ export default function HomePage() {
388
+ const { authenticated, getValueFromIdToken, login, logout } = useTideCloak();
389
+
390
+ if (!authenticated) {
391
+ return (
392
+ <div>
393
+ <h1>Welcome</h1>
394
+ <button onClick={login}>Login with Tide</button>
395
+ </div>
396
+ );
397
+ }
398
+
399
+ return (
400
+ <div>
401
+ <h1>Welcome, {getValueFromIdToken("preferred_username")}</h1>
402
+ <button onClick={logout}>Logout</button>
403
+ </div>
404
+ );
405
+ }
406
+ ```
407
+
408
+ ---
409
+
410
+ ### Step 9: Test Login Flow
411
+
412
+ ```bash
413
+ # Start dev server
414
+ npm run dev
415
+
416
+ # Open browser to http://localhost:3000
417
+ # Click "Login with Tide"
418
+ # Should redirect to TideCloak login page
419
+ # Enter credentials
420
+ # Should redirect back to app, showing "Welcome, {username}"
421
+ ```
422
+
423
+ ---
424
+
425
+ ## Verification Checklist
426
+
427
+ After completing all steps, verify:
428
+
429
+ ### Client-Side
430
+
431
+ - [ ] Login button visible when unauthenticated
432
+ - [ ] Click login redirects to TideCloak
433
+ - [ ] Enter credentials and submit
434
+ - [ ] Redirect back to app within 5-10 seconds
435
+ - [ ] User name displays correctly
436
+ - [ ] Logout button visible when authenticated
437
+ - [ ] Click logout clears session and shows login button again
438
+
439
+ ### Browser Console
440
+
441
+ - [ ] No CSP violations (`frame-src` errors)
442
+ - [ ] No 404 on `silent-check-sso.html`
443
+ - [ ] No 404 on redirect handler path (`/auth/redirect`)
444
+ - [ ] No CORS errors
445
+ - [ ] No "Failed to load resource" for Tide domains
446
+
447
+ ### Browser DevTools → Network
448
+
449
+ - [ ] Redirect to TideCloak `/auth` endpoint
450
+ - [ ] Redirect back to app with `code` parameter
451
+ - [ ] Token exchange request to TideCloak `/token` endpoint
452
+ - [ ] Requests to `*.tideprotocol.com` or `*.dauth.me` (SWE iframe)
453
+
454
+ ### Browser DevTools → Application → Local Storage
455
+
456
+ - [ ] Keys starting with `kc-` or `tc-` present after login
457
+ - [ ] JWT token stored (decode at jwt.io to verify claims)
458
+
459
+ ---
460
+
461
+ ## Common Failures
462
+
463
+ ### Login Hangs Indefinitely
464
+
465
+ **Symptom**: Redirect to TideCloak succeeds, but redirect back never completes. Spinner forever.
466
+
467
+ **Cause**: CSP blocks SWE iframe (most common).
468
+
469
+ **Fix**: Check browser console for CSP violation. Add Tide domains to CSP in `next.config.js` (Step 6).
470
+
471
+ **See**: [canon/troubleshooting.md T-01](../canon/troubleshooting.md#t-01-login-hangs-indefinitely)
472
+
473
+ ---
474
+
475
+ ### 404 on silent-check-sso.html
476
+
477
+ **Symptom**: Silent refresh fails after 10 minutes. User forced to re-login.
478
+
479
+ **Cause**: Missing `public/silent-check-sso.html`.
480
+
481
+ **Fix**: Create file (Step 5). Verify accessible at `http://localhost:3000/silent-check-sso.html`.
482
+
483
+ **See**: [canon/troubleshooting.md T-04](../canon/troubleshooting.md#t-04-silent-token-refresh-fails)
484
+
485
+ ---
486
+
487
+ ### "Cannot find module @tidecloak/nextjs"
488
+
489
+ **Symptom**: Import error on `TideCloakContextProvider`.
490
+
491
+ **Cause**: Package not installed or not on public npm registry.
492
+
493
+ **Fix**: Verify `npm install @tidecloak/nextjs` succeeds. Check `package.json` includes `@tidecloak/nextjs` in dependencies. Contact Tide team if package unavailable.
494
+
495
+ ---
496
+
497
+ ### Config Not Loading
498
+
499
+ **Symptom**: Provider fails to initialize, auth-server-url undefined.
500
+
501
+ **Cause**: `data/tidecloak.json` missing or not imported by provider.
502
+
503
+ **Fix**:
504
+ - Verify `data/tidecloak.json` exists: `test -f data/tidecloak.json`
505
+ - Verify `providers.tsx` imports it: `import tcConfig from '../../data/tidecloak.json'`
506
+ - Verify provider uses `config={tcConfig}`, not `NEXT_PUBLIC_TIDECLOAK_*` env vars
507
+ - Restart dev server (`npm run dev`)
508
+
509
+ ---
510
+
511
+ ### Redirect URI Mismatch
512
+
513
+ **Symptom**: TideCloak error: "Invalid redirect_uri".
514
+
515
+ **Cause**: Client in TideCloak not configured with app's redirect URI.
516
+
517
+ **Fix**:
518
+ 1. TideCloak Admin → Clients → {your-client} → Settings
519
+ 2. Add to "Valid Redirect URIs": `http://localhost:3000/*`
520
+ 3. Add to "Valid Post Logout Redirect URIs": `http://localhost:3000/*`
521
+ 4. Save
522
+
523
+ ---
524
+
525
+ ## Repair Path
526
+
527
+ If setup fails completely:
528
+
529
+ 1. **Clear state**:
530
+ ```bash
531
+ # Browser: DevTools → Application → Local Storage → Clear All
532
+ # Or visit: http://localhost:3000?reset=true (if implemented)
533
+ ```
534
+
535
+ 2. **Verify TideCloak is reachable**:
536
+ ```bash
537
+ curl ${TIDECLOAK_URL}/realms/${REALM}/.well-known/openid-configuration
538
+ # Should return JSON with auth endpoints
539
+ ```
540
+
541
+ 3. **Verify adapter JSON is valid**:
542
+ ```bash
543
+ node -e "console.log(require('./data/tidecloak.json'))"
544
+ # Should output valid JSON
545
+ ```
546
+
547
+ 4. **Check Next.js logs**:
548
+ ```bash
549
+ npm run dev
550
+ # Watch for errors during startup
551
+ ```
552
+
553
+ 5. **Test in incognito**:
554
+ - Clear browser state may not be complete
555
+ - Incognito ensures fresh session
556
+
557
+ 6. **Consult troubleshooting**:
558
+ - [canon/troubleshooting.md](../canon/troubleshooting.md)
559
+ - [canon/anti-patterns.md](../canon/anti-patterns.md)
560
+
561
+ ---
562
+
563
+ ## Do Not Do This
564
+
565
+ ### ❌ Scaffold Command (Alternative)
566
+
567
+ ```bash
568
+ # Alternative: Automated scaffold
569
+ npm init @tidecloak/nextjs@latest <myApp>
570
+ ```
571
+
572
+ **About**: The scaffold command automates realm creation, IGA setup, client configuration, and adapter export. It prompts for TideCloak URL, realm name, client name, admin credentials, and operator email for license activation. The process creates a complete Next.js app with Tide auth pre-configured.
573
+
574
+ **Why manual setup is preferred here**: Manual setup is more inspectable and educational. Scaffold is useful for quick starts but obscures the individual configuration steps. Choose based on your learning goals.
575
+
576
+ ---
577
+
578
+ ### ❌ Do Not Skip CSP Configuration
579
+
580
+ ```javascript
581
+ // ❌ WRONG: No CSP or missing Tide domains
582
+ // SWE iframe will be blocked
583
+ ```
584
+
585
+ **Why**: Browser blocks cross-origin iframes by default. SWE cannot load without CSP whitelist. Login hangs forever with no visible error. See [canon/anti-patterns.md AP-07](../canon/anti-patterns.md#ap-07-missing-csp-whitelist).
586
+
587
+ ---
588
+
589
+ ### ❌ Do Not Skip silent-check-sso.html
590
+
591
+ ```bash
592
+ # ❌ WRONG: Missing silent SSO file
593
+ # Silent refresh will fail
594
+ ```
595
+
596
+ **Why**: Silent token refresh requires this file. Without it, users forced to re-login every 10 minutes (or token expiration). See [canon/anti-patterns.md AP-15](../canon/anti-patterns.md#ap-15-skipping-silent-check-ssohtml).
597
+
598
+ ---
599
+
600
+ ### ❌ Do Not Store Secrets in Client-Side Env Vars
601
+
602
+ ```bash
603
+ # ❌ WRONG: Client secret in NEXT_PUBLIC_ var
604
+ NEXT_PUBLIC_CLIENT_SECRET=secret123
605
+ ```
606
+
607
+ **Why**: `NEXT_PUBLIC_` vars are bundled into client JavaScript. Visible to all users. Tide uses public clients (no client secret). If you have a confidential client, use server-side env vars only.
608
+
609
+ ---
610
+
611
+ ### ❌ Do Not Implement Custom Login Flow
612
+
613
+ ```typescript
614
+ // ❌ WRONG: Custom password submission
615
+ async function handleLogin(username: string, password: string) {
616
+ const response = await fetch(`${tidecloakUrl}/token`, {
617
+ method: 'POST',
618
+ body: new URLSearchParams({ username, password, grant_type: 'password' })
619
+ });
620
+ }
621
+ ```
622
+
623
+ **Why**: Tide authentication is threshold-verified (PRISM). Custom password flows bypass threshold enforcement. Use SDK's `login()` method. See [canon/anti-patterns.md AP-14](../canon/anti-patterns.md#ap-14-implementing-custom-token-refresh-logic).
624
+
625
+ ---
626
+
627
+ ## Known Uncertainties
628
+
629
+ ### Required `_tide_*` Role
630
+
631
+ Each user must have at least one role starting with `_tide_` (e.g., `_tide_enabled`) for Tide operations to work. This is required for the vendor to fund Tide operations through the voucher system. Users without a `_tide_*` role will have their Tide requests rejected because no voucher will be assigned.
632
+
633
+ **Setup**: Ensure your realm's default roles include at least one `_tide_*` role, or assign such roles manually to users.
634
+
635
+ ---
636
+
637
+ ## Next Steps
638
+
639
+ After login works, follow this sequence:
640
+
641
+ 1. [Protect routes](protect-routes-nextjs.md) - Client-side route guards (UI gating only)
642
+ 2. [Protect APIs](protect-api-nextjs.md) - Server-side JWT verification (real authorization). **Required before RBAC.**
643
+ 3. [Add RBAC](add-rbac-nextjs.md) - Role-based access control (depends on API protection)
644
+
645
+ ---
646
+
647
+ ## References
648
+
649
+ - [canon/concepts.md](../canon/concepts.md) - Tide core concepts
650
+ - [canon/framework-matrix.md](../canon/framework-matrix.md) - Next.js implementation patterns
651
+ - [canon/invariants.md](../canon/invariants.md) - Security rules (I-06, I-07)
652
+ - [canon/anti-patterns.md](../canon/anti-patterns.md) - Common mistakes (AP-07, AP-14, AP-15)
653
+ - [canon/troubleshooting.md](../canon/troubleshooting.md) - Symptom-led debugging (T-01, T-04)
654
+ - keylessh exemplar: `sources/example-app-keylessh/` (DC-04, DC-09)