@shyam-148/auth-next
v1.0.3
Published
Next.js App Router authentication - simple SSR, RSC, middleware support
Maintainers
Readme
auth-next
Simple, focused authentication for Next.js App Router. Built on top of auth-client.
Features
- ✅ App Router Only - Designed for Next.js 14/15+ App Router
- ✅ Server Components - Full RSC support with
getSession,getUser - ✅ Client Components - React context with
useAuth,useUser,useSession - ✅ Middleware - Edge-compatible route protection
- ✅ Guards - Declarative
<AuthGuard>and<GuestGuard>components - ✅ TypeScript - Full type safety
- ✅ Tree-shakeable - Import only what you need
Installation
pnpm add auth-next auth-clientQuick Start
1. Create Provider Wrapper
// app/providers.tsx
'use client';
import { AuthProvider } from 'auth-next/client';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<AuthProvider
config={{
baseUrl: process.env.NEXT_PUBLIC_AUTH_API_URL!,
applicationSlug: 'my-app',
}}
>
{children}
</AuthProvider>
);
}2. Add to Layout
// app/layout.tsx
import { Providers } from './providers';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}3. Setup Middleware
// middleware.ts
import { createAuthMiddleware } from 'auth-next/middleware';
export default createAuthMiddleware({
publicRoutes: ['/', '/login', '/register', '/api/public/*'],
authRoutes: ['/login', '/register'],
loginUrl: '/login',
defaultRedirect: '/dashboard',
});
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};Usage
Client Components
'use client';
import { useAuth, useUser, AuthGuard, GuestGuard } from 'auth-next/client';
// Basic hook usage
function UserMenu() {
const { user, logout, isAuthenticated } = useAuth();
if (!isAuthenticated) return null;
return (
<div>
<span>{user?.email}</span>
<button onClick={logout}>Logout</button>
</div>
);
}
// Simpler user-only hook
function UserAvatar() {
const { user, isLoading } = useUser();
if (isLoading) return <Skeleton />;
if (!user) return null;
return <Avatar name={user.fullName} />;
}
// Guard component - shows content only when authenticated
function ProtectedPage() {
return (
<AuthGuard fallback={<Loading />} redirectTo="/login">
<Dashboard />
</AuthGuard>
);
}
// Guest guard - shows content only when NOT authenticated
function LoginPage() {
return (
<GuestGuard redirectTo="/dashboard">
<LoginForm />
</GuestGuard>
);
}Server Components
// app/dashboard/page.tsx
import { getSession, getUser } from 'auth-next/server';
import { redirect } from 'next/navigation';
export default async function DashboardPage() {
const session = await getSession({
apiBase: process.env.AUTH_API_URL!,
});
if (!session) {
redirect('/login');
}
return (
<div>
<h1>Welcome, {session.user.email}</h1>
<p>Session ID: {session.session.id}</p>
</div>
);
}Server Actions
// app/actions.ts
'use server';
import { requireAuth } from 'auth-next/server';
export async function updateProfile(formData: FormData) {
// Throws if not authenticated
const session = await requireAuth({
apiBase: process.env.AUTH_API_URL!,
});
// session.user is guaranteed to exist
await db.users.update({
where: { id: session.user.id },
data: { name: formData.get('name') as string },
});
}Route Handlers
// app/api/protected/route.ts
import { withAuth } from 'auth-next/middleware';
export const GET = withAuth(async (request, { userId }) => {
// userId is guaranteed to exist
const data = await fetchUserData(userId);
return Response.json(data);
});API Reference
Client Exports (auth-next/client)
| Export | Description |
|--------|-------------|
| AuthProvider | React context provider |
| useAuth | Main auth hook - user, session, logout, refresh |
| useUser | User-only hook - user, isLoading, isAuthenticated |
| useSession | Session hook - session, user, refresh |
| useAuthStatus | Status-only hook - status, isLoading, isAuthenticated |
| useLogout | Logout hook - logout function with loading state |
| getAuthManager | Get the underlying AuthManager for advanced operations |
| AuthGuard | Show children only when authenticated |
| GuestGuard | Show children only when NOT authenticated |
| ShowWhenAuthenticated | Conditional render for authenticated users |
| ShowWhenGuest | Conditional render for guests |
Server Exports (auth-next/server)
| Export | Description |
|--------|-------------|
| getSession | Get current session (user + session + token) |
| getUser | Get current user only |
| isAuthenticated | Check if request is authenticated |
| requireAuth | Get session or throw error |
| getAccessToken | Get access token from cookies |
| createAuthHeaders | Create Authorization headers for API calls |
| AuthenticationError | Error class for auth failures |
Middleware Exports (auth-next/middleware)
| Export | Description |
|--------|-------------|
| createAuthMiddleware | Create Next.js middleware |
| getAuthFromRequest | Get auth status from request |
| withAuth | Wrap route handler to require auth |
| createMatcher | Helper to create middleware matcher config |
Configuration
AuthProvider Props
interface AuthProviderProps {
config: {
baseUrl: string; // Auth API URL
applicationSlug: string; // Your app identifier
// ... other auth-client config
};
initialUser?: User | null; // For SSR hydration
initialSession?: Session | null;
loadingComponent?: ReactNode; // Show during init
children: ReactNode;
}Middleware Config
interface AuthMiddlewareConfig {
publicRoutes?: string[]; // Routes that don't require auth
authRoutes?: string[]; // Routes that redirect if authenticated
loginUrl?: string; // Where to redirect unauthenticated users
defaultRedirect?: string; // Where to redirect authenticated users from auth routes
}Login Flow
Since authentication strategies vary, login is handled via auth-client directly:
'use client';
import { getAuthManager } from 'auth-next/client';
import { EmailPasswordStrategy } from 'auth-client';
function LoginForm() {
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
const manager = getAuthManager();
const strategy = new EmailPasswordStrategy(manager.config.applicationSlug);
await manager.login(strategy, {
email: '[email protected]',
password: 'password',
});
// Auth state updates automatically via context
router.push('/dashboard');
};
return <form onSubmit={handleSubmit}>...</form>;
}License
MIT
