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

@arascorp/auth

v1.0.0

Published

Reusable OAuth0/2/OIDC utility with inactivity timeout, built on oidc-client-ts, for React and Web Components.

Readme

@arascorp/auth

A modern authentication library for React applications, built on oidc-client-ts with enhanced features for seamless OAuth2/OIDC integration.

Features

  • 🔐 OAuth2/OIDC Authentication - Built on oidc-client-ts v2.1.1
  • ⚛️ React Integration - Hooks, context, and HOC patterns
  • 🛡️ Protected Routes - Automatic authentication and return URL handling
  • ⏱️ Inactivity Timeout - Configurable automatic logout
  • 🔄 Auto Callback Handling - Automatic OAuth callback processing
  • 🧪 TypeScript Support - Full TypeScript definitions
  • 🌐 Environment Helper - Cross-bundler environment variable support

Installation

npm install @arascorp/auth

Peer Dependencies:

  • react ^17.0.0 || ^18.0.0 || ^19.0.0
  • react-dom ^17.0.0 || ^18.0.0 || ^19.0.0
  • react-router-dom ^6.0.0 || ^7.0.0

Quick Start

1. Setup AuthProvider

import { BrowserRouter } from "react-router-dom";
import { AuthProvider, createAuthConfigFromEnv } from "@arascorp/auth";

// Load from environment variables
const authConfig = createAuthConfigFromEnv();

function App() {
  return (
    <BrowserRouter>
      <AuthProvider config={authConfig}>
        <YourAppContent />
      </AuthProvider>
    </BrowserRouter>
  );
}

⚠️ Important: AuthProvider must be inside a React Router context as it uses useNavigate().

2. Configure Environment Variables

# Vite (.env)
VITE_ARAS_AUTH_AUTHORITY=https://your-provider.com
VITE_ARAS_AUTH_CLIENT_ID=your-client-id
VITE_ARAS_AUTH_REDIRECT_URI=http://localhost:3000/callback
VITE_ARAS_AUTH_POST_LOGOUT_REDIRECT_URI=http://localhost:3000
VITE_ARAS_AUTH_SCOPE=openid profile email
VITE_ARAS_AUTH_AUDIENCE=https://your-api.com
VITE_ARAS_AUTH_TENANT=your-tenant-id
VITE_ARAS_AUTH_SILENT_REDIRECT_URI=http://localhost:3000/silent-renew
VITE_ARAS_AUTH_LOGOUT_AFTER_INACTIVITY_MS=900000

# Webpack/CRA (.env)
REACT_APP_ARAS_AUTH_AUTHORITY=https://your-provider.com
REACT_APP_ARAS_AUTH_CLIENT_ID=your-client-id
REACT_APP_ARAS_AUTH_REDIRECT_URI=http://localhost:3000/callback
REACT_APP_ARAS_AUTH_POST_LOGOUT_REDIRECT_URI=http://localhost:3000
REACT_APP_ARAS_AUTH_SCOPE=openid profile email
REACT_APP_ARAS_AUTH_AUDIENCE=https://your-api.com
REACT_APP_ARAS_AUTH_TENANT=your-tenant-id
REACT_APP_ARAS_AUTH_SILENT_REDIRECT_URI=http://localhost:3000/silent-renew
REACT_APP_ARAS_AUTH_LOGOUT_AFTER_INACTIVITY_MS=900000

Or configure manually:

const authConfig = {
  authority: "https://your-oidc-provider.com",
  client_id: "your-client-id",
  redirect_uri: window.location.origin + "/callback",
  scope: "openid profile email",
  tenant: "your-tenant-id" // Optional: ARAS CIAM tenant
};

3. Use Authentication

import { useAuth } from "@arascorp/auth";

function UserProfile() {
  const { user, loading, isAuthenticated, signInRedirect, signOutRedirect } = useAuth();

  if (loading) return <div>Loading...</div>;

  return isAuthenticated ? (
    <div>
      <h2>Welcome, {user?.profile.name}!</h2>
      <button onClick={signOutRedirect}>Sign Out</button>
    </div>
  ) : (
    <button onClick={signInRedirect}>Sign In</button>
  );
}

4. Protect Routes

import { Routes, Route } from "react-router-dom";
import { ProtectedRoute } from "@arascorp/auth";

