A lightweight authentication session management system for Next.js applications using JWT tokens and HTTP-only cookies.
This module provides a complete session management solution that handles user authentication through encrypted JWT tokens stored in secure HTTP-only cookies. It's designed for Next.js applications and includes functions for login, logout, session retrieval, and automatic session refresh.
- JWT-based Authentication: Uses JSON Web Tokens with HS256 algorithm
- Secure Cookie Storage: Sessions stored in HTTP-only cookies for enhanced security
- Automatic Session Refresh: Built-in session renewal to prevent expiration
- Simple API: Clean, easy-to-use functions for all authentication operations
- TypeScript Support: Fully typed for better development experience
{
"jose": "^4.x.x",
"next": "^13.x.x || ^14.x.x"
}npm install joseThe module uses a hardcoded secret key for demonstration purposes. In production, you should:
- Use a strong, randomly generated secret key
- Store the secret in environment variables
- Consider using a longer session duration
// Replace this in production
const secretKey = process.env.JWT_SECRET || "your-strong-secret-key";Encrypts a payload into a JWT token.
Parameters:
payload: The data to encrypt (typically user information and expiration)
Returns: A signed JWT token string
Decrypts and verifies a JWT token.
Parameters:
input: The JWT token string to decrypt
Returns: The decrypted payload
Handles user login by creating a session and setting a secure cookie.
Parameters:
formData: Form data containing user credentials (expects 'email' field)
Behavior:
- Creates a user object with email and default name
- Generates a session token with 10-second expiration
- Sets an HTTP-only cookie with the session
Logs out the user by clearing the session cookie.
Behavior:
- Sets the session cookie to an empty value
- Sets cookie expiration to a past date to remove it
Retrieves and decrypts the current session.
Returns:
- Session data if valid session exists
nullif no session or invalid session
Middleware function to refresh session expiration.
Parameters:
request: Next.js request object
Returns:
- NextResponse with updated session cookie
undefinedif no session exists
Behavior:
- Extends session expiration by 10 seconds
- Updates the session cookie with new expiration
import { login, getSession, logout } from './auth-session';
// Handle login form submission
async function handleLogin(formData) {
await login(formData);
// User is now logged in
}
// Check if user is authenticated
async function checkAuth() {
const session = await getSession();
if (session) {
console.log('User:', session.user);
return true;
}
return false;
}
// Logout user
async function handleLogout() {
await logout();
// User is now logged out
}// middleware.ts
import { updateSession } from './lib/auth-session';
import { NextRequest } from 'next/server';
export async function middleware(request: NextRequest) {
return await updateSession(request);
}
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|.*\\.png$).*)',
],
};// app/dashboard/page.tsx
import { getSession } from '@/lib/auth-session';
import { redirect } from 'next/navigation';
export default async function Dashboard() {
const session = await getSession();
if (!session) {
redirect('/login');
}
return (
<div>
<h1>Welcome, {session.user.name}!</h1>
<p>Email: {session.user.email}</p>
</div>
);
}-
Change the Secret Key: The current implementation uses a hardcoded secret. In production:
const secretKey = process.env.JWT_SECRET; if (!secretKey) throw new Error('JWT_SECRET environment variable is required');
-
Extend Session Duration: The 10-second expiration is for demo purposes. Use appropriate durations:
.setExpirationTime("24h") // or "7d", "30d", etc.
-
Add CSRF Protection: Consider implementing CSRF tokens for additional security
-
Use HTTPS: Always use HTTPS in production to protect cookie transmission
-
Validate User Credentials: The current
loginfunction doesn't verify credentials
The session payload contains:
{
user: {
email: string,
name: string
},
expires: Date,
iat: number, // Issued at timestamp
exp: number // Expiration timestamp
}The module will throw errors for:
- Invalid JWT tokens
- Expired tokens
- Malformed session data
Implement proper error handling in your application:
try {
const session = await getSession();
} catch (error) {
console.error('Session error:', error);
// Handle invalid session
}This code is provided as-is for educational and development purposes.
import { SignJWT, jwtVerify } from "jose";
import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
const secretKey = "secret";
const key = new TextEncoder().encode(secretKey);
export async function encrypt(payload: any) {
return await new SignJWT(payload)
.setProtectedHeader({ alg: "HS256" })
.setIssuedAt()
.setExpirationTime("10 sec from now")
.sign(key);
}
export async function decrypt(input: string): Promise<any> {
const { payload } = await jwtVerify(input, key, {
algorithms: ["HS256"],
});
return payload;
}
export async function login(formData: FormData) {
// Verify credentials && get the user
const user = { email: formData.get("email"), name: "John" };
// Create the session
const expires = new Date(Date.now() + 10 * 1000);
const session = await encrypt({ user, expires });
// Save the session in a cookie
cookies().set("session", session, { expires, httpOnly: true });
}
export async function logout() {
// Destroy the session
cookies().set("session", "", { expires: new Date(0) });
}
export async function getSession() {
const session = cookies().get("session")?.value;
if (!session) return null;
return await decrypt(session);
}
export async function updateSession(request: NextRequest) {
const session = request.cookies.get("session")?.value;
if (!session) return;
// Refresh the session so it doesn't expire
const parsed = await decrypt(session);
parsed.expires = new Date(Date.now() + 10 * 1000);
const res = NextResponse.next();
res.cookies.set({
name: "session",
value: await encrypt(parsed),
httpOnly: true,
expires: parsed.expires,
});
return res;
}