Discussion: Understanding TideCloak Authentication in Next.js
Conceptual insights, best practices, and deep-dive flows (with SVG diagrams) for TideCloak authentication in Next.js.
π§ How it works (deep dive)β
Below are the end-to-end flows summarized from the sample repo and READMEs.
Example project structure (sample repo)β
tidecloak-client-nextJS/
βββ public/
β βββ silent-check-sso.html
βββ lib/
β βββ db.js
β βββ IAMService.js
β βββ tideJWT.js
βββ pages/
β βββ index.js
β βββ fail.js
β βββ protected.js
β βββ api/
β | βββ retrieve.js
β | βββ store.js
β β βββ endpoint.js
β βββ auth/
β βββ redirect.js
βββ middleware.js
βββ keycloak.json
βββ keys.json
βββ package.json
Normal authorized accessβ
- User visits
http://localhost:3000
and clicks Login. - The app initializes a TideCloak session and redirects to TideCloak.
- TideCloak redirects the user to Tide (IdP).
- User completes sign-up/sign-in in Tideβs secure enclave.
- Tide issues tokens (with anonymity and role context).
redirect.js
exchanges the auth code for tokens and redirects for backend validation.middleware.js
verifies tokens/roles, then continues to the protected destination.protected.js
renders for the authenticated, authorized user.
Automatic session restart (SSO)β
- Home page loads.
- Hidden
silent-check-sso.html
performs a background SSO check. - If already signed in, TideCloak returns the code.
- App initializes tokens and redirects to validation.
middleware.js
re-validates tokens/roles.- User lands on protected content without re-auth.
Unauthenticated attemptβ
- Failed authentication brings the user back to the home page (
index.js
).
Unauthorized attemptβ
- Authenticated but insufficient roles β redirect to
fail.js
(with sign-out option).
Authorized API accessβ
- From a protected page (e.g.,
protected.js
), API requests include the bearer token. - Backend verifies with
verifyTideCloakToken
before returning secure data.
Single-Sign-Outβ
- User-initiated SSO logout ends sessions across related clients.
Automated session refreshβ
- Background process keeps sessions alive with silent token refresh.
E2EE - Authorized decryptionβ
- Protected page loads a form (e.g.
dob.js
). - Frontend requests the encrypted DoB from
/api/retrieve
with the bearer token. - Backend verifies
_tide_dob.selfdecrypt
and fetches ciphertext (no server-held keys). - Encrypted field is returned to the browser.
- Browser invokes Tide Fabric nodes; each validates access and contributes a partial.
- Responses are combined client-side to decrypt only for the authorized user.
E2EE - Authorized encryptionβ
- User edits a protected field (e.g., DoB).
- Browser engages Fabric nodes; each validates access and contributes to encryption.
- The encrypted value is posted to the backend.
- Backend validates and stores ciphertext (no decryption key at rest).
π Why use TideCloak?β
TideCloak simplifies secure authentication by:
- Handling OAuth2/OIDC and JWT verification reliably (including Edge middleware).
- Providing built-in encryption/decryption helpers for sensitive fields (tag-based E2EE).
- Supporting role-based access control (RBAC) at realm and client levels.
- Integrating smoothly with both App Router and Pages Router in Next.js.
π§© When should you use Middleware vs Client-side Authentication?β
Middleware (Edge)β
Use middleware when you need:
- Global route protection (pages and APIs) before rendering.
- Immediate redirection for unauthenticated/unauthorized users.
- Centralized role checks per path pattern.
Client-sideβ
Use client-side auth when you need:
- Conditional rendering of components (e.g., login/logout buttons, protected widgets).
- UX logic that depends on
authenticated
state without hard blocking a route. - Quick reads from tokens (
getValueFromToken
,getValueFromIdToken
) for UI.
Best practice: Use both - middleware to harden routes, client-side to refine UI.
π οΈ Best practices for redirect URIsβ
- Ensure the redirect route exists in your app.
- Default is
"/auth/redirect"
if you donβt set one explicitly. - If you customize it in
<TideCloakProvider config={{ redirectUri }}>
, keep it consistent across environments to avoid broken flows.
π¦ How are roles managed in TideCloak?β
TideCloak roles live at two levels:
- Realm roles - global to the TideCloak realm (e.g.,
"admin"
). - Client roles - scoped to a specific client/app (e.g.,
"editor"
).
Theyβre embedded in JWTs and can be checked with:
hasRealmRole('admin')
hasClientRole('editor', 'myclient')
(client is optional; defaults to your app client)
π¨ Common Pitfallsβ
- Missing
"/auth/redirect"
page when relying on the default route. - Encrypting objects instead of strings/Uint8Array with
doEncrypt()
(will fail). - Middleware
matcher
too broad/too narrow - be precise for public vs protected routes. - Missing
_tide_<tag>.selfencrypt
/_tide_<tag>.selfdecrypt
roles for E2EE.