function AppRoutes() {
  return (
    <Routes>
      <Route path="/" element={<HomePage />} />
      <Route
        path="/dashboard"
        element={
          <ProtectedRoute>
            <Dashboard />
          </ProtectedRoute>
        }
      />
    </Routes>
  );
}

Configuration Options

interface AuthConfig {
  authority: string; // OIDC provider URL (required)
  client_id: string; // Client ID (required)
  redirect_uri?: string; // Callback URL - can be any path (default: window.location.origin + "/callback")
  post_logout_redirect_uri?: string; // Default: window.location.origin
  scope?: string; // Default: "openid profile email"
  response_type?: string; // Default: "code"
  audience?: string; // API audience (Auth0, etc.)
  tenant?: string; // ARAS CIAM tenant identifier
  logoutAfterInactivityMs?: number; // Default: 1800000 (30 mins), 0 to disable
}

Callback Route: The library automatically detects your OAuth callback route from redirect_uri. You can use any path - not just /callback. Examples:

  • redirect_uri: "https://myapp.com/callback" → handles callbacks on /callback
  • redirect_uri: "https://myapp.com/auth/return" → handles callbacks on /auth/return
  • redirect_uri: "https://myapp.com/oauth/complete" → handles callbacks on /oauth/complete

## Supported Providers

Works with any OIDC-compliant provider:

### Auth0

