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:3000and 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.jsexchanges the auth code for tokens and redirects for backend validation.middleware.jsverifies tokens/roles, then continues to the protected destination.protected.jsrenders for the authenticated, authorized user.
Automatic session restart (SSO)
- Home page loads.
- Hidden
silent-check-sso.htmlperforms a background SSO check. - If already signed in, TideCloak returns the code.
- App initializes tokens and redirects to validation.
middleware.jsre-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
verifyTideCloakTokenbefore 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/retrievewith the bearer token. - Backend verifies
_tide_dob.selfdecryptand 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
authenticatedstate 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
matchertoo broad/too narrow - be precise for public vs protected routes. - Missing
_tide_<tag>.selfencrypt/_tide_<tag>.selfdecryptroles for E2EE.