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

@induseuro-labs/auth-ui

v2.3.10

Published

A beautiful, reusable authentication UI template with RBAC support for Next.js and React applications

Readme

@induseuro-labs/auth-ui

A beautiful, reusable authentication UI template with RBAC (Role-Based Access Control) support for Next.js and React applications. Perfect for quickly adding professional login, signup, and password reset flows to any project.

Features

Authentication UI (MUI)

  • Forms: LoginForm, SignupForm, ForgotPasswordForm, ResetPasswordForm — email/password, Google entry point, OTP tab on login, forgot-password email request, and token-based “set new password” (?token= from email links).
  • Full pages: LoginPage, SignupPage, ForgotPasswordPage, ResetPasswordPage — same forms inside AuthPageLayout with left image or slider and right form.
  • Layout primitive: AuthPageLayout for custom compositions.

Session and state

  • AuthProvider + useAuth() — login, signup, Google, OTP login, refresh, logout, send reset email, complete password reset (token + newPassword).
  • Persisted session in localStorage (default key auth_session) with jwtToken, refreshToken, username, id, roles.
  • Cross-tab sync when the session key changes in another tab.

Built-in routing (no React Router required)

  • AuthRoutes — serves /login, /signup, /forgot-password, /reset-password, /dashboard, /unauthorized using the browser history API.
  • lockToAuthRoutes — unknown paths redirect to /login or /dashboard depending on auth; allowedPaths for extra public routes.

RBAC

  • Roles: admin, user, moderator (UserRole enum).
  • ProtectedRoute — gate by authentication and optional requiredRoles.
  • useRole — convenience helpers (isAdmin, etc.).

Theming

  • createMuiTheme / defaultTheme — dark-friendly defaults; works with your own MUI ThemeProvider.

