npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

next-auth-session

v0.1.6

Published

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

Downloads

2,390

Readme

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

| Function | Description | |----------|-------------| | 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 | | actions | Server actions: { refresh, update, logout } | | config | The resolved session config | | clientConfig | Pre-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

| Prop | Type | Default | Description | |------|------|---------|-------------| | children | ReactNode | required | Child components | | initialSession | Session \| null | null | Pre-fetched session from server | | fetchOnMount | boolean | true | Fetch session when component mounts | | refreshInterval | number | undefined | Auto-refresh interval in ms | | refetchOnPathChange | boolean | true | Refetch session on route change | | autoActivityRefresh | boolean | true | Auto-refresh based on refreshThreshold when user is active | | activityRefreshInterval | number | undefined | Custom activity refresh interval (overrides server) | | onSessionChange | (session) => void | undefined | Callback 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>
  );
}

| Property | Type | Description | |----------|------|-------------| | expiresAt | number \| null | Unix timestamp when session expires | | expiresIn | number \| null | Milliseconds until expiry | | isExpiringSoon | boolean | True if expiring within 1 hour | | recalculate | () => void | Manually 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