What This Is

Stuck? Reach out on Discord. We’ll help you debug it.

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.

Dive In

Ready to integrate? Start here.

Getting Started

Positioning

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.

Is it a good fit for my stack?

It depends. oidc-spa is strong for client-side OIDC. But client-side OIDC isn’t the right model for every app.

When NOT to use oidc-spa

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.

When you should use it

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.

Last updated

Was this helpful?