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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@autolabz/service-auth-nextjs

v1.0.3

Published

Next.js App Router authentication utilities for AutoLab services

Readme

@autolabz/service-auth-nextjs

Next.js App Router authentication utilities for AutoLab services.

Overview

This package provides authentication utilities specifically designed for Next.js App Router applications, built on the framework-agnostic @autolabz/service-auth-core. It offers:

  • Request Verification: Verify incoming requests using JWT or OAuth userinfo fallback
  • Scope Validation: Check for required scopes before processing requests
  • AuthBridge Creation: Generate AuthBridge objects for downstream SDK calls
  • Type-Safe: Full TypeScript support with discriminated union return types

Installation

npm install @autolabz/service-auth-nextjs

Quick Start

Basic Request Verification

import { verifyRequest, type AuthConfig } from '@autolabz/service-auth-nextjs';

const authConfig: AuthConfig = {
  jwtAlg: 'HS256',
  jwtAccessSecret: process.env.JWT_ACCESS_SECRET,
  authBaseUrl: process.env.AUTH_BASE_URL!,
  oauthUserinfoPath: '/oauth/userinfo',
  oauthUserinfoTimeoutMs: 2000,
};

// In your API route (app/api/hello/route.ts)
export async function GET(request: Request) {
  const result = await verifyRequest(request, authConfig);
  
  if (!result.success) {
    return Response.json({ error: result.error }, { status: 401 });
  }

  return Response.json({
    message: `Hello, ${result.auth.email || result.auth.userId}!`,
  });
}

Request Verification with Scope Check

import { verifyRequestWithScopes } from '@autolabz/service-auth-nextjs';

export async function GET(request: Request) {
  // Require both 'data' and 'points' scopes
  const result = await verifyRequestWithScopes(request, authConfig, ['data', 'points']);
  
  if (!result.success) {
    const status = result.error === 'Insufficient scopes' ? 403 : 401;
    return Response.json({ error: result.error }, { status });
  }

  return Response.json({ userId: result.auth.userId });
}

Using with Downstream Services

import { verifyRequest, makeAuthBridge } from '@autolabz/service-auth-nextjs';
import { createDataClient } from '@autolabz/data-sdk';
import { createPointsClient } from '@autolabz/points-sdk';
import { createLLMClient } from '@autolabz/llmapi-sdk';

export async function GET(request: Request) {
  // 1. Verify the request
  const authResult = await verifyRequest(request, authConfig);
  if (!authResult.success) {
    return Response.json({ error: authResult.error }, { status: 401 });
  }

  // 2. Create AuthBridge for downstream calls
  const auth = makeAuthBridge(request, {
    onUnauthorized: () => console.error('Downstream service returned 401'),
  });

  // 3. Use with SDK clients
  const dataClient = createDataClient({
    baseURL: process.env.DATA_BASE_URL!,
    auth,
  });

  const pointsClient = createPointsClient({
    baseURL: process.env.POINTS_BASE_URL!,
    auth,
  });

  // 4. Make authenticated requests
  const [userData, balance] = await Promise.all([
    dataClient.get(`/v1/data/user-profile`),
    pointsClient.getMyBalance(),
  ]);

  return Response.json({ userData, balance });
}

API Reference

verifyRequest(request: Request, config: AuthConfig): Promise<AuthResult>

Verify an incoming Next.js request using JWT verification (SIMPLE mode) with OAuth userinfo fallback.

Parameters:

  • request: Next.js Request object (Web API Request)
  • config: Authentication configuration

Returns: AuthResult

  • On success: { success: true, auth: AuthPayload }
  • On failure: { success: false, error: string }

verifyRequestWithScopes(request: Request, config: AuthConfig, requiredScopes: string[]): Promise<AuthResult>

Verify a request and check for required scopes.

Parameters:

  • request: Next.js Request object
  • config: Authentication configuration
  • requiredScopes: Array of required scope strings

Returns: AuthResult

  • On success: { success: true, auth: AuthPayload }
  • On failure: { success: false, error: string } (error can be 'Insufficient scopes')

makeAuthBridge(request: Request, options?: AuthBridgeOptions): AuthBridgeLike

Create an AuthBridge from a Next.js Request for use with AutoLab SDK clients.

Parameters:

  • request: Next.js Request object
  • options: Optional configuration
    • onUnauthorized?: () => void: Callback when downstream service returns 401

Returns: AuthBridgeLike object compatible with SDK clients

Configuration

AuthConfig

interface AuthConfig {
  // JWT verification (SIMPLE mode)
  jwtAlg: 'HS256' | 'RS256';
  jwtAccessSecret?: string;        // Required for HS256
  jwksUrl?: string;                 // Required for RS256
  authIssuer?: string;              // Optional issuer validation

  // OAuth userinfo fallback
  authBaseUrl: string;              // OAuth service base URL
  oauthUserinfoPath?: string;       // Default: 'oauth/userinfo'
  oauthUserinfoTimeoutMs?: number;  // Default: 2000
  oauthExpectedAudience?: string;   // Optional audience validation
}

Type Definitions

AuthResult

Discriminated union type for authentication results:

type AuthResult =
  | { success: true; auth: AuthPayload }
  | { success: false; error: string };

AuthPayload

interface AuthPayload {
  userId: string;
  sub?: string;
  email?: string;
  iat?: number;
  exp?: number;
  iss?: string;
  aud?: string | string[];
  azp?: string;
  scope?: string;
  tokenType?: string;
}

Complete Example: API Route

// app/api/data/[key]/route.ts
import { verifyRequestWithScopes, makeAuthBridge } from '@autolabz/service-auth-nextjs';
import { createDataClient } from '@autolabz/data-sdk';

const authConfig = {
  jwtAlg: 'HS256' as const,
  jwtAccessSecret: process.env.JWT_ACCESS_SECRET!,
  authBaseUrl: process.env.AUTH_BASE_URL!,
  oauthUserinfoPath: '/oauth/userinfo',
  oauthUserinfoTimeoutMs: 2000,
};

export async function GET(
  request: Request,
  { params }: { params: { key: string } }
) {
  // Verify with required scope
  const result = await verifyRequestWithScopes(request, authConfig, ['data']);
  
  if (!result.success) {
    const status = result.error === 'Insufficient scopes' ? 403 : 401;
    return Response.json({ error: result.error }, { status });
  }

  // Create auth bridge for downstream call
  const auth = makeAuthBridge(request);
  const dataClient = createDataClient({
    baseURL: process.env.DATA_BASE_URL!,
    auth,
  });

  try {
    const data = await dataClient.get(`/v1/data/${encodeURIComponent(params.key)}`);
    return Response.json(data);
  } catch (error) {
    return Response.json(
      { error: 'Failed to fetch data' },
      { status: 500 }
    );
  }
}

export async function PUT(
  request: Request,
  { params }: { params: { key: string } }
) {
  const result = await verifyRequestWithScopes(request, authConfig, ['data']);
  
  if (!result.success) {
    const status = result.error === 'Insufficient scopes' ? 403 : 401;
    return Response.json({ error: result.error }, { status });
  }

  const auth = makeAuthBridge(request);
  const dataClient = createDataClient({
    baseURL: process.env.DATA_BASE_URL!,
    auth,
  });

  const body = await request.json();
  
  try {
    await dataClient.put(`/v1/data/${encodeURIComponent(params.key)}`, body);
    return Response.json({ success: true });
  } catch (error) {
    return Response.json(
      { error: 'Failed to update data' },
      { status: 500 }
    );
  }
}

Environment Variables

# JWT verification (SIMPLE mode)
JWT_ALG=HS256
JWT_ACCESS_SECRET=your-secret

# OAuth userinfo fallback
AUTH_BASE_URL=http://auth-service/api
OAUTH_USERINFO_PATH=/oauth/userinfo
OAUTH_USERINFO_TIMEOUT_MS=2000

# Optional
AUTH_ISSUER=https://auth.example.com
OAUTH_EXPECTED_AUDIENCE=autolab-api

# Downstream services
DATA_BASE_URL=http://data-service
POINTS_BASE_URL=http://points-service
LLMAPI_BASE_URL=http://llmapi-service

Middleware Pattern

For route-wide authentication, you can create a middleware wrapper:

// lib/auth-middleware.ts
import { verifyRequest, type AuthConfig, type AuthPayload } from '@autolabz/service-auth-nextjs';

export function withAuth(
  handler: (request: Request, auth: AuthPayload, ...args: any[]) => Promise<Response>
) {
  return async (request: Request, ...args: any[]) => {
    const authConfig: AuthConfig = {
      jwtAlg: 'HS256',
      jwtAccessSecret: process.env.JWT_ACCESS_SECRET!,
      authBaseUrl: process.env.AUTH_BASE_URL!,
    };

    const result = await verifyRequest(request, authConfig);
    
    if (!result.success) {
      return Response.json({ error: result.error }, { status: 401 });
    }

    return handler(request, result.auth, ...args);
  };
}

// Usage in route
export const GET = withAuth(async (request, auth) => {
  return Response.json({ userId: auth.userId });
});

Best Practices

  1. Configuration: Store AuthConfig in a central location and reuse across routes
  2. Error Handling: Always check result.success before accessing result.auth
  3. Scope Validation: Use verifyRequestWithScopes when endpoints require specific permissions
  4. AuthBridge: Create AuthBridge only after successful verification
  5. Environment Variables: Never hardcode secrets; use environment variables

Troubleshooting

401 Unauthorized

  • Verify AUTH_BASE_URL and OAUTH_USERINFO_PATH are correct
  • Ensure request includes Authorization: Bearer <token> header
  • Check token validity and expiration

403 Insufficient Scopes

  • Verify the token includes all required scopes
  • Check scope configuration in OAuth application settings

Request Timeout

  • Increase oauthUserinfoTimeoutMs value
  • Check auth service performance and network latency

License

MIT