npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pawells/react-auth

v1.0.5

Published

Keycloak Authorization Code Flow with PKCE authentication for React SPAs

Readme

@pawells/react-auth

npm License

Keycloak OIDC authentication for React applications. Built on oidc-client-ts with Authorization Code + PKCE flow, automatic silent token renewal, popup login support, axios interceptor, and Apollo Client link.

Installation

yarn add @pawells/react-auth oidc-client-ts

Quick start

Wrap your application (inside your router) with AuthProvider and access auth state via useAuth.

import { AuthProvider, useAuth } from '@pawells/react-auth';

function AppWithAuth() {
	const navigate = useNavigate();

	return (
		<AuthProvider
			authority="https://keycloak.example.com/realms/my-realm"
			client_id="my-spa-client"
			redirect_uri={`${window.location.origin}/auth/callback`}
			post_logout_redirect_uri={window.location.origin}
			onSigninCallback={() => navigate('/')}
		>
			<App />
		</AuthProvider>
	);
}

function NavBar() {
	const { isAuthenticated, isLoading, user, login, logout } = useAuth();

	if (isLoading) return <Spinner />;
	if (!isAuthenticated) return <button onClick={login}>Sign in</button>;
	return (
		<>
			<span>{user?.profile.name}</span>
			<button onClick={logout}>Sign out</button>
		</>
	);
}

API reference

AuthProvider

Provider component that supplies Keycloak OIDC authentication to the component tree. Place it inside your router so onSigninCallback can call useNavigate.

| Prop | Type | Required | Description | |---|---|---|---| | authority | string | Yes | Keycloak realm base URL, e.g. https://host/realms/my-realm | | client_id | string | Yes | Public (non-confidential) Keycloak client ID | | redirect_uri | string | Yes | URI to redirect to after login — must be registered in Keycloak | | post_logout_redirect_uri | string | No | URI to redirect to after logout | | popup_redirect_uri | string | No | URI for popup login callback — enables loginWithPopup() | | scope | string | No | OAuth2 scopes. Defaults to 'openid profile email' | | storageType | 'sessionStorage' \| 'localStorage' | No | Token storage strategy. Defaults to 'sessionStorage' | | onSigninCallback | (user: User) => void | No | Called after a successful signin redirect callback |

All other UserManagerSettings from oidc-client-ts are accepted and forwarded.

useAuth

Returns the AuthContextValue from the nearest AuthProvider. Throws if called outside a provider.

const {
	isAuthenticated,   // boolean — true when user has a valid, non-expired token
	isLoading,         // boolean — true during initial hydration, callback processing, or silent renew
	user,              // User | null — the OIDC user object
	error,             // Error | null — most recent auth error
	login,             // () => Promise<void> — initiates redirect login
	loginWithPopup,    // () => Promise<void> — opens a popup login window
	logout,            // () => Promise<void> — redirects to Keycloak logout
	getAccessToken,    // () => Promise<string | null> — returns a valid token, renewing silently if needed
	clearSession,      // () => Promise<void> — removes the user from storage without redirecting
} = useAuth();

useAuthAxios

Returns an Axios instance with a request interceptor that automatically attaches a valid Bearer token to every outgoing request. Silent token renewal is triggered transparently when the current token is expired.

import { useAuthAxios } from '@pawells/react-auth';

function DataService() {
	const api = useAuthAxios(); // new axios instance
	const fetchItems = () => api.get('/api/items');
}

Pass an existing Axios instance to attach the interceptor to it instead:

const sharedAxios = axios.create({ baseURL: 'https://api.example.com' });

function DataService() {
	const api = useAuthAxios(sharedAxios);
}

Note: if multiple components call useAuthAxios with the same shared instance, multiple interceptors will be registered. Use a dedicated instance per hook invocation to avoid this.

createAuthApolloLink

Creates an Apollo Client ApolloLink that prepends a valid Bearer token to the Authorization header of every GraphQL operation. Silent token renewal is triggered transparently.

import { createAuthApolloLink, useAuth } from '@pawells/react-auth';
import { ApolloClient, ApolloProvider, HttpLink, InMemoryCache } from '@apollo/client';

function ApolloSetup({ children }: { children: React.ReactNode }) {
	const { getAccessToken } = useAuth();

	const client = useMemo(() => {
		const authLink = createAuthApolloLink(getAccessToken);
		const httpLink = new HttpLink({ uri: '/graphql' });
		return new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache() });
	}, [getAccessToken]);

	return <ApolloProvider client={client}>{children}</ApolloProvider>;
}

KeycloakAuthConfig

Full configuration interface accepted by AuthProvider (all props listed in the AuthProvider table above, plus any UserManagerSettings fields).

Token utilities

import { parseJwt, isTokenExpired } from '@pawells/react-auth';

// Decode a JWT payload without signature verification (client-side use only)
const payload = parseJwt<{ sub: string; email: string }>(token);

// Check if a JWT is expired (clockSkewSeconds adds a grace window)
const expired = isTokenExpired(token, 30); // true if expired more than 30s ago

Notes

  • PKCE (S256) is enabled by default via oidc-client-ts — no additional configuration is required.
  • Silent token renewal via refresh token is enabled automatically. The getAccessToken method and useAuthAxios interceptor both renew tokens transparently.
  • storageType is only read on initial render. Changes to this prop after mount are ignored because the UserManager instance is created once and retains its original storage.
  • React Strict Mode safe — AuthProvider guards against double-invocation of the signin redirect callback in development.
  • Popup login requires popup_redirect_uri to be configured on AuthProvider and registered in Keycloak's "Valid redirect URIs". If the popup is blocked by the browser, loginWithPopup() throws — callers should catch and fall back to login() if desired.