New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

next-auth-session

Package Overview
Dependencies
Maintainers
1
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

next-auth-session

Session management package for Next.js with JWT encryption, route protection, and React hooks

latest
npmnpm
Version
0.1.6
Version published
Maintainers
1
Created
Source

next-auth-session

A simple, flexible session management library for Next.js 14+ with App Router support.

Features

  • 🔐 JWT Session Encryption - Secure session storage using jose
  • 🚀 Server & Client Support - Works in Server Components, Server Actions, and Client Components
  • 🛡️ Route Protection - Middleware guard for public/auth/hybrid routes
  • 🌍 i18n Support - Locale-aware route matching
  • Factory API - Single configuration, all functions pre-configured
  • 🎣 React Hooks - useSession, useUser, useSessionExpiry and more
  • 📝 TypeScript - Full type safety with generic user types
  • 🔄 Auto Refresh - Automatic session refresh based on user activity

Installation

npm install next-auth-session
# or
pnpm add next-auth-session
# or
yarn add next-auth-session

Imports

// Server-side: Factory and utilities
import { NextAuthSession, route, patterns } from "next-auth-session";

// Client-side: Provider and hooks
import { 
  SessionProvider, 
  useSession, 
  useUser, 
  useSessionExpiry,
  useRequireAuth 
} from "next-auth-session/client";

Quick Start

1. Set Environment Variable

SESSION_SECRET=your-secret-key-at-least-32-characters

Generate a secret:

openssl rand -base64 32

2. Create Auth Configuration

Create lib/auth.ts:

import { NextAuthSession, route, patterns } from "next-auth-session";

export const {
  // Session operations
  createSession,
  getSession,
  updateSession,
  refreshSession,
  deleteSession,
  isAuthenticated,

  // Utilities
  encryptSession,
  decryptSession,
  isSessionExpired,
  shouldRefreshSession,

  // Middleware & Handlers
  middleware,
  handlers,

  // Server Actions - use with client components
  actions,

  // Config
  config,
  clientConfig,
} = NextAuthSession({
  session: {
    sessionExpiry: 60 * 60 * 24, // 1 day in seconds
    cookieName: "session",
    autoRefresh: true,
  },
  middleware: {
    routes: [
      route.public("/login"),
      route.public("/register"),
      route.auth(patterns.dashboard), // /dashboard/*
      route.hybrid("/"),
    ],
    loginPath: "/login",
    homePath: "/",
  },
});

3. Setup API Route

Create app/api/session/[[...session]]/route.ts:

import { handlers } from "@/lib/auth";

export const { GET, POST, PATCH, DELETE } = handlers();

4. Setup Middleware

Create middleware.ts:

import { middleware } from "@/lib/auth";

export default middleware();

export const config = {
  matcher: ["/((?!api|_next|static|.*\\..*).*)"],
};

Or with custom logic:

import { middleware } from "@/lib/auth";
import { NextRequest, NextResponse } from "next/server";

export default middleware((request, isAuthenticated, rule) => {
  // Custom logic here
  // Return NextResponse to override default behavior
  // Return undefined to use default behavior
});

5. Create Session (Login)

import { createSession } from "@/lib/auth";
import { redirect } from "next/navigation";

export async function loginAction(formData: FormData) {
  "use server";
  
  // Validate credentials...
  const user = await validateUser(formData);
  
  if (!user) {
    return { error: "Invalid credentials" };
  }

  const result = await createSession(user, {
    accessToken: "optional-token",
    refreshToken: "optional-refresh-token",
  });

  if (result.success) {
    redirect("/dashboard");
  }

  return { error: result.error };
}

6. Get Session (Server Components)

import { getSession } from "@/lib/auth";

export default async function DashboardPage() {
  const session = await getSession();

  if (!session) {
    return <div>Not authenticated</div>;
  }

  return <div>Welcome, {session.user.name}</div>;
}

7. Client-Side Session

For client components, use the SessionProvider:

// app/providers.tsx
"use client";

import { SessionProvider } from "next-auth-session/client";

export function Providers({ children }: { children: React.ReactNode }) {
  return <SessionProvider>{children}</SessionProvider>;
}
// app/layout.tsx
import { Providers } from "./providers";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
// components/UserMenu.tsx
"use client";

import { useSession } from "next-auth-session/client";

