| icon | layout | metaLinks | |||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
lightbulb-exclamation-on |
|
{% hint style="info" %} Stuck? Reach out on Discord. We’ll help you debug it. {% endhint %}
oidc-spa is an OpenID Connect client for browser-first web apps. It implements the Authorization Code Flow with PKCE and supports DPoP. It also ships token validation utilities for JavaScript backends.
It includes security defenses to reduce token exposure risks in the browser.
It’s one dependency free library for the full stack. It can replace frontend SDKs like keycloak-js, MSAL.js, or @auth0/auth0-spa-js. It can also replace backend token tooling like jsonwebtoken, jose, or express-jwt.
Why we built it
Most OIDC client libraries handle the basic sign-in flow well. But they leave you to implement:
- Token renewal, and what happens on expiry.
- Idle timeout UX. Auto-logout and re-auth prompts.
- Login/logout sync across tabs.
- Reliable session restore on reload, including third‑party cookie blocks.
- Provider quirks. Keycloak, Entra ID, and Auth0 differ in practice.
We also wanted a TanStack-style developer experience:
- Types flowing from config into the runtime API.
- APIs that are hard to misuse.
- Mockable OIDC for tests and “no-auth” / degraded environments.
So we built oidc-spa. It’s opinionated and high-level. It has few knobs by design.
It gives you enterprise-grade auth out of the box. So you can focus on your app.
Ready to integrate? Start here.
{% content-ref url="integration-guides/example-setups.md" %} example-setups.md {% endcontent-ref %}
Here’s where oidc-spa sits compared to server-side OIDC:
| Browser-Side OIDC | Server-Side OIDC | |
|---|---|---|
| Implementation | oidc-spa, keycloak-js, angular-oauth2-oidc, react-oidc-context, @auth0/auth0-spa-js, @azure/msal-browser, @axa-fr/oidc-client, oidc-client-ts (without client secret) | nuxt-oidc-auth, oidc-client-ts (with client secret), NextAuth/Auth.js/BetterAuth (often “roll your own auth” frameworks that can broker OIDC providers) |
| OIDC Model | The frontend is the OIDC client. Your backend API is an OAuth resource server. The frontend calls the API with an access token. The API can validate the token signature and resolve identity offline. | The backend is the OIDC client. User identity is tracked with session cookies. In this model, there is usually no OAuth resource server. Access tokens are mainly used for calling third-party APIs. |
| Infrastructure Requirement | None. The browser talks directly to the authorization server. | Requires a stateful backend and a shared session store (e.g. Redis). |
| Setup | Simple. Auth is decoupled from your app framework, router, and API. | Tightly coupled to a framework. You typically build login/logout routes and middleware. |
| Security | Historically weaker because tokens exist in the browser. With DPoP and modern defenses, the security gap can shrink significantly. See details. | Secure by design. Tokens are not exposed to frontend code. |
| Server-side rendering | Limited. The server renders without user context. Auth-aware UI renders on the client. See in practice. | Seamless. The server knows who the user is during render. |
It depends. oidc-spa is strong for client-side OIDC. But client-side OIDC isn’t the right model for every app.
Avoid oidc-spa if you rely on SSR for auth-aware pages. This includes Next.js, Nuxt, SvelteKit, Remix/React Router Framework (non‑SPA mode), or Astro.
Those stacks push state and logic to the server. They also aim to ship minimal client JavaScript.
oidc-spa drives auth from the browser. That’s a mismatch for SSR-first architectures.
Use it for client-first apps. It works best when state and logic live in the browser.
Typically:
- Vite + React (or another UI framework) - SPAs
- TanStack Start (SSR works, but auth-aware UI renders client-side. See in practice)
- Angular applications
- Nuxt with
ssr: false - React Router Framework with
ssr: false
If you’re choosing between this and a BFF for security, start with the security features. With those defenses enabled, the security profile can be comparable to server-side OIDC.