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

@nightmar3/uauth-server

v1.0.6

Published

Server-side utilities for Universal Auth SDK (Next.js, Node.js)

Readme

@nightmar3/uauth-server

Server-side utilities for Universal Auth SDK. Provides session management and token handling for Next.js and other server environments.

[!IMPORTANT] Backend Required: This SDK requires a backend API. See Backend Requirements for the complete API contract, or use our Backend Implementation Guide for step-by-step instructions.

Installation

npm install @nightmar3/uauth-core @nightmar3/uauth-server

Quick Start

Next.js App Router

// app/dashboard/page.tsx
import { cookies } from 'next/headers'
import { createServerAuth, getServerSession } from '@nightmar3/uauth-server'
import { redirect } from 'next/navigation'

export default async function DashboardPage() {
  const auth = createServerAuth({
    baseURL: process.env.AUTH_API_URL!
  })

  const session = await getServerSession(auth, cookies)

  if (!session) {
    redirect('/login')
  }

  return (
    <div>
      <h1>Welcome {session.user.name}</h1>
      <p>{session.user.email}</p>
    </div>
  )
}

Next.js Middleware

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { createServerAuth } from '@nightmar3/uauth-server'

const auth = createServerAuth({
  baseURL: process.env.AUTH_API_URL!
})

