@aniloptimizely/aspnet-auth-react
v1.0.0
Published
Plug-and-play React authentication for ASP.NET Core — JWT, cookie, silent refresh, anti-forgery, and role/claim-based UI guards.
Readme
@aniloptimizely/aspnet-auth-react
Plug-and-play React 19 authentication for ASP.NET Core — JWT, cookie, silent refresh, anti-forgery, and role/claim-based UI guards.
Features
- Dual auth modes — JWT bearer tokens or cookie-based sessions
- Silent token refresh — proactive refresh with configurable buffer + mutex to prevent concurrent refreshes
- Cross-tab sync — BroadcastChannel keeps auth state consistent across browser tabs
- XSRF protection — automatic anti-forgery token management for cookie mode
- Role & claim guards —
<Authorize>component anduseAuthorize()hook for declarative or imperative checks - Authenticated fetch —
useAspNetFetch()hook with auto-attached auth headers and 401 retry - .NET claim normalisation — maps WIF claim URIs (e.g.
http://schemas.microsoft.com/ws/2008/06/identity/claims/role) to short-form names - Typed errors —
AuthErrorwith error codes and ASP.NET CoreProblemDetailssupport - Dependency injection — injectable services for easy testing and customisation
- SSR-safe — guards on
window/documentaccess - Tree-shakeable —
sideEffects: false, ESM + CJS dual output
Requirements
| Dependency | Version | |---|---| | React | >= 19.0.0 | | React DOM | >= 19.0.0 | | react-router-dom | >= 6.0.0 (optional) | | Node.js | >= 18.0.0 |
Installation
npm install @aniloptimizely/aspnet-auth-reactQuick Start
1. Configure
// authConfig.ts
import type { AuthConfig } from '@aniloptimizely/aspnet-auth-react';
export const authConfig: AuthConfig = {
mode: 'jwt',
baseUrl: 'http://localhost:5000',
loginEndpoint: '/api/auth/login',
logoutEndpoint: '/api/auth/logout',
userInfoEndpoint: '/api/auth/me',
refreshEndpoint: '/api/auth/refresh',
refreshBufferMs: 60_000,
onError: (error) => console.error('[auth]', error.code, error.message),
};2. Wrap Your App
// App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { AspNetAuthProvider } from '@aniloptimizely/aspnet-auth-react';
import { authConfig } from './authConfig';
export default function App() {
return (
<BrowserRouter>
<AspNetAuthProvider config={authConfig}>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/dashboard" element={<DashboardPage />} />
<Route path="/admin" element={<AdminPage />} />
</Routes>
</AspNetAuthProvider>
</BrowserRouter>
);
}3. Login
import { useAspNetAuth } from '@aniloptimizely/aspnet-auth-react';
function LoginPage() {
const { login, status, error } = useAspNetAuth();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
await login({ username: 'admin', password: 'password' });
};
return (
<form onSubmit={handleSubmit}>
{error && <p style={{ color: 'red' }}>{error.message}</p>}
{/* username/password inputs */}
<button type="submit" disabled={status === 'loading'}>
{status === 'loading' ? 'Signing in...' : 'Sign In'}
</button>
</form>
);
}4. Protect Routes
import { ProtectedRoute, Authorize, useAspNetAuth } from '@aniloptimizely/aspnet-auth-react';
function DashboardPage() {
const { user, logout } = useAspNetAuth();
return (
<ProtectedRoute redirectTo="/login" loadingFallback={<p>Loading...</p>}>
<h1>Welcome, {user.name}!</h1>
<Authorize roles={['Admin']} fallback={<p>Admin section hidden.</p>}>
<div>Admin-only content</div>
</Authorize>
<button onClick={() => void logout()}>Sign Out</button>
</ProtectedRoute>
);
}5. Make Authenticated API Calls
import { useAspNetFetch } from '@aniloptimizely/aspnet-auth-react';
function UserProfile() {
const apiFetch = useAspNetFetch();
const loadProfile = async () => {
const data = await apiFetch<{ displayName: string }>('/api/profile');
console.log(data.displayName);
};
return <button onClick={loadProfile}>Load Profile</button>;
}Auth Modes
| Mode | How it works | When to use |
|---|---|---|
| JWT (mode: 'jwt') | Bearer token in Authorization header. Silent refresh via HttpOnly cookie. | SPAs, mobile-first, microservices |
| Cookie (mode: 'cookie') | Session cookie + XSRF token. Auto-attaches X-XSRF-TOKEN header on mutating requests. | Traditional web apps, same-origin APIs |
➡️ See JWT Mode Guide and Cookie Mode Guide for detailed setup.
Exports
| Export | Type | Purpose |
|---|---|---|
| AspNetAuthProvider | Component | Root context provider |
| useAspNetAuth() | Hook | Auth state + login/logout/refresh actions |
| useAuthorize() | Hook | Role/claim-based authorization checks |
| useAspNetFetch() | Hook | Authenticated fetch with auto-retry |
| <Authorize> | Component | Declarative role/claim guard |
| <ProtectedRoute> | Component | Route guard with redirect |
| <LoginRedirect> | Component | Redirect to login with return URL |
| AuthService | Class | HTTP auth operations (injectable) |
| AntiforgeryService | Class | XSRF token management (injectable) |
| AuthError | Class | Typed error with code + ProblemDetails |
| AuthErrorCode | Enum | Machine-readable error codes |
➡️ See the full API Reference for detailed signatures and types.
Documentation
| Document | Description | |---|---| | API Reference | Complete API documentation for all exports | | Integration Guide | Step-by-step ASP.NET Core + React setup | | JWT Mode | JWT bearer token authentication guide | | Cookie Mode | Cookie/session authentication guide | | Testing Checklist | Comprehensive testing and verification checklist | | Contributing | How to contribute to this project | | Changelog | Version history and release notes |
ASP.NET Core Endpoint Contract
The library expects your ASP.NET Core API to expose:
| Endpoint | Method | Purpose | Response |
|---|---|---|---|
| /api/auth/login | POST | Authenticate | { accessToken, refreshToken?, expiresIn? } (JWT) or set cookie (cookie mode) |
| /api/auth/logout | POST | End session | 200 OK |
| /api/auth/me | GET | Current user info | { id, name, email, roles[], claims[] } |
| /api/auth/refresh | POST | Refresh JWT | { accessToken } (JWT mode only) |
All endpoints are configurable via AuthConfig. The library accepts both camelCase and PascalCase response shapes.
Architecture
AspNetAuthProvider (DI root)
├── AuthContext (React context)
├── authReducer (pure state management)
├── AuthService (HTTP layer, injectable)
├── AntiforgeryService (XSRF tokens, injectable)
├── RefreshMutex (concurrent refresh serialisation)
└── BroadcastChannel (cross-tab sync)
Hooks
├── useAspNetAuth() → facade over context
├── useAuthorize() → role/claim checks
└── useAspNetFetch() → authenticated HTTP
Components
├── <Authorize> → conditional render by role/claim/strategy
├── <ProtectedRoute> → route guard with redirect
└── <LoginRedirect> → login redirect with return URL
Utils
├── claimsNormaliser → .NET WIF URI → short-form mapping
├── tokenUtils → JWT decode, expiry, validation
└── refreshMutex → concurrent refresh coordination