export function UserMenu() {
  const { session, status, logout, refresh } = useSession();

  if (status === "loading") return <div>Loading...</div>;
  if (status === "unauthenticated") return <LoginButton />;

  return (
    <div>
      <span>{session.user.name}</span>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

8. Using Server Actions

The actions object contains server-ready functions for client components:

// lib/actions.ts
"use server";

import { actions } from "@/lib/auth";

export async function refreshAction() {
  return actions.refresh();
}

export async function logoutAction() {
  return actions.logout();
}

export async function updateAction(updates: { name?: string }) {
  return actions.update({ user: updates });
}
// components/RefreshButton.tsx
"use client";

import { refreshAction, logoutAction } from "@/lib/actions";

export function RefreshButton() {
  return (
    <button onClick={() => refreshAction()}>
      Refresh Session
    </button>
  );
}

Configuration Options

Session Config

NextAuthSession({
  session: {
    // Required: Secret key (defaults to SESSION_SECRET env var)
    secretKey: process.env.SESSION_SECRET,
    
    // Session expiry in seconds (default: 7 days)
    sessionExpiry: 60 * 60 * 24 * 7,
    
    // Auto-refresh threshold in seconds (default: 1 day)
    refreshThreshold: 60 * 60 * 24,
    
    // Cookie name (default: "session")
    cookieName: "session",
    
    // Auto-refresh session on read (default: true)
    autoRefresh: true,
    
    // Secure cookie in production (default: true in production)
    secureCookie: process.env.NODE_ENV === "production",
    
    // SameSite cookie attribute (default: "lax")
    sameSite: "lax",
    
    // Custom validation callback
    onValidate: async (session) => {
      // Return true if valid, false to invalidate
      return true;
    },
    
    // Custom refresh callback
    onRefresh: async (session) => {
      // Return updated session or null
      return session;
    },
  },
});

Middleware Config

NextAuthSession({
  middleware: {
    // Route rules
    routes: [
      route.public("/login"),      // Only for unauthenticated users
      route.auth("/dashboard/*"),  // Only for authenticated users
      route.hybrid("/"),           // For everyone
    ],
    
    // Default route type (default: "hybrid")
    defaultType: "hybrid",
    
    // Redirect paths
    loginPath: "/login",
    homePath: "/",
    
    // i18n locale prefixes to strip
    locales: ["en", "ar"],
    
    // Custom authorization
    authorize: async (isAuthenticated, request, rule) => {
      // Return NextResponse to override
      // Return undefined for default behavior
    },
  },
});

Route Types

  • public: Only accessible to unauthenticated users. Authenticated users are redirected to homePath.
  • auth: Only accessible to authenticated users. Unauthenticated users are redirected to loginPath.
  • hybrid: Accessible to everyone. No redirects.

Route Patterns

import { route, patterns } from "next-auth-session";

// Built-in patterns
patterns.api        // "/api/*"
patterns.dashboard  // "/dashboard/*"
patterns.admin      // "/admin/*"
patterns.settings   // "/settings/*"
patterns.profile    // "/profile/*"

// Custom patterns
route.auth("/dashboard/*")    // Matches /dashboard and /dashboard/anything
route.public("/login")        // Exact match
route.hybrid("/blog*")        // Matches /blog, /blog/post, /blogs

Session Object

interface Session<T extends User> {
  user: T;
  accessToken?: string;
  refreshToken?: string;
  expiresAt: number;      // Unix timestamp in ms
  expiryDate: string;     // ISO date string
  createdAt: number;      // Unix timestamp in ms
  lastActivity: number;   // Unix timestamp in ms
}

interface User {
  id: string;
  email?: string;
  name?: string;
  image?: string;
  [key: string]: unknown;
}

API Reference

Factory Return Values

FunctionDescription
createSession(user, tokens?)Create a new session
getSession()Get current session
updateSession(updates)Update session data
refreshSession()Extend session expiry
deleteSession()Delete session
isAuthenticated()Check if user is authenticated
middleware(customHandler?)Create middleware function
handlers()Create API route handlers
encryptSession(session)Encrypt session to JWT
decryptSession(token)Decrypt JWT to session
isSessionExpired(session)Check if session is expired
shouldRefreshSession(session)Check if session needs refresh
actionsServer actions: { refresh, update, logout }
configThe resolved session config
clientConfigPre-configured props for SessionProvider

Client Hooks

import { useSession, useUser, useSessionExpiry, useRequireAuth } from "next-auth-session/client";

// useSession - Full session access
const {
  session,      // Current session or null
  status,       // "loading" | "authenticated" | "unauthenticated"
  refresh,      // Refresh session function
  update,       // Update session function
} = useSession();

// useUser - User-focused access
const {
  user,            // User object or null
  isAuthenticated, // Boolean
  isLoading,       // Boolean
} = useUser();

// useSessionExpiry - Track session expiry
const {
  expiresAt,       // Unix timestamp or null
  expiresIn,       // Milliseconds until expiry
  isExpiringSoon,  // True if expiring within 1 hour
  recalculate,     // Manually recalculate values
} = useSessionExpiry();

// useRequireAuth - Redirect if not authenticated
const { isLoading, isAuthenticated } = useRequireAuth("/login");

SessionProvider Props

PropTypeDefaultDescription
childrenReactNoderequiredChild components
initialSessionSession | nullnullPre-fetched session from server
fetchOnMountbooleantrueFetch session when component mounts
refreshIntervalnumberundefinedAuto-refresh interval in ms
refetchOnPathChangebooleantrueRefetch session on route change
autoActivityRefreshbooleantrueAuto-refresh based on refreshThreshold when user is active
activityRefreshIntervalnumberundefinedCustom activity refresh interval (overrides server)
onSessionChange(session) => voidundefinedCallback when session changes

The SessionProvider automatically fetches refreshThreshold from the API and uses it for activity-based session refresh. When a user is active (mouse, keyboard, touch, scroll), the session is refreshed at the configured threshold interval.

useSessionExpiry Hook

import { useSessionExpiry } from "next-auth-session/client";

function SessionTimer() {
  const { expiresAt, expiresIn, isExpiringSoon, recalculate } = useSessionExpiry();

  // Manually recalculate expiry time
  useEffect(() => {
    const interval = setInterval(recalculate, 1000);
    return () => clearInterval(interval);
  }, [recalculate]);

  if (!expiresAt) return null;

  return (
    <div>
      {isExpiringSoon && <span>Session expiring soon!</span>}
      <span>Expires in: {Math.floor((expiresIn ?? 0) / 1000)}s</span>
    </div>
  );
}
PropertyTypeDescription
expiresAtnumber | nullUnix timestamp when session expires
expiresInnumber | nullMilliseconds until expiry
isExpiringSoonbooleanTrue if expiring within 1 hour
recalculate() => voidManually recalculate expiry values

Advanced Usage

Custom User Type

import type { User, Session } from "next-auth-session";

interface MyUser extends User {
  id: string;
  email: string;
  name: string;
  role: "admin" | "user";
  permissions: string[];
}

// Type-safe session operations
const session = await getSession<MyUser>();
session?.user.role; // "admin" | "user"

With i18n (next-intl)

// lib/auth.ts
export const { middleware } = NextAuthSession({
  middleware: {
    routes: [
      route.public("/login"),
      route.auth("/dashboard/*"),
    ],
    locales: ["en", "ar", "es"], // Strip locale prefix when matching
    loginPath: "/login",
    homePath: "/dashboard",
  },
});

// middleware.ts
import { middleware } from "@/lib/auth";
import createIntlMiddleware from "next-intl/middleware";

const intlMiddleware = createIntlMiddleware({
  locales: ["en", "ar", "es"],
  defaultLocale: "en",
});

export default async function combinedMiddleware(request: NextRequest) {
  const response = intlMiddleware(request);
  
  if (response.ok) {
    const authResponse = await middleware()(request);
    if (authResponse.status !== 200) {
      return authResponse;
    }
  }
  
  return response;
}

Server-Side Initial Session

// app/layout.tsx
import { getSession } from "@/lib/auth";
import { SessionProvider } from "next-auth-session/client";

export default async function RootLayout({ children }) {
  const session = await getSession();

  return (
    <html>
      <body>
        <SessionProvider 
          initialSession={session}
          fetchOnMount={false}
        >
          {children}
        </SessionProvider>
      </body>
    </html>
  );
}

Types

interface User {
  id: string;
  [key: string]: unknown;
}

interface Session<T extends User = User> {
  user: T;
  accessToken?: string;
  refreshToken?: string;
  expiresAt: number;
  expiryDate: string;
  createdAt: number;
  lastActivity?: number;
}

interface SessionConfig {
  secretKey?: string;
  sessionExpiry?: number;
  refreshThreshold?: number;
  cookieName?: string;
  autoRefresh?: boolean;
  secureCookie?: boolean;
  sameSite?: "strict" | "lax" | "none";
  onRefresh?: (session: Session) => Promise<Session | null>;
  onValidate?: (session: Session) => Promise<boolean>;
}

interface MiddlewareConfig {
  routes?: RouteRule[];
  defaultType?: RouteType;
  loginPath?: string;
  homePath?: string;
  locales?: string[];
  authorize?: (isAuth: boolean, req: NextRequest, rule?: RouteRule) => NextResponse | void;
}

type RouteType = "public" | "auth" | "hybrid";

interface RouteRule {
  pattern: string;
  type: RouteType;
}

License

MIT

Keywords

next.js

FAQs

Package last updated on 14 Dec 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts