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

@auth31/auth-service

v1.0.16

Published

Reusable authentication package with login, forgot password, and reset password flows using React, TypeScript, and MUI

Readme

@auth31/auth-service

A comprehensive and reusable authentication service for React and Next.js applications, featuring Login, MFA (OTP Verification), Forgot Password, Reset Password, Change Password, and token refresh flows with Material UI (MUI) and dynamic branding support.

🚀 Features

  • Pre-built Auth Pages: Highly optimized Login, MFA (Verify OTP), Forgot Password, Reset Password, and Change Password pages.
  • Token Refresh: Built-in POST /auth/refresh support with token rotation, cookie storage, and automatic retry on 401.
  • Backend-Driven Error Messaging: Displays precise backend API error responses (detail, message, error) seamlessly across all authentication flows without static fallback error strings.
  • Enhanced OTP Verification (MFA):
    • Privacy & Security: Built-in email masking with interactive show/hide toggle.
    • Persistent Cooldown: Session-backed OTP resend timer that maintains countdown across browser refreshes.
    • Seamless Inputs: Mobile-friendly 6-digit input boxes with auto-focus and clipboard paste support.
  • Dynamic Branding: Inject logos, titles, colors, and backgrounds dynamically via BrandingProvider or remote config.
  • Flexible UI: Seamlessly integrates with Material UI (v5/v6) and custom themes.
  • Multiple Frameworks: Complete integration support for React (Vite/CRA) and Next.js (App Router).
  • Callback Driven: Handle authentication events (success/failure) and navigation overrides with custom callbacks.

🆕 What's New in Recent Updates

🔄 Token Refresh (/api/v1/auth/refresh)

  • Exchange a valid refresh token for a new access + refresh token pair.
  • Token rotation: the submitted refresh token is revoked; the client must replace both stored tokens.
  • Public-Key header is sent automatically from cached branding (must match the app that issued the token).
  • Single session: if another device already consumed the refresh token, the API returns 401 and the package clears tokens and redirects to login.
  • Authenticated package API calls that receive 401 automatically attempt one refresh, then retry.

⚡ Backend-Driven Error Toast Notifications

  • Replaced hardcoded static error strings with direct backend error response parsing (detail, message, error).
  • Clean, single-source toast notifications for failed API calls (e.g. {"detail": "Invalid OTP code"}).

🔐 MFA & OTP Improvements

  • Email Privacy Control: Automatically masks recipient email (a*****@domain.com) with a toggle button to reveal the full email address.
  • Resend OTP Cooldown: Persisted timer storage (otpResendStorage) ensuring cooldown timers remain accurate even if the page is refreshed.
  • Dynamic Text Templates: Support for template interpolation in verifyOtp branding configuration ({{email}} and {{expiryTime}}).

📦 Installation

To get started, install the package and its peer dependencies:

npm install @auth31/auth-service @mui/material @emotion/react @emotion/styled @mui/icons-material react-router-dom axios notistack js-cookie

[!NOTE] Ensure you have react and react-dom (>= 18) installed in your project.


🛠️ Usage: React (Vite/CRA)

Follow these steps to integrate the auth service into your React application.

1. Configure the Auth Provider

In your entry point (usually main.tsx or App.tsx), wrap your application with the hierarchical providers.

[!IMPORTANT] appId and backend_url are essential configuration properties. Other properties like endpoints, callbacks, and navigation are optional. Set onNavigateToLogin so expired sessions redirect correctly after a failed refresh.

import {
	AuthConfigProvider,
	BrandingProvider,
	ThemeProvider,
	NotistackProvider,
	LoginPage,
	ForgotPasswordPage,
	ResetPasswordPage,
	VerifyOtpPage
} from "@auth31/auth-service";

import { BrowserRouter, Routes, Route } from "react-router-dom";

const authConfig = {
	appId: "12345", // Required
	apiBaseUrl: "http://localhost:3000", // Frontend URL (Testing)
	backend_url: "https://your-api-url.com/api/v1", // Backend API URL
	navigation: {
		onNavigateToLogin: () => {
			window.location.assign("/");
		}
	},
	callbacks: {
		onTokenRefreshSuccess: (data) => {
			console.log("Tokens refreshed", data);
		},
		onTokenRefreshError: (error) => {
			console.error("Token refresh failed", error);
		},
		onSessionExpired: () => {
			console.log("Session expired — user redirected to login");
		}
	}
};

function App() {
	return (
		<AuthConfigProvider config={authConfig}>
			<BrandingProvider>
				{/* ThemeProvider is optional. Use yours or ours! */}
				<ThemeProvider>
					<NotistackProvider>
						<BrowserRouter>
							<Routes>
								<Route path="/" element={<LoginPage />} />
								<Route path="/verify-otp" element={<VerifyOtpPage />} />
								<Route
									path="/forgot-password"
									element={<ForgotPasswordPage />}
								/>
								<Route path="/reset-password" element={<ResetPasswordPage />} />
							</Routes>
						</BrowserRouter>
					</NotistackProvider>
				</ThemeProvider>
			</BrandingProvider>
		</AuthConfigProvider>
	);
}

export default App;

🛠️ Usage: Next.js (App Router)

Since this package uses react-router-dom for internal navigation, it requires a client-side wrapper to function within Next.js.

Step 1: Create a Client-Side Auth Wrapper

Create components/AuthServiceWrapper.tsx:

"use client";

import {
	AuthConfigProvider,
	BrandingProvider,
	ThemeProvider,
	NotistackProvider,
	LoginPage,
	ForgotPasswordPage,
	ResetPasswordPage,
	VerifyOtpPage
} from "@auth31/auth-service";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { useRouter } from "next/navigation";

