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

@wmtkrishan/auth

v1.1.1

Published

Reusable authentication package for React applications

Readme

@wmtkrishan/auth

A reusable React authentication package with full login/register flow, route guards, role-based access control, and swappable UI components.

Installation

npm install @wmtkrishan/auth

Peer Dependencies

npm install axios react react-dom react-router-dom zustand

Quick Start

1. Import the stylesheet once in your entry file:

// main.tsx
import '@wmtkrishan/auth/dist/style.css'

2. Wrap your app:

import { BrowserRouter } from 'react-router-dom'
import { AuthModule } from '@wmtkrishan/auth'

<BrowserRouter>
  <AuthModule
    config={{ apiBaseUrl: 'https://api.example.com' }}
    routes={{ login: '/login', register: '/register', appHome: '/dashboard' }}
  />
</BrowserRouter>

That's it. Default login and register pages are included out of the box.


Config

AuthConfig

| Property | Type | Default | Description | |---|---|---|---| | apiBaseUrl | string | — | Required. Base URL for all API calls | | storage | 'localStorage' \| 'sessionStorage' | 'localStorage' | Where the token is persisted | | tokenKey | string | 'wmt_auth_token' | Storage key name for the token | | userKey | string | 'wmt_auth_user' | Storage key name for the user | | timeout | number | 10000 | Axios request timeout in ms | | axiosInstance | AxiosInstance | — | Bring your own axios instance | | tokenResponseKey | string | 'token' | Key path in login/register response that contains the token. Supports dot notation e.g. 'data.accessToken' | | mapUser | (response: unknown) => AuthUser | identity | Transform the raw getCurrentUser API response into your user shape |

AuthRoutesConfig

| Property | Type | Default | Description | |---|---|---|---| | login | string | — | Required. Path for the login page | | register | string | — | Required. Path for the register page | | appHome | string | '/dashboard' | Redirect destination after login | | roleRedirects | Record<string, string> | {} | Permission-based redirects after login |

const routes = {
  login: '/login',
  register: '/register',
  appHome: '/dashboard',
  roleRedirects: {
    ADMIN: '/admin',   // users with ADMIN permission → /admin
    EDITOR: '/editor', // users with EDITOR permission → /editor
  },
}

Patterns

Pattern A — AuthModule (plug-and-play)

<BrowserRouter>
  <AuthModule
    config={config}
    routes={routes}
    components={components}
    loadingFallback={<Spinner />}
  >
    <Routes>
      <Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
    </Routes>
  </AuthModule>
</BrowserRouter>

Pattern B — AuthProvider + AuthRoutes (explicit)

<BrowserRouter>
  <AuthProvider config={config} routes={routes}>
    <AuthRoutes components={components} loadingFallback={<Spinner />}>
      <Routes>
        <Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
      </Routes>
    </AuthRoutes>
  </AuthProvider>
</BrowserRouter>

Both patterns are equivalent. Pattern B gives more control over layout.


Route Guards

ProtectedRoute

Redirects unauthenticated users to the login page. Optionally enforces permissions.

// Any authenticated user
<ProtectedRoute>
  <Dashboard />
</ProtectedRoute>

// Only users with the ADMIN permission
<ProtectedRoute requiredPermissions={['ADMIN']}>
  <AdminPanel />
</ProtectedRoute>

// With a loading fallback
<ProtectedRoute fallback={<Spinner />}>
  <Dashboard />
</ProtectedRoute>

| Prop | Type | Description | |---|---|---| | children | ReactNode | Content to render when access is granted | | requiredPermissions | string[] | Permissions the user must have. Redirects to appHome if missing | | fallback | ReactNode | Shown while session is restoring |

GuestRoute

Redirects authenticated users away from public pages (login, register).

<GuestRoute fallback={<Spinner />}>
  <LoginPage />
</GuestRoute>

Hooks

useAuth()

Returns the current session state.

const { user, token, loading, isAuthenticated } = useAuth()

| Return | Type | Description | |---|---|---| | user | AuthUser \| null | Current logged-in user | | token | string \| null | Current auth token | | loading | boolean | true while session is being restored on mount | | isAuthenticated | boolean | true when user and token are present |


useLogin()

Handles login, token storage, user fetch, and role-based redirect. Pass any fields your API expects — no fixed shape required.

const { login, loading, error } = useLogin()

// username + password
await login({ username: 'john', password: 'secret' })

// email + password
await login({ email: '[email protected]', password: 'secret' })

// any custom shape
await login({ phone: '+1234567890', pin: '9999', rememberMe: true })

| Return | Type | Description | |---|---|---| | login | (credentials: LoginCredentials) => Promise<void> | Triggers the login flow | | loading | boolean | true while request is in-flight | | error | string \| null | Error message if login failed |


useRegister()

Handles registration, token storage, user fetch, and redirect to appHome. Pass any fields your API expects.

const { register, loading, error } = useRegister()

await register({ username: 'jane', email: '[email protected]', password: 'secret' })

// with extra fields
await register({ email: '[email protected]', password: 'secret', firstName: 'Jane', referralCode: 'ABC' })

| Return | Type | Description | |---|---|---| | register | (data: RegisterData) => Promise<void> | Triggers the register flow | | loading | boolean | true while request is in-flight | | error | string \| null | Error message if registration failed |


useLogout()

Calls the logout API, clears local state and storage, and redirects to login.

const { logout } = useLogout()

<button onClick={logout}>Logout</button>

The local session is always cleared even if the server call fails.


Custom UI

Override any page by passing components to AuthModule or AuthRoutes.

import { NoShell } from '@wmtkrishan/auth'

const components = {
  LoginPage: CustomLogin,       // your own login page
  RegisterPage: CustomRegister, // your own register page
  AuthShell: NoShell,           // removes the default layout wrapper
}

<AuthModule config={config} routes={routes} components={components} />

NoShell

A bare passthrough component. Use it as AuthShell when your custom pages manage their own full-screen layout and you don't want DefaultAuthShell's background or padding applied.

import { NoShell } from '@wmtkrishan/auth'

components={{ AuthShell: NoShell }}

Custom Login Example

Use useLogin() inside your component — it handles all logic.

import { useLogin } from '@wmtkrishan/auth'

export function CustomLogin() {
  const { login, loading, error } = useLogin()
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')

  return (
    <form onSubmit={e => { e.preventDefault(); login({ username, password }) }}>
      {error && <p>{error}</p>}
      <input value={username} onChange={e => setUsername(e.target.value)} />
      <input type="password" value={password} onChange={e => setPassword(e.target.value)} />
      <button disabled={loading}>{loading ? 'Signing in…' : 'Sign in'}</button>
    </form>
  )
}

Custom Register Example

import { useRegister } from '@wmtkrishan/auth'

export function CustomRegister() {
  const { register, loading, error } = useRegister()

  return (
    <form onSubmit={e => {
      e.preventDefault()
      register({ username: '...', email: '...', password: '...' })
    }}>
      {error && <p>{error}</p>}
      {/* your fields */}
      <button disabled={loading}>{loading ? 'Creating…' : 'Register'}</button>
    </form>
  )
}

API Endpoints

The package calls these endpoints against your apiBaseUrl:

| Method | Endpoint | Auth | Description | |---|---|---|---| | POST | /auth/login | No | Login with credentials | | POST | /auth/register | No | Register a new user | | POST | /auth/logout | Yes | Invalidate the session | | GET | /auth/me | Yes | Fetch the current user | | POST | /auth/refresh-token | No | Refresh the access token |

Token is sent as Authorization: Bearer <token> on authenticated requests.


TypeScript

All types are exported:

import type {
  AuthConfig,
  AuthRoutesConfig,
  AuthUser,
  ComponentOverrides,
  LoginCredentials,
  RegisterData,
  ApiResponse,
} from '@wmtkrishan/auth'

AuthUser

Only permissions is typed (required for role-based access control). All other fields are open — your API response shape is used as-is.

type AuthUser = {
  id?: number | string
  permissions?: { name: string }[]
  [key: string]: unknown   // any fields your API returns
}

Use mapUser in config to type-cast the user to your own interface:

interface MyUser {
  id: number
  name: string
  email: string
  role: string
}

const config = {
  apiBaseUrl: '...',
  mapUser: (res) => res as MyUser,
}

// Then in components:
const { user } = useAuth()
const myUser = user as MyUser

Advanced — Token Response Key

If your login API returns the token under a different key:

// API returns: { accessToken: 'abc123' }
config = { apiBaseUrl: '...', tokenResponseKey: 'accessToken' }

// API returns: { data: { jwt: 'abc123' } }
config = { apiBaseUrl: '...', tokenResponseKey: 'data.jwt' }

Dot notation is supported for nested values.


Advanced — Map User Response

If your getCurrentUser API wraps data in a wrapper object:

// API returns: { status: 'ok', data: { id: 1, name: 'John', role: 'admin' } }
config = {
  apiBaseUrl: '...',
  mapUser: (res: any) => res.data,
}

mapUser runs on every session restore (page reload) and after every login/register.


Advanced — Bring Your Own Axios Instance

import axios from 'axios'

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

<AuthProvider
  config={{ apiBaseUrl: 'https://api.example.com', axiosInstance: myAxios }}
  routes={routes}
>
  ...
</AuthProvider>

Changelog

1.1.0

  • LoginCredentials and RegisterData are now open records — pass any fields your API expects
  • AuthUser is now an open type — only permissions is typed, all other fields come from your API
  • Added tokenResponseKey config — configure which key (including dot-notation paths) holds the token in login/register responses
  • Added mapUser config — transform raw getCurrentUser response into your user shape

1.0.4

  • Added README.md to published package

1.0.3

  • Added NoShell export for custom full-screen page layouts

1.0.2

  • Fixed shell bypass using named Passthrough component instead of Fragment

1.0.1

  • Auto-skip DefaultAuthShell when custom LoginPage or RegisterPage is provided

1.0.0

  • Initial release