Thoryn

Quickstarts · react-spa

React SPA — Hub login with `oidc-client-ts`

Wire OAuth2 / OIDC into a React 19 + Vite SPA using the standard browser library. Auth code with PKCE, no client secret.

Tested against:framework: React 19 + Vite 5oidcClient: oidc-client-ts@3.0.0

React SPA + Thoryn quickstart architecture — oidc-client-ts uses PKCE so no client secret leaves the browser; Hub federates to your IdP; access token returns to the SPA

Prereqs

  • React 19 + Vite 5 (or Create-React-App, less recommended)
  • A Thoryn account

Step 1 — Register a SPA client in Hub

SPAs use auth-code + PKCE — no client secret. Register accordingly:

hub clients create \
  --name "My React SPA" \
  --redirect-uri "http://localhost:5173/callback" \
  --grant-types authorization_code,refresh_token \
  --client-type public \
  --pkce required \
  --scopes "openid email profile"

Step 2 — Install

npm install oidc-client-ts

Step 3 — Configure

src/auth.ts:

import { UserManager, WebStorageStateStore } from "oidc-client-ts";
 
export const userManager = new UserManager({
  authority: "https://hub.thoryn.org",
  client_id: import.meta.env.VITE_THORYN_CLIENT_ID,
  redirect_uri: window.location.origin + "/callback",
  scope: "openid email profile",
  response_type: "code",
  userStore: new WebStorageStateStore({ store: window.localStorage }),
});

Step 4 — Wire login + callback

src/App.tsx:

import { useEffect, useState } from "react";
import { userManager } from "./auth";
 
export default function App() {
  const [user, setUser] = useState(null);
 
  useEffect(() => {
    if (window.location.pathname === "/callback") {
      userManager.signinRedirectCallback().then((u) => {
        setUser(u);
        window.history.replaceState({}, "", "/");
      });
    } else {
      userManager.getUser().then(setUser);
    }
  }, []);
 
  if (!user) {
    return <button onClick={() => userManager.signinRedirect()}>Sign in</button>;
  }
  return (
    <div>
      <p>Hello, {user.profile.name}</p>
      <button onClick={() => userManager.signoutRedirect()}>Sign out</button>
    </div>
  );
}

Step 5 — Run it

VITE_THORYN_CLIENT_ID=... npm run dev

http://localhost:5173, click sign in, get redirected to Hub, come back logged in.

What's next

Troubleshooting

  • PKCE missing: oidc-client-ts enables PKCE by default. If your Hub registration requires it (it should), this is automatic.
  • localStorage tokens are XSS-exposed: that's the SPA trade-off. For sensitive data, use a back-end-for-frontend instead.