export async function middleware(request: NextRequest) {
  const session = await auth.getSessionFromRequest(request)

  if (!session.ok) {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  // Add user info to headers for downstream use
  const requestHeaders = new Headers(request.headers)
  requestHeaders.set('x-user-id', session.data.user.id)
  requestHeaders.set('x-user-email', session.data.user.email)

  return NextResponse.next({
    request: {
      headers: requestHeaders
    }
  })
}

export const config = {
  matcher: ['/dashboard/:path*', '/api/protected/:path*']
}

Backend Requirements

The SDK expects a backend API that implements the following endpoints. You can use our FastAPI reference implementation or build your own.

Endpoints

| Method | Path | Description | Request Body | Response Data | |--------|------|-------------|--------------|---------------| | POST | /sign-in/password | Sign in with email/password | { email, password } | { user, tokens } | | POST | /sign-in/oauth2 | Exchange OAuth code for tokens | { provider, code, redirect_uri } | { user, tokens } | | POST | /sign-up | Create new account | { email, password, name? } | { user, tokens } | | DELETE| /session | Sign out (revoke tokens) | - | { ok: boolean } | | GET | /session | Get current user session | - | { user } | | POST | /token/refresh | Refresh access token | { refresh_token } | { tokens } | | GET | /providers | List available OAuth providers | - | { providers } |

Response Format

All API responses must follow this envelope structure:

interface ApiResponse<T> {
  ok: boolean
  data: T | null
  error: {
    code: string
    message: string
    details?: any
  } | null
}

Token Structure

The backend must return tokens in this format:

interface AuthTokens {
  access_token: string
  refresh_token: string
  expires_in: number // seconds
}

OAuth Provider Response (Optional)

If implementing OAuth support, the /providers endpoint must return:

interface OAuth2Provider {
  name: string
  displayName: string
  clientId: string
  authorizationUrl: string
  scope?: string
}

Example:

{
  "ok": true,
  "data": {
    "providers": [
      {
        "name": "google",
        "displayName": "Google",
        "clientId": "your-google-client-id",
        "authorizationUrl": "https://accounts.google.com/o/oauth2/v2/auth",
        "scope": "openid email profile"
      }
    ]
  },
  "error": null
}

API Reference

createServerAuth(config)

Create a server-side auth client.

import { createServerAuth } from '@nightmar3/uauth-server'

const auth = createServerAuth({
  baseURL: 'https://api.yourapp.com/auth',
  cookieName: 'auth_token',          // Optional: access token cookie name (default: 'auth_token')
  refreshTokenCookieName: 'refresh_token',  // Optional: refresh token cookie name (default: 'refresh_token')
  fetch: customFetch                 // Optional: custom fetch implementation
})

Methods

auth.getSession(cookieHeader, onTokenRefresh?)

Get session from a cookie header string. Supports automatic token refresh on 401 responses.

// Basic usage
const session = await auth.getSession(req.headers.cookie)

if (session.ok) {
  console.log('User:', session.data.user)
}

// With auto-refresh on 401
const session = await auth.getSession(req.headers.cookie, async (tokens) => {
  // Called when tokens are refreshed
  // Set new cookies or update storage
  res.setHeader('Set-Cookie', [
    serializeCookie('access_token', tokens.access_token, { httpOnly: true, secure: true }),
    serializeCookie('refresh_token', tokens.refresh_token, { httpOnly: true, secure: true }),
  ])
})

Parameters:

  • cookieHeader - The Cookie header string from the request
  • onTokenRefresh - Optional callback called when tokens are refreshed (for 401 auto-refresh)

Returns: Promise<ApiResponse<SessionData>>

Auto-refresh behavior: When onTokenRefresh is provided and the session request returns 401:

  1. SDK extracts refresh token from cookies
  2. Calls /token/refresh to get new tokens
  3. Calls onTokenRefresh callback with new tokens
  4. Retries session request with new access token

auth.getSessionFromRequest(request)

Get session from a Request object (works with Next.js, Vercel Edge, etc.).

const session = await auth.getSessionFromRequest(request)

if (session.ok) {
  console.log('User:', session.data.user)
}

Returns: Promise<ApiResponse<SessionData>>

auth.verifyToken(token)

Verify a JWT token and return user.

const token = 'eyJhbGc...'
const result = await auth.verifyToken(token)

if (result.ok) {
  console.log('Token valid:', result.data.user)
}

Returns: Promise<ApiResponse<SessionData>>

auth.refreshToken(refreshToken)

Refresh access token using a refresh token.

const result = await auth.refreshToken(refreshTokenValue)

if (result.ok) {
  console.log('New tokens:', result.data.tokens)
  // Set new cookies with the refreshed tokens
}

Returns: Promise<ApiResponse<{ tokens: AuthTokens }>>

auth.refreshFromCookies(cookieHeader, refreshTokenCookieName?)

Refresh token by extracting the refresh token from cookies.

const result = await auth.refreshFromCookies(req.headers.cookie)

if (result.ok) {
  // Set new cookies with refreshed tokens
  res.setHeader('Set-Cookie', [
    serializeCookie('access_token', result.data.tokens.access_token, { ... }),
    serializeCookie('refresh_token', result.data.tokens.refresh_token, { ... }),
  ])
}

Returns: Promise<ApiResponse<{ tokens: AuthTokens }>>

Cookie Utilities

parseCookies(cookieHeader)

Parse cookies from a Cookie header string.

import { parseCookies } from '@nightmar3/uauth-server'

const cookies = parseCookies(req.headers.cookie)
console.log(cookies.auth_token)

Returns: Record<string, string>

serializeCookie(name, value, options)

Create a cookie string with proper security settings.

import { serializeCookie } from '@nightmar3/uauth-server'

const cookie = serializeCookie('auth_token', 'token_value', {
  httpOnly: true,
  secure: true,
  sameSite: 'lax',
  maxAge: 60 * 60 * 24 * 7  // 7 days
})

// Set-Cookie: auth_token=token_value; HttpOnly; Secure; SameSite=Lax; Max-Age=604800

Options:

interface CookieOptions {
  domain?: string
  path?: string
  maxAge?: number
  httpOnly?: boolean
  secure?: boolean
  sameSite?: 'strict' | 'lax' | 'none'
}

deleteCookie(name, options)

Create a cookie deletion string.

import { deleteCookie } from '@nightmar3/uauth-server'

const cookie = deleteCookie('auth_token')
res.setHeader('Set-Cookie', cookie)

Next.js Utilities

getServerSession(auth, cookies)

Get session in Next.js App Router server components.

import { cookies } from 'next/headers'
import { getServerSession } from '@nightmar3/uauth-server'

const session = await getServerSession(auth, cookies)

if (!session) {
  redirect('/login')
}

Returns: Promise<SessionData | null>

createAuthMiddleware(config)

Create Next.js middleware with authentication.

import { createAuthMiddleware, createServerAuth } from '@nightmar3/uauth-server'

const auth = createServerAuth({
  baseURL: process.env.AUTH_API_URL!
})

const authMiddleware = createAuthMiddleware({
  auth,
  redirectTo: '/login',
  publicPaths: ['/login', '/signup', '/public/*']
})

export async function middleware(request) {
  const result = await authMiddleware(request)

  if (result.redirect) {
    return NextResponse.redirect(new URL(result.redirect, request.url))
  }

  // result.session contains user data
  return NextResponse.next()
}

Examples

Next.js API Route

// app/api/protected/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { createServerAuth } from '@nightmar3/uauth-server'

const auth = createServerAuth({
  baseURL: process.env.AUTH_API_URL!
})

export async function GET(request: NextRequest) {
  const session = await auth.getSessionFromRequest(request)

  if (!session.ok) {
    return NextResponse.json(
      { error: 'Unauthorized' },
      { status: 401 }
    )
  }

  return NextResponse.json({
    message: 'Protected data',
    user: session.data.user
  })
}

Express.js Middleware

import express from 'express'
import { createServerAuth } from '@nightmar3/uauth-server'

const app = express()
const auth = createServerAuth({
  baseURL: process.env.AUTH_API_URL!
})

// Auth middleware
const requireAuth = async (req, res, next) => {
  const session = await auth.getSession(req.headers.cookie)

  if (!session.ok) {
    return res.status(401).json({ error: 'Unauthorized' })
  }

  req.user = session.data.user
  next()
}

// Protected route
app.get('/api/protected', requireAuth, (req, res) => {
  res.json({
    message: 'Protected data',
    user: req.user
  })
})

Cookie-Based Authentication Flow

// Sign in endpoint that sets cookie
export async function POST(request: NextRequest) {
  const { email, password } = await request.json()

  // Call your auth backend
  const response = await fetch(`${process.env.AUTH_API_URL}/auth/sign-in/password`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password })
  })

  const result = await response.json()

  if (!result.ok) {
    return NextResponse.json(result, { status: 401 })
  }

  // Set cookie
  const cookie = serializeCookie('auth_token', result.data.tokens.access_token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    maxAge: result.data.tokens.expires_in
  })

  return NextResponse.json(result, {
    headers: {
      'Set-Cookie': cookie
    }
  })
}

