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

@camall/react-auth

v1.10.18

Published

Camall authentication provider for react.

Readme

@camall/react-auth

OIDC/OAuth 2.0 authentication provider for React, built on the Authorization Code + PKCE flow. Handles login, logout, token storage, silent token refresh, and authenticated API requests.

Features

  • Authorization Code flow with PKCE (no client secret required in the browser)
  • Automatic token refresh with cross-tab lock to prevent duplicate refresh requests
  • Three storage backends: session, local, and memory
  • RequireAuth guard component that redirects unauthenticated users to the IDP
  • authFetch helper that automatically attaches Bearer tokens to requests
  • Full TypeScript support

Requirements

  • React 17, 18, or 19

Installation

npm install @camall/react-auth

Quick Start

import { AuthProvider, RequireAuth } from "@camall/react-auth";

const config = {
  issuer: "https://c00000.camall.io",
  clientId: "spa-client",
  redirectUri: window.location.origin + "/auth/callback",
  scopes: ["openid", "profile", "email", "offline_access"],
  storage: "session",
};

export function App() {
  return (
    <AuthProvider config={config}>
      <RequireAuth>
        <ProtectedRoutes />
      </RequireAuth>
    </AuthProvider>
  );
}

AuthProvider must wrap any component that calls useAuth or renders RequireAuth. On mount it inspects the current URL for an OAuth callback (?code=&state=), exchanges the code for tokens if present, and restores an existing session from storage otherwise.

Configuration Reference

Pass an AuthConfig object to <AuthProvider config={...}>.

| Property | Type | Default | Description | |---|---|---|---| | issuer | string | required | Base URL of the OIDC provider, e.g. https://idp.example.com/t123 | | clientId | string | required | OAuth client ID registered with the IDP | | redirectUri | string | required | Absolute URI the IDP redirects back to after login | | authorizeEndpoint | string | {issuer}/oauth2/authorize | Override the authorization endpoint | | tokenEndpoint | string | {issuer}/oauth2/token | Override the token endpoint | | userInfoEndpoint | string | {issuer}/oauth2/userinfo | Override the userinfo endpoint | | endSessionEndpoint | string | — | If set, logout() redirects to this URL to end the IDP session | | postLogoutRedirectUri | string | — | Where to send the user after the IDP ends the session | | scopes | string[] | ["openid","profile","email"] | OAuth scopes to request. Include "offline_access" for refresh tokens | | audience | string | — | Resource audience parameter (if required by your IDP) | | extraAuthorizeParams | Record<string,string> | — | Additional query parameters appended to the authorization URL | | useRefreshToken | boolean | true | Enable silent refresh using a refresh token | | defaultAppRedirect | string | window.location.pathname | App route to land on after login when no target was recorded | | storage | "session" | "local" | "memory" | "session" | Where tokens are persisted (see Storage) | | clockSkewSeconds | number | 60 | Tolerance when deciding if an access token is expired | | refreshLeewaySeconds | number | 90 | Refresh the access token this many seconds before it actually expires | | refreshLockKey | string | "ra_refresh_lock" | Storage key used for the cross-tab refresh lock | | refreshLockTtlMs | number | 15000 | How long (ms) the refresh lock can be held before it is force-released | | postLoginNavigation | "replace" \| "history" | "replace" | Callback completion navigation strategy ("replace" does full navigation; "history" uses history.replaceState) |

<RequireAuth>

Renders children only when the user is authenticated. While the session is being restored (isLoading) nothing is rendered. If the user is not authenticated, login() is called automatically and the component renders nothing.

<RequireAuth redirectTo="/dashboard">
  <ProtectedPage />
</RequireAuth>

| Prop | Type | Default | Description | |---|---|---|---| | redirectTo | string | window.location.pathname | App route to return to after login completes |

useAuth

Returns the current auth context. Must be called inside <AuthProvider>.

import { useAuth } from "@camall/react-auth";

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

  if (isLoading) return <span>Loading…</span>;
  if (!isAuthenticated) return <button onClick={() => login()}>Sign in</button>;

  return (
    <div>
      <span>{user?.name}</span>
      <button onClick={() => logout()}>Sign out</button>
    </div>
  );
}

Auth context properties

| Name | Type | Description | |---|---|---| | isLoading | boolean | true while the provider is restoring or completing the session | | isAuthenticated | boolean | true when a valid session exists | | user | Record<string, any> \| undefined | Decoded claims from the userinfo endpoint | | tokens | TokenSet \| undefined | Current token set (access, id, refresh, expiry) | | error | string \| undefined | Set when initialization fails | | config | AuthConfig | The config passed to <AuthProvider> | | login(opts?) | (opts?: { redirectTo?: string }) => Promise<void> | Redirect to the IDP login page | | logout() | () => Promise<void> | Clear the local session and optionally redirect to the IDP end-session endpoint | | getAccessToken() | () => Promise<string \| undefined> | Return a valid access token, refreshing silently if needed |

authFetch

A thin wrapper around fetch that injects the Authorization: Bearer <token> header and sets Accept: application/json by default. Calls getAccessToken() internally so the token is always fresh.

import { useAuth, authFetch } from "@camall/react-auth";

function DataLoader() {
  const auth = useAuth();

  async function load() {
    const res = await authFetch(auth, "https://api.example.com/me");
    if (!res.ok) throw new Error("Request failed");
    return res.json();
  }

  return <button onClick={load}>Load data</button>;
}

authFetch accepts the same arguments as the native fetch API except that the first argument is the auth context returned by useAuth().

authFetch(auth, input: RequestInfo | URL, init?: RequestInit): Promise<Response>

Storage

| Value | Persistence | Notes | |---|---|---| | "session" (default) | Browser tab lifetime | Cleared when the tab is closed | | "local" | Persistent across tabs and restarts | Use with caution — tokens survive browser restarts | | "memory" | Current page lifetime | Nothing is written to localStorage or sessionStorage; useful for SSR or strict CSP environments |

Refresh Token Support

Set useRefreshToken: true in your config and request the "offline_access" scope. The provider automatically refreshes the access token before it expires (refreshLeewaySeconds before expiry). A cross-tab storage lock (refreshLockKey) prevents multiple tabs from refreshing simultaneously — other tabs wait and then pick up the new token written by the winning tab.

IDP requirement: The IDP must allow refresh tokens for public (PKCE) clients. Token rotation is strongly recommended.

TypeScript

The package ships its own declarations. The following types are exported:

import type { AuthConfig, AuthState, TokenSet } from "@camall/react-auth";

| Type | Description | |---|---| | AuthConfig | Configuration object passed to <AuthProvider> | | AuthState | isLoading, isAuthenticated, user, tokens, error | | TokenSet | accessToken, idToken, refreshToken, tokenType, scope, expiresAt |

License

MIT