@freshheads/react-auth
v0.0.2
Published
A type-safe React authentication library for Next.js and react applications with built-in role-based access control (RBAC) and JWT token management. Based on our own authentication backend.
Readme
@freshheads/react-auth
A type-safe React authentication library for Next.js and react applications with built-in role-based access control (RBAC) and JWT token management. Based on our own authentication backend.
Features
- 🔐 Authentication Management - Built-in login/logout functionality with JWT token handling
- 🛡️ Role-Based Access Control (RBAC) - Define route access based on user roles
- 🎯 Type-Safe - Full TypeScript support with generic types for routes and roles
- 🚀 Next.js Middleware Integration - Server-side route protection
- 🪝 React Hooks - Easy-to-use hooks for authentication state and utilities
- 🍪 Cookie Management - Automatic JWT cookie handling
Installation
npm install @freshheads/react-authPeer Dependencies
This package requires the following peer dependencies:
npm install react react-dom next @tanstack/react-query typescriptRequirements
- React: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- Next.js: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
- TypeScript: ^5.0.0
- @tanstack/react-query: ^5.95.2
Usage
1. Define Your Configuration
Create a configuration object that defines your routes, roles, and API mutations:
import { ReactAuthConfig } from '@freshheads/react-auth';
const appRoutes = ['/login', '/dashboard', '/admin', '/profile'] as const; // these are placeholders. Normally generated by next.js
const appRoles = ['admin', 'user'] as const; // these are placeholders. Normally generated by backend
const authConfig: ReactAuthConfig<
typeof AppRoutes,
typeof AppRoles[],
typeof usePasswordLoginPost,
typeof useLogoutPost> = {
// Define role-based routes
rbacRoutes: {
admin: {
routes: ['/admin'],
landing: '/admin',
},
user: {
routes: ['/dashboard', '/profile'],
landing: '/dashboard',
},
},
// Default routes
defaultRoutes: {
login: '/login',
landing: '/dashboard', // this is the default landing page when there is no landing page defined for a role
},
// Routes accessible to everyone
openRoutes: ['/about', '/contact'],
// Routes only accessible when NOT authenticated
unauthenticatedRoutes: ['/login', '/register'],
// Authorized roles
authorizedRoles: appRoles,
// Locale prefix support (e.g. /en/dashboard). based on next-intl
withLocaleRoutePrefix: false,
// API mutation functions pass in the mutation generated by Orval
apiMutations: {
loginUsernamePassword: usePasswordLoginPost,
logout: useLogoutPost,
},
// Optional: Custom cookie name (default: 'jwt_hp')
cookieName: 'jwt_hp',
};
export default authConfig;2. Set Up Next.js Middleware
Create or update your middleware.ts or proxy.ts file:
import { withAuth } from '@freshheads/react-auth/server';
import authConfig from './auth.config';
export default withAuth(authConfig);
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};3. Wrap Your App with AuthConfigProvider
In your root layout or app component:
'use client';
import { AuthConfigProvider } from '@freshheads/react-auth/client';
import authConfig from './auth.config';
export default function RootLayout({ children }) {
return (
<html>
<body>
<AuthConfigProvider config={authConfig}>
{children}
</AuthConfigProvider>
</body>
</html>
);
}4. Use Authentication Hooks
Check User Authentication and Roles
'use client';
import { useAuthUser } from '@freshheads/react-auth/client';
export default function Dashboard() {
const { roles, hasRole } = useAuthUser<'admin' | 'user'>();
if (!roles) {
return <div>Loading...</div>;
}
return (
<div>
<h1>Dashboard</h1>
{hasRole('admin') && <AdminPanel />}
{hasRole('user') && <UserPanel />}
</div>
);
}Login with Username and Password
'use client';
import { useUsernamePasswordLogin } from '@freshheads/react-auth/client';
export default function LoginForm() {
const { login } = useUsernamePasswordLogin();
const handleSubmit = async (e) => {
e.preventDefault();
await login({ username: 'user', password: 'pass' });
};
return <form onSubmit={handleSubmit}>{/* form fields */}</form>;
}Logout
'use client';
import { useLogout } from '@freshheads/react-auth/client';
export default function LogoutButton() {
const { logout } = useLogout();
return <button onClick={() => logout()}>Logout</button>;
}Get Role from Path
'use client';
import { useAuthUtils } from '@freshheads/react-auth/client';
export default function Navigation() {
const { getRoleFromPath } = useAuthUtils();
const adminRole = getRoleFromPath('/admin');
// Returns the role required to access the path
return <nav>{/* navigation */}</nav>;
}Access Auth Configuration
'use client';
import { useAuthConfig } from '@freshheads/react-auth/client';
export default function MyComponent() {
const config = useAuthConfig();
// Access any configuration property
console.log(config.defaultRoutes.login);
console.log(config.authorizedRoles);
return <div>...</div>;
}5. Server-Side Utilities
Get Roles from Request Cookies (Server-Side)
import { getRolesFromRequestCookies } from '@freshheads/react-auth/server';
import { cookies } from 'next/headers';
export async function GET() {
const cookieStore = await cookies();
const userRoles = getRolesFromRequestCookies(cookieStore);
return Response.json({ roles: userRoles });
}Get Role from Path (Server-Side)
import { getRoleFromPath } from '@freshheads/react-auth/server';
const requiredRole = getRoleFromPath('/admin');
// Returns 'admin'6. Utility Functions
Check if User Has a Specific Role
import { userHasRole } from '@freshheads/react-auth/client';
const isAdmin = await userHasRole('admin');Get Roles from Cookies
import { getRolesFromCookies } from '@freshheads/react-auth/client';
const roles = await getRolesFromCookies();
// Returns array of user roles or nullConfiguration Options
ReactAuthConfig
| Property | Type | Description |
|----------|------|-------------|
| rbacRoutes | RbacRoutes | Maps roles to their accessible routes and landing pages |
| defaultRoutes | { login: ValidRoute, landing: ValidRoute } | Default login and landing routes |
| openRoutes | ValidRoute[] | Routes accessible to everyone (authenticated or not) |
| unauthenticatedRoutes | ValidRoute[] | Routes only accessible when NOT authenticated |
| authorizedRoles | AuthorizedRoles | Array of valid roles in your application |
| withLocaleRoutePrefix | boolean | Whether routes have locale prefixes (e.g., /en/dashboard) |
| apiMutations | { loginUsernamePassword, logout } | API mutation functions for auth operations |
| cookieName | string (optional) | Custom cookie name (default: 'jwt_hp') |
RbacRoutes
type RbacRoutes<ValidRoute, AuthorizedRoles extends string[]> = {
[key in AuthorizedRoles[number]]: {
routes: ValidRoute[];
landing?: ValidRoute;
};
};How It Works
Middleware Protection: The
withAuthmiddleware intercepts all requests and checks:- If the route requires authentication
- If the user has the required role for the route
- Redirects unauthenticated users to the login page
- Redirects authenticated users away from unauthenticated-only routes
JWT Token Management: User roles are stored in a JWT token in cookies. The library automatically:
- Parses the JWT to extract user roles
- Validates authentication state
- Provides hooks to access user information
Role-Based Access: Routes are protected based on the roles defined in
rbacRoutes. Users can only access routes that match their assigned roles.
TypeScript Support
This library is built with TypeScript and provides full type safety:
// Define your specific types
type MyRoutes = '/home' | '/dashboard' | '/admin';
type MyRoles = 'user' | 'admin' | 'moderator';
// Get full type checking and autocomplete
const config: ReactAuthConfig<MyRoutes, MyRoles[]> = {
// TypeScript will validate all routes and roles
};Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
