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-ts
cd my-app
npm 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 client
const 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;
}
Local TideCloak (dev)
If you don't have a server yet, start the dev container which auto‑imports a sample realm:
sudo docker run -d -v .:/opt/keycloak/data/h2 -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=password --name tidecloak tideorg/tidecloak-dev:latest
Activate a license (dev/free)
Go to your realm's Tide IdP Settings → Manage License → Request License and finish the flow.
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