This document details how client-side applications connect with Zero IDS securely using standard protocols. Because browser apps cannot maintain credentials (secrets) securely, they operate as Public Clients and require PKCE (Proof Key for Code Exchange) to verify identity.
The standard react-oidc-context library (powered by oidc-client-ts) is recommended. Install the dependency first:
npm install react-oidc-context oidc-client-ts
Wrap your application root and initialize the provider properties:
import React from "react";
import ReactDOM from "react-dom/client";
import { AuthProvider, useAuth } from "react-oidc-context";
// Configuration for Zero IDS
const oidcConfig = {
authority: "http://localhost:3000/oidc",
client_id: "your-react-spa-client-id",
redirect_uri: window.location.origin + "/callback",
post_logout_redirect_uri: window.location.origin,
response_type: "code", // Forces Authorization Code with PKCE Flow
scope: "openid profile email offline_access", // offline_access requests refresh tokens
automaticSilentRenew: true, // Auto-refreshes tokens before expiration
loadUserInfo: true, // Fetch profile details immediately after callback exchange
onSigninCallback: (_user) => {
// Clear authorization code parameters from route query parameters
window.history.replaceState({}, document.title, window.location.pathname);
}
};
function AppContent() {
const auth = useAuth();
// Handling authentication state transitions
if (auth.isLoading) {
return <div style={{ color: "white", padding: "2rem" }}>Verifying OIDC Session...</div>;
}
if (auth.error) {
return (
<div style={{ color: "#ef4444", padding: "2rem" }}>
<h3>Authentication Error</h3>
<p>{auth.error.message}</p>
<button onClick={() => auth.signinRedirect()}>Retry Login</button>
</div>
);
}
if (auth.isAuthenticated) {
return (
<div style={{ color: "white", padding: "2rem" }}>
<h2>Welcome, {auth.user?.profile.name || auth.user?.profile.email}</h2>
<p>Email Address: {auth.user?.profile.email}</p>
<p>Organization UUID: {auth.user?.profile.org_id}</p>
<h4>Access Token Payload Details:</h4>
<pre style={{ background: "rgba(0,0,0,0.3)", padding: "1rem", borderRadius: "8px" }}>
{JSON.stringify(auth.user?.profile, null, 2)}
</pre>
<div style={{ display: "flex", gap: "1rem", marginTop: "2rem" }}>
<button onClick={() => auth.signoutRedirect()}>Log Out (OIDC Session)</button>
<button onClick={() => auth.removeUser()}>Clear Client Storage</button>
</div>
</div>
);
}
return (
<div style={{ color: "white", padding: "2rem", textAlign: "center" }}>
<h2>Secure SPA Authentication</h2>
<p>Protect routes and views using Zero IDS identity services.</p>
<button
style={{ padding: "12px 24px", background: "#a5b4fc", color: "#1e1b4b", border: "none", borderRadius: "8px", fontWeight: "bold", cursor: "pointer" }}
onClick={() => auth.signinRedirect()}
>
Authenticate via Zero IDS
</button>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<AuthProvider {...oidcConfig}>
<AppContent />
</AuthProvider>
</React.StrictMode>
);
Since the SPA makes a direct API POST request from the browser to the /oidc/token endpoint during PKCE authorization code exchange, you **MUST** authorize the SPA origin in the Zero IDS Admin Console:
http://localhost:5173) to the client's Web Origins / CORS whitelist.
By default, oidc-client-ts stores tokens in sessionStorage. For enhanced security against Cross-Site Scripting (XSS):