How-to Guide: Common Tasks with TideCloak in Vanilla JS
Quick, copy-paste snippets for everyday tasks using @tidecloak/js.
Install
npm install @tidecloak/js
Ensure public/silent-check-sso.html exists (see tutorial) and place your adapter at ./tidecloak.json.
Initialize IAM
import { IAMService } from "@tidecloak/js";import config from "./tidecloak.json";await IAMService.initIAM(config);// or override redirect:await IAMService.initIAM({ ...config, redirectUri: "https://your.app/auth/callback" });
Default redirect:
${window.location.origin}/auth/redirect→ ensure that path exists.
DPoP (opt-in)
DPoP binds the access token to a key held by this browser, so a copied token stops working. It is off unless you ask for it:
await IAMService.initIAM({ ...config, useDPoP: { mode: "strict" } });
Turning it on changes the token. The realm issues one with typ: "DPoP" and cnf.jkt, and that token is rejected with a bare 401 if it is later sent as a plain Authorization: Bearer .... Use IAMService.secureFetch, which attaches the proof for you, and make sure your resource server validates it.
Your app also has to serve the DPoP verification page, which is how TideCloak confirms the browser holds the key. It has to come from your origin, because the key lives in your app's IndexedDB and nothing on another origin can read it.
The setup is the same as for React: fetch the page into public/, then serve it from a small Vite middleware in dev and from your host's header config in production. See serve the DPoP verification page for both, and DPoP and sender-constrained tokens for what the page actually does.
If the page is missing, logins still work but stall for about four seconds and fall back to a popup. That stall is the usual sign this is not set up.
Login / Logout
IAMService.doLogin(); // redirect to SSOIAMService.doLogout(); // clear and redirect
Tokens & Claims
const isLogged = IAMService.isLoggedIn(); // booleanconst token = await IAMService.getToken(); // access token (string)const idToken = IAMService.getIDToken(); // ID token (string)const exp = IAMService.getTokenExp(); // seconds since epochconst username = IAMService.getName(); // preferred_usernameconst email = IAMService.getValueFromToken("email");const sub = IAMService.getValueFromIDToken("sub");
Role Checks
IAMService.hasRealmRole("admin"); // booleanIAMService.hasClientRole("editor"); // boolean (defaults to your app client)
Token Refresh
await IAMService.updateIAMToken(); // try to refresh if neededawait IAMService.forceUpdateToken(); // force refresh attempt
Events
const onReady = (auth) => console.log("Ready, logged in:", auth);IAMService.on("ready", onReady);// Later (SPA cleanup):IAMService.off("ready", onReady);
Common events:
| Event | When it fires |
|---|---|
ready | Initial silent SSO finished (true/false) |
authSuccess | Interactive login success |
authError | Interactive login failed |
authRefreshSuccess | Silent token refresh succeeded |
authRefreshError | Silent token refresh failed |
logout | User logged out |
tokenExpired | Token expired before refresh |
Encrypt / Decrypt (E2EE)
Requires roles per tag:
_tide_<tag>.selfencrypt/_tide_<tag>.selfdecrypt
// Encrypt string values:const [encDob] = await IAMService.doEncrypt([{ data: "2005-03-04", tags: ["dob"] }]);// Decrypt back:const [dob] = await IAMService.doDecrypt([{ encrypted: encDob, tags: ["dob"] }]);// Multi-field example:const encrypted = await IAMService.doEncrypt([{ data: "10 Smith Street", tags: ["street"] },{ data: "Southport", tags: ["suburb"] },{ data: "20 James Street - Burleigh Heads", tags: ["street", "suburb"] }]);const decrypted = await IAMService.doDecrypt([{ encrypted: encrypted[0], tags: ["street"] },{ encrypted: encrypted[1], tags: ["suburb"] },{ encrypted: encrypted[2], tags: ["street", "suburb"] }]);
datamust be string or Uint8Array. Output order matches input order.
Protecting Backend APIs
Send the access token as a bearer:
const token = await IAMService.getToken();const res = await fetch("/api/secure", {headers: { Authorization: `Bearer ${token}` }});
Verify the JWT in your backend (Node, Go, etc.) using your realm's JWKS.