Server Component with User Data

// app/profile/page.tsx
import { cookies } from 'next/headers'
import { createServerAuth, getServerSession } from '@nightmar3/uauth-server'
import { redirect } from 'next/navigation'

interface User {
  id: string
  email: string
  name: string
  role: 'admin' | 'user'
}

export default async function ProfilePage() {
  const auth = createServerAuth<User>({
    baseURL: process.env.AUTH_API_URL!
  })

  const session = await getServerSession(auth, cookies)

  if (!session) {
    redirect('/login')
  }

  return (
    <div>
      <h1>{session.user.name}</h1>
      <p>Email: {session.user.email}</p>
      <p>Role: {session.user.role}</p>
    </div>
  )
}

Role-Based Access Control

// lib/auth.ts
import { cookies } from 'next/headers'
import { createServerAuth, getServerSession } from '@nightmar3/uauth-server'
import { redirect } from 'next/navigation'

export async function requireAuth() {
  const auth = createServerAuth({
    baseURL: process.env.AUTH_API_URL!
  })

  const session = await getServerSession(auth, cookies)

  if (!session) {
    redirect('/login')
  }

  return session
}

export async function requireRole(role: string) {
  const session = await requireAuth()

  if (session.user.role !== role) {
    redirect('/unauthorized')
  }

  return session
}

// Usage in server component
export default async function AdminPage() {
  const session = await requireRole('admin')

  return <AdminPanel user={session.user} />
}

TypeScript Support

Full TypeScript support with generic user types:

interface MyUser {
  id: string
  email: string
  role: 'admin' | 'user'
  subscription: string
}

const auth = createServerAuth<MyUser>({
  baseURL: process.env.AUTH_API_URL!
})

const session = await auth.getSession(cookieHeader)

if (session.ok) {
  // session.data.user is typed as MyUser
  console.log(session.data.user.role)
}

Security Best Practices

Cookie Security

serializeCookie('auth_token', token, {
  httpOnly: true,      // Prevents XSS attacks
  secure: true,        // HTTPS only
  sameSite: 'strict',  // CSRF protection
  path: '/',
  maxAge: 60 * 60 * 24 * 7  // 7 days
})

CSRF Protection

For cookie-based auth, implement CSRF tokens:

// Generate CSRF token
import { randomBytes } from 'crypto'

const csrfToken = randomBytes(32).toString('hex')

// Store in session and send to client
// Verify on state-changing requests

Token Validation

Always validate tokens on protected routes:

const session = await auth.getSessionFromRequest(request)

if (!session.ok) {
  return new Response('Unauthorized', { status: 401 })
}

// Token is valid, proceed

License

MIT