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

@sp-uvb/next

v0.1.0

Published

Next.js middleware for Universal Verification Broker (UVB)

Readme

@sp-uvb/next

Next.js middleware for Universal Verification Broker (UVB) authentication. Supports both App Router and Pages Router.

Installation

npm install @sp-uvb/next
# or
yarn add @sp-uvb/next
# or
pnpm add @sp-uvb/next

Quick Start

App Router (Next.js 13+)

Create middleware.ts in your project root:

import { createUvbMiddleware } from '@sp-uvb/next';

export default createUvbMiddleware({
  tenantId: 'my-tenant',
  uvbUrl: 'http://localhost:8080',
  excludePaths: ['/login', '/api/auth'],
  loginUrl: '/login', // Optional: redirect to login page
});

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};

Access session in Server Components:

import { getUvbSessionServer } from '@sp-uvb/next/server';

export default async function ProfilePage() {
  const session = await getUvbSessionServer();

  return (
    <div>
      <h1>User Profile</h1>
      <p>User ID: {session?.userId}</p>
      <p>Factors: {session?.factorsVerified.join(', ')}</p>
    </div>
  );
}

Pages Router (Next.js 12+)

Protect API routes:

// pages/api/profile.ts
import { requireUvbAuth, getUvbSession } from '@sp-uvb/next/server';

export default requireUvbAuth(async function handler(req, res) {
  const session = getUvbSession(req);
  res.json({
    userId: session.userId,
    factors: session.factorsVerified,
  });
});

API

App Router

createUvbMiddleware(config)

Create Next.js middleware for App Router.

Configuration:

  • tenantId (required): Your UVB tenant ID
  • uvbUrl (optional): UVB server URL, defaults to http://localhost:8080
  • apiKey (optional): API key for server-to-server authentication
  • cookieName (optional): Cookie name for session token, defaults to uvb_session
  • excludePaths (optional): Array of paths to exclude from authentication
  • loginUrl (optional): Redirect URL for unauthenticated users
// middleware.ts
import { createUvbMiddleware } from '@sp-uvb/next';

export default createUvbMiddleware({
  tenantId: 'my-tenant',
  uvbUrl: process.env.UVB_URL,
  loginUrl: '/login',
});

getUvbSessionServer()

Get session in App Router Server Components.

import { getUvbSessionServer } from '@sp-uvb/next/server';

export default async function Page() {
  const session = await getUvbSessionServer();
  if (!session) {
    return <div>Not authenticated</div>;
  }
  return <div>Hello {session.userId}</div>;
}

requireFactors(factors)

Middleware to require specific MFA factors in App Router.

// middleware.ts
import { createUvbMiddleware, requireFactors } from '@sp-uvb/next';
import { NextResponse } from 'next/server';

const uvbMiddleware = createUvbMiddleware({
  tenantId: 'my-tenant',
});

const adminFactors = requireFactors(['totp', 'webauthn']);

export async function middleware(request) {
  // Apply base auth
  const response = await uvbMiddleware(request);
  if (response.status !== 200) return response;

  // Require additional factors for /admin
  if (request.nextUrl.pathname.startsWith('/admin')) {
    return adminFactors(request);
  }

  return NextResponse.next();
}

Pages Router / Server-Side

getUvbSession(req)

Get session from API route or getServerSideProps.

import { getUvbSession } from '@sp-uvb/next/server';

// In API route
export default function handler(req, res) {
  const session = getUvbSession(req);
  if (!session) {
    return res.status(401).json({ error: 'Not authenticated' });
  }
  res.json({ userId: session.userId });
}

// In getServerSideProps
export async function getServerSideProps({ req }) {
  const session = getUvbSession(req);
  if (!session) {
    return { redirect: { destination: '/login', permanent: false } };
  }
  return { props: { session } };
}

requireUvbAuth(handler)

HOF to require authentication for API routes.

import { requireUvbAuth } from '@sp-uvb/next/server';

export default requireUvbAuth(async function handler(req, res) {
  // User is authenticated
  res.json({ message: 'Protected data' });
});

requireFactorsApi(factors)

HOF to require specific MFA factors for API routes.