export default function AuthServiceWrapper() {
	const router = useRouter();

	const authConfig = {
		appId: process.env.NEXT_PUBLIC_APP_ID!,
		backend_url: process.env.NEXT_PUBLIC_API_URL!,
		apiBaseUrl: "http://localhost:3000", // Frontend URL for testing
		navigation: {
			onNavigateToLogin: () => router.push("/auth/login"),
			onNavigateToVerifyOtp: (data) =>
				router.push(
					`/auth/verify-otp?request_id=${data.request_id}&email=${data.email}`
				)
		},
		callbacks: {
			onLoginSuccess: (data) => {
				console.log("Login success, proceed to MFA", data);
			},
			onVerifyOtpSuccess: () => router.push("/dashboard"),
			onTokenRefreshSuccess: (data) => {
				console.log("Tokens refreshed", data);
			},
			onSessionExpired: () => router.push("/auth/login")
		}
	};

	return (
		<AuthConfigProvider config={authConfig}>
			<BrandingProvider>
				<ThemeProvider>
					<NotistackProvider>
						<BrowserRouter basename="/auth">
							<Routes>
								<Route path="/login" element={<LoginPage />} />
								<Route path="/verify-otp" element={<VerifyOtpPage />} />
								<Route
									path="/forgot-password"
									element={<ForgotPasswordPage />}
								/>
								<Route path="/reset-password" element={<ResetPasswordPage />} />
							</Routes>
						</BrowserRouter>
					</NotistackProvider>
				</ThemeProvider>
			</BrandingProvider>
		</AuthConfigProvider>
	);
}

Step 2: Create a Catch-all Route

Create app/auth/[...slug]/page.tsx to handle all authentication routes:

import dynamic from "next/dynamic";

// Disable SSR for the auth flow because it depends on browser routing
const AuthServiceWrapper = dynamic(
	() => import("@/components/AuthServiceWrapper"),
	{ ssr: false }
);

export default function AuthPage() {
	return <AuthServiceWrapper />;
}

🔑 Token Storage & Refresh (Host App Requirements)

Installing the package and wrapping providers is not enough for refresh. The MFA flow returns an authorization code, not tokens. Your host application must store tokens after it receives them (for example after exchanging the code with your backend).

1. Store tokens (required)

import { tokenStorage } from "@auth31/auth-service";

// After your app obtains access_token + refresh_token:
tokenStorage.set(access_token, refresh_token);

Tokens are stored in cookies (access_token, refresh_token).

2. Refresh tokens

import { refreshSession, refreshTokenApi, tokenStorage } from "@auth31/auth-service";

// Recommended: rotates cookies, handles 401 → login
const data = await refreshSession();
// data.access_token, data.refresh_token, data.user, ...

// Or call the API directly (you must store the new pair yourself):
const response = await refreshTokenApi({
	refresh_token: tokenStorage.getRefreshToken()!
});
tokenStorage.set(response.access_token, response.refresh_token);

3. What the package does automatically

| Behavior | Details | | -------- | ------- | | Public-Key header | Injected from branding cache on every API call (including refresh) | | Token rotation | refreshSession() replaces both cookies with the new pair | | Auto-refresh on 401 | Package API calls that send Authorization retry once after refresh | | Failed refresh / 401 | Clears cookies and redirects via navigation.onNavigateToLogin (fallback: /) |

[!IMPORTANT] Auto-refresh only applies to the package API client. If your host app uses its own Axios/fetch client, call refreshSession() yourself on 401, or use createApiClient from this package.

4. Clear tokens on logout

import { tokenStorage } from "@auth31/auth-service";

tokenStorage.clear();

⚙️ Configuration Reference

AuthConfig

| Property | Type | Requirement | Description | | ------------- | -------- | ------------ | ----------- | | backend_url | string | Required | The base URL for your authentication backend API (e.g. https://…/api/v1). | | apiBaseUrl | string | Optional | Frontend Testing URL. If provided, it takes precedence over the branding redirect_url and is used to construct forgot password links. Ideal for localhost testing. | | appId | string | Required | ID used to fetch branding and for Public-Key scoped API calls (including refresh). | | endpoints | object | Optional | Override default paths for login, forgotPassword, resetPassword, changePassword, and refresh. | | callbacks | object | Optional | Success/Error hooks for auth actions, MFA, token refresh (onTokenRefreshSuccess, onTokenRefreshError), and onSessionExpired. | | navigation | object | Optional | Override internal routing (crucial for Next.js). Includes onNavigateToLogin (used after failed refresh) and onNavigateToVerifyOtp. |

BrandingConfig

| Property | Description | | ---------------- | -------------------------------------------------------------- | | appName | The name of your application. | | logoUrl | URL to your brand logo. | | primaryColor | Hex code for primary buttons and accents. | | secondaryColor | Hex code for success indicators. | | background | Configuration for "gradient", "color", or "image" backgrounds. |


📦 Exported Components & Hooks

  • Pages: LoginPage, VerifyOtpPage, ForgotPasswordPage, ResetPasswordPage, ChangePasswordPage.
  • Providers: AuthConfigProvider, BrandingProvider, ThemeProvider, NotistackProvider.
  • Hooks:
    • useAuthConfig(): Access current configuration.
    • useBranding(): Access active branding and theme settings.
  • Token / session:
    • tokenStorage: set, getAccessToken, getRefreshToken, clear.
    • refreshSession(): Exchange refresh token, rotate cookies, redirect on failure.
    • refreshTokenApi(): Low-level POST /auth/refresh call.
  • API helpers: loginApi, verifyOtpApi, forgotPasswordApi, changePasswordApi, createApiClient.

📄 License

MIT © auth31