```tsx
const config = {
  authority: "https://your-domain.auth0.com",
  client_id: "your-client-id",
  audience: "https://your-api.com" // Optional: for API access
};

Azure AD B2C

const config = {
  authority: "https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/B2C_1_signin/v2.0",
  client_id: "your-client-id"
};

Okta

const config = {
  authority: "https://your-org.okta.com/oauth2/default",
  client_id: "your-client-id"
};

Keycloak

const config = {
  authority: "https://your-keycloak.com/auth/realms/your-realm",
  client_id: "your-client-id"
};

Advanced Patterns

Error Handling

The library provides comprehensive error handling for OAuth callback errors (e.g., access_denied, unauthorized_client, etc.) with built-in loop prevention.

Callback Error Handling Modes

The callbackErrorHandling prop on AuthProvider controls how OAuth callback errors are handled and displayed:

Available modes:

| Mode | UI Display | Use Case | | --------------- | ------------------- | ------------------------------------------------- | | "simple" | Plain text | Default - minimal unstyled error (⭐ default) | | "silent" | None | Manual error handling via useAuth().error | | "rich" | Styled with buttons | Production-ready error UI | | "none" | None | ⚠️ Debugging only - disables loop prevention | | Custom function | Your renderer | Full control over error display |

All modes except "none" prevent infinite redirect loops when all routes are protected.

Example - Simple mode (default):

<AuthProvider config={authConfig}>
  <App />
</AuthProvider>

// Shows plain text error on callback route:
// "Authentication Failed
//  Access denied. You don't have permission to access this application.
//  [Try Again]"

Example - Rich mode (recommended for production):

<AuthProvider config={authConfig} callbackErrorHandling="rich">
  <App />
</AuthProvider>

// Shows styled error with branded UI and retry/dismiss buttons

Example - Silent mode (manual handling):

<AuthProvider config={authConfig} callbackErrorHandling="silent">
  <App />
</AuthProvider>;

function App() {
  const { error, clearError, signInRedirect } = useAuth();

  return (
    <div>
      {error && (
        <div className="error-banner">
          <h3>{error.title}</h3>
          <p>{error.message}</p>
          {error.canRetry && <button onClick={signInRedirect}>Try Again</button>}
          <button onClick={clearError}>Dismiss</button>
        </div>
      )}
      <YourAppContent />
    </div>
  );
}

Example - Custom function:

<AuthProvider
  config={authConfig}
  callbackErrorHandling={(error, clearError, signInRedirect) => (
    <div className="my-custom-error">
      <h2>🔒 {error.title}</h2>
      <p>{error.message}</p>
      {error.canRetry && <button onClick={signInRedirect}>Try Again</button>}
      <button onClick={clearError}>Dismiss</button>
    </div>
  )}
>
  <App />
</AuthProvider>

Common OAuth errors handled:

  • access_denied - User denied access or lacks permission (no retry)
  • unauthorized_client - Application not authorized
  • invalid_request - Malformed authentication request
  • invalid_scope - Invalid or unsupported scope
  • server_error - Server-side error occurred (can retry)
  • temporarily_unavailable - Service temporarily down (can retry)
  • interaction_required - User interaction needed
  • login_required - Re-authentication required
  • consent_required - User consent needed
  • unsupported_response_type - Response type not supported

Error object structure:

interface AuthErrorInfo {
  title: string; // User-friendly title
  message: string; // Detailed error message
  error: string; // OAuth error code (e.g., "access_denied")
  canRetry: boolean; // Whether retry is appropriate
  isUserAction?: boolean; // True if user explicitly denied access
}

Testing error handling:

Navigate to the callback URL with error parameters:

http://localhost:3000/callback?error=access_denied&error_description=No%20access&state=test

How loop prevention works:

When an OAuth error occurs on the callback route:

  1. AuthProvider detects the error and displays it (based on callbackErrorHandling mode)
  2. Children components (including ProtectedRoute) are not rendered during error display
  3. User can retry (triggers fresh sign-in) or reload the page (clears error state)
  4. This prevents infinite redirect loops even when all routes (including /) are protected

Custom Loading States

import { useAuth } from "@arascorp/auth";

function MyComponent() {
  const { user, loading, isAuthenticated, signInRedirect } = useAuth();

  if (loading) {
    return <CustomLoadingSpinner />;
  }

  if (!isAuthenticated) {
    return (
      <div>
        <h2>Please Sign In</h2>
        <button onClick={signInRedirect}>Sign In</button>
      </div>
    );
  }

  return <div>Welcome, {user?.profile.name}!</div>;
}

Custom Fallback for ProtectedRoute

const AuthRequired = () => (
  <div>
    <h2>Authentication Required</h2>
    <button onClick={() => signInRedirect()}>Sign In</button>
  </div>
);

<ProtectedRoute fallbackComponent={AuthRequired}>
  <ProtectedContent />
</ProtectedRoute>;

HOC Pattern

import { withAuth, AuthComponentProps } from "@arascorp/auth";

function UserComponent({ user, isAuthenticated, signInRedirect }: AuthComponentProps) {
  return isAuthenticated ? (
    <div>Welcome, {user?.profile.name}!</div>
  ) : (
    <button onClick={signInRedirect}>Sign In</button>
  );
}

// Basic usage
const User = withAuth(UserComponent);

// With route protection
const ProtectedUser = withAuth(UserComponent, { requireAuth: true });

// With custom fallback
const CustomUser = withAuth(UserComponent, {
  requireAuth: true,
  fallbackComponent: () => <div>Loading...</div>
});

Manual Callback Handling

By default, AuthProvider automatically handles OAuth callbacks on the route specified in redirect_uri.

Automatic mode (default):

<AuthProvider config={config} callbackErrorHandling="simple">
  {/* Library automatically:
      - Detects callback route from redirect_uri
      - Processes OAuth response (code or error)
      - Handles errors based on callbackErrorHandling
      - Navigates to returnUrl or "/"
  */}
  <YourApp />
</AuthProvider>

Note: The library automatically detects your callback route from the redirect_uri configuration. You can use any path (not just /callback):

const config = {
  authority: "https://your-provider.com",
  client_id: "your-client-id",
  redirect_uri: window.location.origin + "/auth/return" // Custom callback path
  // ... other config
};

<AuthProvider config={config}>
  {/* Auto-handles callback on /auth/return */}
  <YourApp />
</AuthProvider>;

Manual Control

For full control over callback processing, set autoHandleCallback={false}:

⚠️ Important: When autoHandleCallback={false}:

  • You must create a callback route component
  • You must manually call authService.signinRedirectCallback()
  • You're responsible for storing/retrieving returnUrl
  • You can optionally use library's error handling (see example below)
<AuthProvider config={config} autoHandleCallback={false}>
  <Routes>
    <Route path="/callback" element={<CallbackHandler />} />
    {/* Your other routes */}
  </Routes>
</AuthProvider>

Manual callback handler with custom error handling:

// CallbackHandler.tsx - Custom error UI
import { useAuth, handleOAuthCallback } from "@arascorp/auth";
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";

function CallbackHandler() {
  const { authService } = useAuth();
  const navigate = useNavigate();
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    handleOAuthCallback(authService, navigate, {
      onError: (err) => setError(err.message)
    });
  }, [authService, navigate]);

  if (error) {
    return (
      <div>
        <h2>Authentication Error</h2>
        <p>{error}</p>
        <button onClick={() => navigate("/")}>Go Home</button>
      </div>
    );
  }

  return <div>Processing login...</div>;
}

Manual callback handler using library's error UI (recommended):

// CallbackHandler.tsx - Reuse library's error display
import { useAuth, handleOAuthCallback } from "@arascorp/auth";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

function CallbackHandler() {
  const { authService, setError } = useAuth();
  const navigate = useNavigate();

  useEffect(() => {
    handleOAuthCallback(authService, navigate, { setError });
  }, [authService, setError, navigate]);

  // Error automatically displayed by AuthProvider based on callbackErrorHandling
  return <div>Processing login...</div>;
}

Simplest manual callback:

// CallbackHandler.tsx - Minimal implementation
import { useAuth, handleOAuthCallback } from "@arascorp/auth";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

function CallbackHandler() {
  const { authService } = useAuth();
  const navigate = useNavigate();

  useEffect(() => {
    handleOAuthCallback(authService, navigate).catch(console.error);
  }, [authService, navigate]);

  return <div>Processing login...</div>;
}
```**Why use manual mode?**

- Custom error UI/logic beyond built-in `callbackErrorHandling`
- Integration with existing error handling systems
- Analytics/logging on callback success/failure
- Custom navigation logic (e.g., based on user roles)
- Non-standard OAuth flows

React Strict Mode

The library is fully compatible with React Strict Mode. OAuth callbacks are processed only once, even with double-mounting, using sessionStorage-based state management.

TypeScript

Full TypeScript support with type definitions:

import { User } from "oidc-client-ts";
import { AuthConfig, AuthContextType, AuthComponentProps } from "@arascorp/auth";

// Typed hook usage
const { user, loading, isAuthenticated }: AuthContextType = useAuth();

// Typed HOC props
interface MyProps extends AuthComponentProps {
  customProp: string;
}

API Reference

useAuth()

Hook that provides authentication state and methods:

const {
  user, // User | null - Current user object
  loading, // boolean - Loading state
  isAuthenticated, // boolean - Authentication status
  error, // AuthErrorInfo | null - OAuth callback error
  signInRedirect, // () => Promise<void> - Initiate sign-in
  signOutRedirect, // () => Promise<void> - Sign out user
  clearError, // () => void - Clear current error
  setError, // (error: AuthErrorInfo | null) => void - Set error (for manual mode)
  authService // AuthService - Direct service access
} = useAuth();

<AuthProvider>

Main provider component:

<AuthProvider
  config={authConfig} // Auth configuration (required)
  callbackErrorHandling="simple" // Error display mode (default: "simple")
  autoHandleCallback={true} // Auto-handle OAuth callbacks (default: true)
>
  <App />
</AuthProvider>

Props:

  • config (required) - Authentication configuration object
    • authority (required) - OIDC provider URL
    • client_id (required) - Application client ID
    • redirect_uri - Callback URL (default: window.location.origin + "/callback")
    • scope - OAuth scopes (default: "openid profile email")
    • logoutAfterInactivityMs - Auto-logout timeout in ms (default: 900000 = 15 min)
    • audience - API audience (Auth0, etc.)
    • tenant - Tenant ID (ARAS CIAM)
  • callbackErrorHandling - How to handle OAuth callback errors (default: "simple")
    • "simple" - Show plain text error
    • "silent" - No UI, access via useAuth().error
    • "rich" - Styled error with retry/dismiss buttons
    • "none" - No error handling (⚠️ debugging only)
    • Custom function: (error: AuthErrorInfo, clearError: () => void, signInRedirect: () => void) => React.ReactNode
  • autoHandleCallback - Automatically process OAuth callbacks (default: true)

### `<ProtectedRoute>`

Component that requires authentication:

```tsx
<ProtectedRoute fallbackComponent={CustomComponent}>
  <YourProtectedContent />
</ProtectedRoute>

withAuth()

HOC for injecting auth props:

withAuth(Component, {
  requireAuth?: boolean,           // Auto-redirect if not authenticated
  fallbackComponent?: React.FC     // Custom loading/fallback component
});

createAuthConfigFromEnv()

Creates config from environment variables:

const config = createAuthConfigFromEnv({
  // Optional overrides
  scope: "openid profile email custom"
});

Manual Callback Utilities

Helper functions for manual callback handling (when autoHandleCallback={false}):

import {
  hasOAuthParams,
  isOAuthCallback,
  isCallbackRoute,
  getCallbackPath,
  saveReturnUrl,
  getReturnUrl,
  clearReturnUrl,
  navigateToReturnUrl
} from "@arascorp/auth";

// Check if URL has OAuth params (code/error + state)
hasOAuthParams(location.search); // true/false

// Check if current page is OAuth callback
isOAuthCallback(); // true/false

// Check if pathname matches callback route
isCallbackRoute(location.pathname, config.redirect_uri);

// Extract callback path from redirect_uri
getCallbackPath("https://example.com/auth/callback"); // "/auth/callback"

// Save URL to return to after authentication
saveReturnUrl("/dashboard");
saveReturnUrl(); // Saves current location

// Get saved return URL and clear it from storage
const url = getReturnUrl(); // Returns saved URL or "/"
const url = getReturnUrl("/home"); // Custom fallback

// Clear saved return URL without retrieving it
clearReturnUrl();

// Navigate to saved return URL using React Router (recommended)
navigateToReturnUrl(navigate); // Navigates to saved URL or "/"
navigateToReturnUrl(navigate, { replace: true }); // With navigation options

// Complete callback handler - handles everything in one call
handleOAuthCallback(authService, navigate); // Throws on error
handleOAuthCallback(authService, navigate, { setError }); // Use library error display (recommended)
handleOAuthCallback(authService, navigate, {
  onError: (err) => setCustomError(err.message), // Custom error handling
  callbackRoute: "/auth/callback", // Stay here on error
  navigationOptions: { replace: true } // Success navigation options
});

Error Types

interface AuthErrorInfo {
  title: string; // User-friendly error title
  message: string; // Detailed error message
  error: string; // OAuth error code
  canRetry: boolean; // Whether user can retry
  isUserAction?: boolean; // If user explicitly denied access
}

Important Notes

autoHandleCallback and callbackErrorHandling

  • callbackErrorHandling only works when autoHandleCallback={true} (default)
  • When autoHandleCallback={false}, you must handle errors manually in your callback component
  • See Manual Callback Handling for complete examples

Browser Support

  • Modern browsers with ES2018+ support
  • React 17+, 18+, 19+
  • React Router DOM v6+, v7+

Troubleshooting

"Oops! redirect_uri" or Invalid Redirect URI Error

This error occurs when the redirect_uri in your application config doesn't match the allowed callback URLs configured in your OIDC provider (CIAM, Auth0, etc.).

Common causes:

  1. Exact mismatch - URIs must match exactly, including:

    • Protocol (http:// vs https://)
    • Domain/port (localhost:3000 vs localhost:5173)
    • Path (/callback vs /auth/callback)
    • Trailing slashes (/callback vs /callback/)
  2. Case sensitivity - Some providers are case-sensitive (/Callback vs /callback)

  3. Missing configuration - Redirect URI not added to provider's allowed list

How to fix:

  1. Check your app configuration:
// Make sure redirect_uri exactly matches what's configured in CIAM
const authConfig = {
  authority: "https://your-provider.com",
  client_id: "your-client-id",
  redirect_uri: "https://myapp.com/callback" // ← Must match EXACTLY
  // ...
};
  1. Check your OIDC provider settings:

    • ARAS CIAM: Go to your application settings → Allowed Callback URLs
    • Auth0: Dashboard → Applications → Your App → Settings → Allowed Callback URLs
    • Azure AD: App registrations → Authentication → Redirect URIs
    • Okta: Applications → Your App → General Settings → Login redirect URIs
  2. Verify exact match:

# Your app config:
redirect_uri: "https://myapp.com/callback"

# CIAM allowed URLs must include:
https://myapp.com/callback    ✅ Correct
https://myapp.com/callback/   ❌ Wrong (trailing slash)
https://myapp.com/auth        ❌ Wrong (different path)
http://myapp.com/callback     ❌ Wrong (http vs https)
  1. For local development, add both:
http://localhost:3000/callback
http://localhost:5173/callback  (if using Vite)
  1. Common pitfall - Environment variables:
# Make sure your .env matches production config
VITE_ARAS_AUTH_REDIRECT_URI=https://myapp.com/callback
# Not:
VITE_ARAS_AUTH_REDIRECT_URI=https://myapp.com/callback/  ❌

Testing locally:

  • Use exact domain from environment variables
  • Check browser console for the actual redirect_uri being used
  • Verify provider's configuration includes your local URL

License

MIT

Support

For issues and questions: [email protected]