React
Many SPAs use a framework such as React to simplify the creation of interactive experiences. We suggest the open source react-oidc-context library, built on oidc-client-ts, to make securing React applications easier. It logs users in with the authorization code flow and PKCE, keeps the tokens in session storage and refreshes them before they expire.
Example
Phase Two has a React project with sample code or view a live deployed version. The React tutorial walks through it step by step.
The app needs a public OpenID Connect client in Keycloak: client authentication off, the standard flow enabled with PKCE (S256), http://localhost:3000/* as valid redirect URI, and + as web origin and as valid post logout redirect URI. The local Keycloak of the examples repo already has one, reactjs-example.
Configure the app
The example reads the issuer URL and the client ID from environment variables. For the local Keycloak, start it from the root of the examples repo with docker compose -f keycloak/docker-compose.yml up -d --wait, and run cp .env.local.sample .env.local in the example folder. The file holds:
VITE_OIDC_ISSUER_URI=http://localhost:8080/auth/realms/p2examples
VITE_OIDC_CLIENT_ID=reactjs-example
For another Keycloak, set VITE_OIDC_ISSUER_URI to your realm's issuer URL, https://<your-keycloak-host>/auth/realms/<your-realm>, and VITE_OIDC_CLIENT_ID to the ID of your client.
Then run pnpm install and pnpm dev, and open localhost:3000. On the local Keycloak, log in as demo / demo.
Set up the AuthProvider
Install the libraries:
pnpm add react-oidc-context oidc-client-ts
Then wrap the app in an AuthProvider. In src/main.tsx:
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { AuthProvider, type AuthProviderProps } from "react-oidc-context";
import App from "./App.tsx";
import "./index.css";
const oidcConfig: AuthProviderProps = {
authority: import.meta.env.VITE_OIDC_ISSUER_URI,
client_id: import.meta.env.VITE_OIDC_CLIENT_ID,
redirect_uri: `${window.location.origin}/`,
post_logout_redirect_uri: `${window.location.origin}/`,
scope: "openid profile email",
onSigninCallback: () => {
window.history.replaceState({}, document.title, window.location.pathname);
},
};
createRoot(document.getElementById("root")!).render(
<StrictMode>
<AuthProvider {...oidcConfig}>
<App />
</AuthProvider>
</StrictMode>,
);
Use the hook
When a component requires access to the login state, use the useAuth hook. The example's src/Auth.tsx calls it and renders the page from what it returns:
auth.isLoadingistruewhile the library loads the user, andauth.errorholds an authentication error;auth.isAuthenticatedtells whether the user is logged in, andauth.user?.profileholds the claims of the ID token, such asnameandemail;auth.signinRedirect()sends the user to the Keycloak login page, andauth.signoutRedirect()logs them out of the app and of Keycloak.
The react-oidc-context documentation describes the hook and how to protect routes.
oidc-spa
Phase Two also has an oidc-spa example, with a live deployed version. oidc-spa is the library Phase Two uses in its own dashboards. Its Vite plugin starts it before the app loads and hardens the page against token theft. The oidc-spa tutorial builds the example step by step.