Backend integration (no UI)

  • createAuthApiHandlers — builds AuthProvider callbacks from a baseURL + default REST paths (JSON fetch). Override paths or merge with custom onLogin, etc.
  • HTTP constantsAUTH_TOKEN_STORAGE_KEY, AUTH_HEADER_KEYS (X-tenant, Authorization, …), AUTH_CONTENT_TYPES for consistent headers.
  • createAuthAxiosClientAxios instance factory with tenant/accept headers, bearer from auth_tokens storage (separate from auth_session), and 401 → refresh → retry. Paths default to /api/v1/auth/* (signup, login, loginOtp, forgot/reset password, Google, refresh). axios is a peer dependency — install it alongside this package.

Utilities

  • useRouter / createDefaultRouter — small history-based router for SPAs not using Next.js.

Installation

npm install @induseuro-labs/auth-ui @mui/material @mui/icons-material @emotion/react @emotion/styled
# or
yarn add @induseuro-labs/auth-ui @mui/material @mui/icons-material @emotion/react @emotion/styled
# or
pnpm add @induseuro-labs/auth-ui @mui/material @mui/icons-material @emotion/react @emotion/styled

Peer dependency: install axios in your app (required for createAuthAxiosClient):

npm install axios

Note: Next.js is optional. The package works with both Next.js and regular React applications.

Quick Start

1. Setup MUI Theme Provider

Wrap your app with MUI's ThemeProvider:

// app/layout.tsx (Next.js) or App.tsx (React)
import { ThemeProvider } from '@mui/material/styles'
import CssBaseline from '@mui/material/CssBaseline'
import { createMuiTheme } from '@induseuro-labs/auth-ui'

const theme = createMuiTheme()

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <ThemeProvider theme={theme}>
          <CssBaseline />
          {children}
        </ThemeProvider>
      </body>
    </html>
  )
}

2. Wrap your app with AuthProvider

// app/layout.tsx (Next.js) or App.tsx (React)
import { AuthProvider } from '@induseuro-labs/auth-ui'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <AuthProvider
          onLogin={async (credentials) => {
            // Your login API call
            const response = await fetch('/api/login', {
              method: 'POST',
              body: JSON.stringify(credentials),
            })
            return response.json()
          }}
          onSignup={async (data) => {
            // Your signup API call
            const response = await fetch('/api/signup', {
              method: 'POST',
              body: JSON.stringify(data),
            })
            return response.json()
          }}
          onGoogleLogin={async () => {
            // Your Google OAuth implementation
            // ...
          }}
        >
          {children}
        </AuthProvider>
      </body>
    </html>
  )
}

3. Create Login Page

// app/login/page.tsx
'use client'

import { LoginPage } from '@induseuro-labs/auth-ui'

export default function LoginPage() {
  return (
    <LoginPage
      redirectTo="/dashboard"
      media="/images/auth-left.jpg" // single image mode
    />
  )
}

3A. Use Built-in Routes (No app routes required)

If you do not want to define /login, /signup, /forgot-password, /reset-password in each project, use AuthRoutes directly:

import { AuthProvider, AuthRoutes } from '@induseuro-labs/auth-ui'

export default function App() {
  return (
    <AuthProvider>
      <AuthRoutes
        // default paths:
        // /login, /signup, /forgot-password, /reset-password, /dashboard, /unauthorized
        lockToAuthRoutes
        media={['/images/slide-1.jpg', '/images/slide-2.jpg']}
        mediaMode="auto"
        dashboardComponent={<div>Dashboard content</div>}
      />
    </AuthProvider>
  )
}

With lockToAuthRoutes={true} (default), unknown routes are redirected:

  • Not logged in -> /login
  • Logged in -> /dashboard

Full-page layout with image/slider

You can use ready-made full pages for login, signup, and forgot password.

import { LoginPage, SignupPage, ForgotPasswordPage, ResetPasswordPage } from '@induseuro-labs/auth-ui'

// Single image
<LoginPage media="/images/auth.jpg" mediaMode="single" />

// Multiple images -> slider (auto when mediaMode="auto")
<SignupPage
  media={[
    '/images/slide-1.jpg',
    '/images/slide-2.jpg',
    '/images/slide-3.jpg',
  ]}
  mediaMode="auto"
  sliderIntervalMs={5000}
/>

// With rich slide content
<ForgotPasswordPage
  media={[
    {
      src: '/images/recover.jpg',
      title: 'Recover Account Access',
      description: 'Reset password and continue securely.',
    },
    {
      src: '/images/security.jpg',
      title: 'Your Security Matters',
      description: 'Use strong passwords and keep your account protected.',
    },
  ]}
/>

<ResetPasswordPage />

4. Create Signup Page

// app/signup/page.tsx (Next.js) or pages/Signup.tsx (React)
'use client' // Only needed in Next.js

import { SignupForm } from '@induseuro-labs/auth-ui'

export default function SignupPage() {
  return (
    <div className="min-h-screen flex items-center justify-center bg-slate-900 p-8">
      <SignupForm redirectTo="/dashboard" />
    </div>
  )
}

5. Protect Routes

// app/dashboard/page.tsx (Next.js) or pages/Dashboard.tsx (React)
'use client' // Only needed in Next.js

import { ProtectedRoute, UserRole } from '@induseuro-labs/auth-ui'

export default function DashboardPage() {
  return (
    <ProtectedRoute>
      <div>Your protected content</div>
    </ProtectedRoute>
  )
}

// Admin only page
export default function AdminPage() {
  return (
    <ProtectedRoute requiredRoles={[UserRole.ADMIN]}>
      <div>Admin only content</div>
    </ProtectedRoute>
  )
}

Backend integration

Fetch-based handlers for AuthProvider

If your backend matches the default JSON routes (see createAuthApiHandlers defaults), you can avoid repeating fetch boilerplate. createAuthApiHandlers does not call a logout URLlogout() only clears localStorage and session state. Redirect users to login when they have no session by wrapping protected pages with ProtectedRoute (or your own guard): when there is no token/session, isAuthenticated is false and redirectTo (default /login) runs.

import { AuthProvider, createAuthApiHandlers } from '@induseuro-labs/auth-ui'

const api = createAuthApiHandlers({
  baseURL: 'https://your-api.example.com',
  tenant: 'dev',
  paths: {
    // optional overrides, e.g. login: '/api/v1/auth/login'
  },
})

export function Root({ children }: { children: React.ReactNode }) {
  return (
    <AuthProvider
      {...api}
      // merge or override any single handler:
      // onLogin={customLogin}
      storageKey="auth_session"
    >
      {children}
    </AuthProvider>
  )
}

Axios client + shared header constants

Use this when you want a shared Axios instance for app APIs (not only auth forms), with 401 refresh retry and tokens in localStorage under auth_tokens by default (independent from AuthProvider’s auth_session unless you sync them):

import {
  AUTH_TOKEN_STORAGE_KEY,
  AUTH_HEADER_KEYS,
  AUTH_CONTENT_TYPES,
  createAuthAxiosClient,
} from '@induseuro-labs/auth-ui'

const authHttp = createAuthAxiosClient({
  baseURL: process.env.NEXT_PUBLIC_API_URL ?? '',
  tenant: 'dev',
  tokenStorageKey: AUTH_TOKEN_STORAGE_KEY,
  paths: {
    // optional: override defaults under /api/v1/auth/*
  },
})

// Use returned methods or the underlying instance:
const api = authHttp.getAxios()

// After login via this client, tokens are stored; interceptors attach:
// AUTH_HEADER_KEYS.authorization, AUTH_HEADER_KEYS.tenant, etc.

Exported TypeScript types include AuthTokens, LoginResponse, AuthUserResponse, AuthAxiosClient, CreateAuthAxiosClientConfig, and AuthAxiosPaths.

API Reference

AuthProvider Props

| Prop | Type | Required | Description | |------|------|----------|-------------| | onLogin | (credentials: LoginCredentials) => Promise<AuthResponse \| User> | No | Custom login handler | | onSignup | (data: SignupData) => Promise<AuthResponse \| User> | No | Custom signup handler | | onGoogleLogin | () => Promise<AuthResponse \| User> | No | Google OAuth handler | | onOTPLogin | (otpData: OTPData) => Promise<AuthResponse \| User> | No | OTP login handler | | onRefreshToken | (refreshToken: string) => Promise<AuthResponse> | No | Refresh token handler | | onLogout | (session: AuthResponse \| null) => Promise<void> \| void | No | Optional server revoke; default logout is client-only (clears storageKey + auth_tokens) | | additionalLogoutStorageKeys | string[] | No | Extra keys removed on logout (default: ['auth_tokens']; pass [] to only clear storageKey) | | onSendOTP | (email: string) => Promise<void> | No | Send OTP handler | | onResetPassword | (email: string) => Promise<void> | No | Password reset handler | | onCompletePasswordReset | (payload: { token: string; newPassword: string }) => Promise<void> | No | Complete reset with token + new password | | storageKey | string | No | localStorage key (default: 'auth_session') |

LoginForm Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | onSuccess | () => void | - | Callback on successful login | | redirectTo | string | '/dashboard' | Redirect path after login | | showBackButton | boolean | true | Show back button | | showGoogleLogin | boolean | true | Show Google login button | | showOTPTab | boolean | true | Show OTP tab | | title | string | 'Log in' | Form title | | subtitle | string | "Choose how you'd like to sign in." | Form subtitle | | className | string | '' | Additional CSS classes |

SignupForm Props

Similar to LoginForm with signup-specific defaults.

ProtectedRoute Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | requiredRoles | UserRole[] | - | Required roles to access | | redirectTo | string | '/login' | Redirect if not authenticated | | unauthorizedRedirectTo | string | '/unauthorized' | Redirect if wrong role |

AuthRoutes Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | loginPath | string | '/login' | Login route path | | signupPath | string | '/signup' | Signup route path | | forgotPasswordPath | string | '/forgot-password' | Forgot password route path | | resetPasswordPath | string | '/reset-password' | Reset password route path | | dashboardPath | string | '/dashboard' | Post-login route path | | unauthorizedPath | string | '/unauthorized' | Unauthorized route path | | lockToAuthRoutes | boolean | true | Redirect unknown paths to auth/dashboard routes | | allowedPaths | string[] | [] | Extra paths allowed when route lock is enabled | | dashboardComponent | React.ReactNode | null | Component rendered for dashboard path | | unauthorizedComponent | React.ReactNode | null | Component rendered for unauthorized path | | notFoundComponent | React.ReactNode | null | Component rendered for unknown path when route lock is disabled |

Hooks

useAuth

import { useAuth } from '@induseuro-labs/auth-ui'

function MyComponent() {
  const { user, session, isAuthenticated, refreshSession, logout, hasRole } = useAuth()
  
  // Check if user has specific role
  if (hasRole(UserRole.ADMIN)) {
    // Admin content
  }

  // Refresh access token when needed
  const handleRefresh = async () => {
    await refreshSession()
  }
}

useRole

import { useRole } from '@induseuro-labs/auth-ui'

function MyComponent() {
  const { isAdmin, isUser, isModerator } = useRole()
  
  if (isAdmin()) {
    // Admin content
  }
}

Auth Response Shape

The package supports and persists this API response shape in localStorage:

{
  "data": {
    "jwtToken": "string",
    "refreshToken": "string",
    "username": "string",
    "id": 0,
    "roles": ["string"]
  },
  "message": "string",
  "success": true
}

Types

import { User, UserRole, LoginCredentials, SignupData, AuthResponse, AuthData } from '@induseuro-labs/auth-ui'

enum UserRole {
  ADMIN = 'admin',
  USER = 'user',
  MODERATOR = 'moderator',
}

Using in React Apps (without Next.js)

This package works seamlessly with regular React applications. See REACT_APP_USAGE.md for detailed instructions.

Quick Example:

// App.tsx
import React from 'react'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { AuthProvider, LoginForm } from '@induseuro-labs/auth-ui'
import { ThemeProvider } from '@mui/material/styles'
import { createMuiTheme } from '@induseuro-labs/auth-ui'
import CssBaseline from '@mui/material/CssBaseline'

const theme = createMuiTheme()

function App() {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <BrowserRouter>
        <AuthProvider>
          <Routes>
            <Route path="/login" element={
              <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <LoginForm onSuccess={() => window.location.href = '/dashboard'} />
              </div>
            } />
          </Routes>
        </AuthProvider>
      </BrowserRouter>
    </ThemeProvider>
  )
}

export default App

Note: For React apps, use the onSuccess callback with your router's navigate function for SPA navigation, or let the component use window.location for full page navigation.

Customization

Custom MUI Theme

All components use Material-UI. You can customize the theme:

import { createTheme } from '@mui/material/styles'
import { createMuiTheme } from '@induseuro-labs/auth-ui'

// Use the default theme
const theme = createMuiTheme()

// Or create your own
const customTheme = createTheme({
  palette: {
    mode: 'dark',
    primary: {
      main: '#9333ea',
    },
  },
})

Custom Callbacks

<AuthProvider
  onLogin={async (credentials) => {
    // Your API integration
    const response = await fetch('/api/auth/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(credentials),
    })
    
    if (!response.ok) throw new Error('Login failed')
    
    const authResponse = await response.json()
    return authResponse
  }}
  onRefreshToken={async (refreshToken) => {
    const response = await fetch('/api/auth/refresh', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ refreshToken }),
    })
    if (!response.ok) throw new Error('Refresh failed')
    const authResponse = await response.json()
    return authResponse
  }}
>
  {children}
</AuthProvider>

Examples

Full Page Layout with Sidebar

// app/login/page.tsx
'use client'

import { LoginForm } from '@induseuro-labs/auth-ui'

export default function LoginPage() {
  return (
    <div className="min-h-screen flex">
      {/* Left Section - Image/Content */}
      <div className="hidden lg:flex lg:w-1/2 relative bg-gradient-to-br from-slate-800 to-slate-900">
        <div className="absolute inset-0 bg-[url('/your-image.jpg')] bg-cover bg-center opacity-20"></div>
        <div className="relative z-10 flex flex-col justify-between p-12 text-white">
          <div className="space-y-4">
            <h2 className="text-4xl font-bold">Welcome Back</h2>
            <p className="text-lg text-slate-300">
              Sign in to continue to your account.
            </p>
          </div>
        </div>
      </div>

      {/* Right Section - Login Form */}
      <div className="flex-1 flex items-center justify-center p-8 bg-slate-900">
        <LoginForm />
      </div>
    </div>
  )
}

Publishing to npm

  1. Update version in package.json
  2. Build the library:
    npm run build:lib
  3. Publish:
    npm publish --access public

License

MIT

Support

For issues and feature requests, please open an issue on GitHub.