How‑to Guide: Common Tasks with TideCloak in React
Copy‑paste snippets for the tasks you'll use most in a React SPA.
Install or scaffold
New React + Vite app (TypeScript):
npm create vite@latest my-app -- --template react-tscd my-appnpm install @tidecloak/react
Required file for silent SSO ``
<html><body><script>parent.postMessage(location.href, location.origin)</script></body></html>
Initialize the Provider (React Router)
import React from 'react';import ReactDOM from 'react-dom/client';import { BrowserRouter, Routes, Route } from 'react-router-dom';import { TideCloakContextProvider } from '@tidecloak/react';import adapter from '../tidecloakAdapter.json';import Home from './pages/Home';import RedirectPage from './pages/auth/RedirectPage';import Dashboard from './pages/Dashboard';ReactDOM.createRoot(document.getElementById('root')!).render(<React.StrictMode><TideCloakContextProvider config={adapter}><BrowserRouter><Routes><Route path="/" element={<Home />} /><Route path="/auth/redirect" element={<RedirectPage />} /><Route path="/dashboard" element={<Dashboard />} /></Routes></BrowserRouter></TideCloakContextProvider></React.StrictMode>);
Customize redirect URI
Default (if omitted):
${window.location.origin}/auth/redirect
Override it:
<TideCloakContextProvider config={{ ...adapter, redirectUri: 'https://yourapp.com/auth/callback' }}>{/* app */}</TideCloakContextProvider>
Ensure the target route exists in your router.
Example redirect handler
import { useEffect } from 'react';import { useNavigate } from 'react-router-dom';import { useTideCloak } from '@tidecloak/react';export default function RedirectPage() {const { authenticated, isInitializing, logout } = useTideCloak();const navigate = useNavigate();useEffect(() => {const params = new URLSearchParams(window.location.search);if (params.get('auth') === 'failed') {sessionStorage.setItem('tokenExpired', 'true');logout();}}, []);useEffect(() => {if (!isInitializing) navigate(authenticated ? '/dashboard' : '/');}, [authenticated, isInitializing, navigate]);return (<div style={{ minHeight:'100vh', display:'flex', alignItems:'center', justifyContent:'center' }}><p>Waiting for authentication...</p></div>);}
Read token claims
import { useTideCloak } from '@tidecloak/react';const { getValueFromToken, getValueFromIdToken } = useTideCloak();const email = getValueFromToken('email');const username = getValueFromIdToken('preferred_username');
Check roles
import { useTideCloak } from '@tidecloak/react';const { hasRealmRole, hasClientRole } = useTideCloak();const isAdmin = hasRealmRole('admin');const isEditor = hasClientRole('editor'); // defaults to your app clientconst isBillingOnBackoffice = hasClientRole('billing:writer', 'backoffice-client');
Manually refresh token
import { useTideCloak } from '@tidecloak/react';const { refreshToken } = useTideCloak();const ok = await refreshToken();console.log(ok ? 'Token refreshed!' : 'Refresh failed.');
(Tokens also refresh automatically as they expire.)
Encrypt data before sending
import { useTideCloak } from '@tidecloak/react';const { doEncrypt } = useTideCloak();const encrypted = await doEncrypt([{ data: 'Sensitive Information', tags: ['private'] },]);
Data type:
datamust be string or Uint8Array. Permissions: require_tide_<tag>.selfencrypton the access token.
Decrypt received data
import { useTideCloak } from '@tidecloak/react';const { doDecrypt } = useTideCloak();const decrypted = await doDecrypt([{ encrypted: receivedEncryptedData, tags: ['private'] },]);
Permissions: require
_tide_<tag>.selfdecrypt. Order guarantee: output preserves input order.
Route guards and gated UI
Simple gated UI:
import { Authenticated, Unauthenticated } from '@tidecloak/react';export function Header() {return (<><Authenticated><button>Sign out</button></Authenticated><Unauthenticated><button>Sign in</button></Unauthenticated></>);}
Lightweight route guard:
import { useTideCloak } from '@tidecloak/react';import { Navigate } from 'react-router-dom';export function RequireAuth({ children }: { children: JSX.Element }) {const { authenticated, isInitializing } = useTideCloak();if (isInitializing) return null;return authenticated ? children : <Navigate to="/" replace />;}
Use it:
<Route path="/dashboard" element={<RequireAuth><Dashboard/></RequireAuth>} />
Verify tokens on the backend (Node Express)
import express from 'express';import type { Request, Response, NextFunction } from 'express';import { verifyTideCloakToken } from '@tidecloak/react/server';import adapter from '../tidecloakAdapter.json';const app = express();async function auth(requiredRoles: string[] = []) {return async (req: Request, res: Response, next: NextFunction) => {const authz = req.headers.authorization || '';const token = authz.startsWith('Bearer ') ? authz.slice(7) : '';const payload = await verifyTideCloakToken(adapter, token, requiredRoles);if (!payload) return res.status(401).json({ error: 'Unauthorized' });(req as any).user = payload;next();};}app.get('/api/secure', await auth(['user']), (req, res) => {res.json({ data: 'Secure data response' });});app.listen(3001, () => console.log('API on :3001'));
Handle auth errors
import { useEffect } from 'react';import { useTideCloak } from '@tidecloak/react';export function AuthErrorToast() {const { initError } = useTideCloak();useEffect(() => {if (initError) {console.error('Authentication error:', initError);alert('Authentication failed. Please log in again.');}}, [initError]);return null;}
Quick checklist
-
public/silent-check-sso.htmlexists -
<TideCloakContextProvider config={adapter}>wraps your app - Redirect route exists (default
/auth/redirector your customredirectUri) - Roles are created and assigned in TideCloak
- Backend verifies tokens before serving secure data