import { requireFactorsApi } from '@sp-uvb/next/server';

export default requireFactorsApi(['totp', 'webauthn'])(async function handler(req, res) {
  res.json({ message: 'Admin action completed' });
});

validateUvbSession(token, tenantId, uvbUrl?, apiKey?)

Validate a session token directly (for custom flows).

import { validateUvbSession } from '@sp-uvb/next/server';

export default async function handler(req, res) {
  const token = req.cookies.uvb_session;
  const session = await validateUvbSession(token, 'my-tenant', 'http://localhost:8080');

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

  res.json({ userId: session.userId });
}

Examples

Protecting Specific Routes (App Router)

// middleware.ts
import { createUvbMiddleware } from '@sp-uvb/next';

export default createUvbMiddleware({
  tenantId: 'my-tenant',
  excludePaths: ['/login', '/register', '/api/auth', '/public'],
});

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

Conditional MFA Requirements

// middleware.ts
import { createUvbMiddleware, requireFactors } from '@sp-uvb/next';
import { NextResponse } from 'next/server';

const baseAuth = createUvbMiddleware({ tenantId: 'my-tenant' });
const strictAuth = requireFactors(['totp', 'webauthn']);

export async function middleware(request) {
  const response = await baseAuth(request);
  if (response.status !== 200) return response;

  // Require strong auth for sensitive routes
  if (
    request.nextUrl.pathname.startsWith('/admin') ||
    request.nextUrl.pathname.startsWith('/transfer')
  ) {
    return strictAuth(request);
  }

  return NextResponse.next();
}

Server Actions (App Router)

// app/actions.ts
'use server';

import { getUvbSessionServer } from '@sp-uvb/next/server';

export async function updateProfile(formData: FormData) {
  const session = await getUvbSessionServer();

  if (!session) {
    throw new Error('Not authenticated');
  }

  // Update user profile using session.userId
  // ...
}

API Route with Factor Requirements (Pages Router)

// pages/api/admin/delete.ts
import { requireFactorsApi, getUvbSession } from '@sp-uvb/next/server';

export default requireFactorsApi(['totp', 'webauthn'])(async function handler(req, res) {
  const session = getUvbSession(req);

  // Perform admin action
  res.json({ message: `Admin ${session.userId} performed action` });
});

Custom Authentication Flow

// pages/api/custom-auth.ts
import { validateUvbSession } from '@sp-uvb/next/server';

export default async function handler(req, res) {
  const customToken = req.headers['x-custom-token'];

  if (!customToken) {
    return res.status(401).json({ error: 'No token' });
  }

  const session = await validateUvbSession(customToken, 'my-tenant', process.env.UVB_URL);

  if (!session) {
    return res.status(401).json({ error: 'Invalid token' });
  }

  res.json({ userId: session.userId });
}

Redirect After Login

// middleware.ts
import { createUvbMiddleware } from '@sp-uvb/next';

export default createUvbMiddleware({
  tenantId: 'my-tenant',
  loginUrl: '/login' // Redirects to /login?from=/original-path
});

// pages/login.tsx
import { useRouter } from 'next/router';

export default function LoginPage() {
  const router = useRouter();
  const { from } = router.query;

  const handleLogin = async () => {
    // Perform login
    // ...

    // Redirect back to original page
    router.push((from as string) || '/dashboard');
  };

  return <button onClick={handleLogin}>Login</button>;
}

Server Component with Auth Check

// app/profile/page.tsx
import { getUvbSessionServer } from '@sp-uvb/next/server';
import { redirect } from 'next/navigation';

export default async function ProfilePage() {
  const session = await getUvbSessionServer();

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

  // Check for specific factors
  const hasStrongAuth = session.factorsVerified.includes('totp') &&
                        session.factorsVerified.includes('webauthn');

  return (
    <div>
      <h1>Profile</h1>
      <p>User ID: {session.userId}</p>
      <p>Strong Auth: {hasStrongAuth ? 'Yes' : 'No'}</p>
    </div>
  );
}

TypeScript

This package includes full TypeScript definitions:

import type { UvbSession, UvbMiddlewareConfig } from '@sp-uvb/next';

License

MIT