← Back to Blog

Integrating Zero IDS with Single Page Applications (SPAs)

Deploying secure authentication in browser-rendered clients (React, Vue, Angular) with PKCE and state management

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.

React Integration Framework

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

Comprehensive React Setup Example

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>
);

Production Configuration & Security Best Practices

1. CORS and Origin Registration

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:

  • Add the exact origin (e.g. http://localhost:5173) to the client's Web Origins / CORS whitelist.
  • Register the exact callback URL under Allowed Redirect URIs.

2. Token Storage and XSS Mitigation

By default, oidc-client-ts stores tokens in sessionStorage. For enhanced security against Cross-Site Scripting (XSS):

  • Prefer keeping the Access Token in-memory (inside React context memory) and use silent refreshes via hidden iframes.
  • Ensure your app utilizes CSP (Content Security Policy) headers to limit script execution sources.

OIDC Series Guides