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

nitro-oidc-auth

v0.0.1

Published

OpenID Connect (OIDC) authentication for Nitro

Readme

Nitro OIDC Auth

🔐 Enterprise-grade OpenID Connect (OIDC) authentication module for Nitro applications.

Features

Core Features

  • 🔐 OpenID Connect - Standard OIDC authentication flow (Authorization Code + PKCE)
  • 🔒 PKCE Support - Proof Key for Code Exchange for enhanced security (public & confidential clients)
  • 🔄 Auto Token Refresh - Automatic access token refresh before expiration
  • 🍪 Session Management - Encrypted, production-ready session storage
  • 🎯 Type Safe - Full TypeScript support with auto-generated types
  • 🚀 Easy Integration - Simple setup with sensible defaults
  • 🌐 Provider Agnostic - Works with any OIDC-compliant provider

🛡️ Enterprise Security Features (NEW!)

  • ID Token Signature Verification - JWKS-based JWT validation
  • Encrypted Session Storage - AES-256-GCM encryption with Unstorage drivers
  • Cryptographically Secure Random - Web Crypto API for all random generation
  • Nonce Parameter - ID token replay attack protection
  • Refresh Token Rotation - OAuth 2.1 best practices (coming soon)
  • Session Fixation Protection - Session ID regeneration after login (coming soon)
  • Audit Logging - Security event logging for compliance
  • Configurable Storage Drivers - Memory, Redis, Cloudflare KV, MongoDB, etc.
  • Claims Validation - Issuer, audience, expiration, email verification

Installation

pnpm add nitro-oidc-auth

Quick Start

1. Configure Nitro

For Confidential Clients (Recommended for server-side):

// nitro.config.ts
import { defineNitroConfig } from 'nitropack/config'

export default defineNitroConfig({
  modules: ['nitro-oidc-auth'],
  oidc: {
    issuer: 'https://your-provider.com',
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    redirectUri: 'http://localhost:3000/auth/callback',
  },
})

For Public Clients (PKCE enabled):

export default defineNitroConfig({
  modules: ['nitro-oidc-auth'],
  oidc: {
    issuer: 'https://your-provider.com',
    clientId: 'your-client-id',
    // No clientSecret needed - PKCE is used for security
    redirectUri: 'http://localhost:3000/auth/callback',
  },
})

2. Protect Your Routes

// routes/api/protected.ts
export default defineEventHandler(async (event) => {
  const user = requireAuth(event)

  return {
    message: `Hello, ${user.name}!`,
    user,
  }
})

3. Optional Authentication

// routes/api/optional.ts
export default defineEventHandler(async (event) => {
  const user = useAuth(event)

  if (user) {
    return { message: `Welcome back, ${user.name}!` }
  }

  return { message: 'Hello, guest!' }
})

Configuration

Basic Configuration

export default defineNitroConfig({
  oidc: {
    // Required
    issuer: 'https://your-provider.com',
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    redirectUri: 'http://localhost:3000/auth/callback',

    // Optional
    postLogoutRedirectUri: 'http://localhost:3000',
    scopes: ['openid', 'profile', 'email'],
    basePath: '/auth',
  },
})

🔐 Production-Ready Configuration (Recommended)

export default defineNitroConfig({
  oidc: {
    // Provider Configuration
    issuer: process.env.OIDC_ISSUER,
    clientId: process.env.OIDC_CLIENT_ID,
    clientSecret: process.env.OIDC_CLIENT_SECRET,
    redirectUri: process.env.OIDC_REDIRECT_URI,

    // Session Storage (Production)
    sessionStorage: {
      driver: 'redis',
      options: {
        base: 'oidc:',
        url: process.env.REDIS_URL,
      },
      encryption: true,
      encryptionSecret: process.env.SESSION_SECRET, // Strong secret!
    },

    // Security Features
    security: {
      nonce: true,                        // ID token replay protection
      refreshTokenRotation: true,          // OAuth 2.1 best practice
      sessionFixationProtection: true,     // Regenerate session ID after login
      auditLog: true,                      // Log security events

      // Rate Limiting (optional)
      rateLimiting: {
        enabled: true,
        maxAttempts: 5,
        windowMs: 15 * 60 * 1000,         // 15 minutes
      },
    },

    // Token Validation
    tokenValidation: {
      algorithms: ['RS256', 'ES256'],     // Allowed algorithms
      verifySignature: true,               // JWKS verification
      validateClaims: true,                // Issuer, audience, exp
      requireEmailVerified: false,         // Strict email verification
    },

    // Token Options
    usePKCE: true,
    refreshThreshold: 300,                 // 5 minutes before expiry
  },
})

Session Storage Drivers

The module supports multiple storage backends via Unstorage:

Memory (Default - Development Only)

sessionStorage: {
  driver: 'memory',
}

Redis (Recommended for Production)

sessionStorage: {
  driver: 'redis',
  options: {
    base: 'oidc:sessions:',
    url: 'redis://localhost:6379',
    // or
    host: 'localhost',
    port: 6379,
    password: 'your-password',
  },
  encryption: true,
}

Cloudflare KV

sessionStorage: {
  driver: 'cloudflare-kv-binding',
  options: {
    binding: 'MY_KV_NAMESPACE',
  },
  encryption: true,
}

MongoDB

sessionStorage: {
  driver: 'mongodb',
  options: {
    connectionString: process.env.MONGODB_URL,
    databaseName: 'auth',
    collectionName: 'sessions',
  },
  encryption: true,
}

Filesystem (Not recommended for production)

sessionStorage: {
  driver: 'fs',
  options: {
    base: './.data/sessions',
  },
  encryption: true,
}

Advanced Configuration

For custom provider endpoints (if not using standard discovery):

export default defineNitroConfig({
  oidc: {
    // ... basic config
    providerConfig: {
      authorizationEndpoint: 'https://provider.com/oauth/authorize',
      tokenEndpoint: 'https://provider.com/oauth/token',
      userinfoEndpoint: 'https://provider.com/oauth/userinfo',
      endSessionEndpoint: 'https://provider.com/oauth/logout',
      jwksUri: 'https://provider.com/.well-known/jwks.json',
    },
  },
})

Authentication Flow

1. Login

Direct users to /auth/login to start authentication:

<a href="/auth/login">Login</a>

Or with a return URL:

<a href="/auth/login?returnTo=/dashboard">Login</a>

2. Callback

Users are redirected to /auth/callback after authentication. This is handled automatically.

3. Logout

Direct users to /auth/logout to end their session:

<a href="/auth/logout">Logout</a>

4. User Info

Get current user info at /auth/me:

const response = await $fetch('/auth/me')
console.log(response.user)

Helper Functions

Auto-imported helpers for easy authentication checks:

requireAuth(event)

Require authentication - throws 401 if not authenticated:

export default defineEventHandler(async (event) => {
  const user = requireAuth(event)
  // User is guaranteed to be authenticated here
  return { user }
})

useAuth(event)

Optional authentication - returns user or undefined:

export default defineEventHandler(async (event) => {
  const user = useAuth(event)
  if (user) {
    return { authenticated: true, user }
  }
  return { authenticated: false }
})

isAuthenticated(event)

Check if user is authenticated:

export default defineEventHandler(async (event) => {
  if (isAuthenticated(event)) {
    return { status: 'logged in' }
  }
  return { status: 'guest' }
})

useAccessToken(event)

Get the access token for API calls:

export default defineEventHandler(async (event) => {
  const token = useAccessToken(event)

  // Use token to call external APIs
  const data = await $fetch('https://api.example.com/data', {
    headers: {
      Authorization: `Bearer ${token}`,
    },
  })

  return data
})

User Object

The user object contains claims from the ID token:

interface OIDCUser {
  sub: string                    // User ID
  name?: string                  // Full name
  email?: string                 // Email address
  email_verified?: boolean       // Email verification status
  preferred_username?: string    // Username
  picture?: string               // Profile picture URL
  given_name?: string            // First name
  family_name?: string           // Last name
  locale?: string                // User locale
  [key: string]: any             // Additional provider-specific claims
}

Provider Examples

Keycloak

export default defineNitroConfig({
  oidc: {
    issuer: 'https://keycloak.example.com/realms/your-realm',
    clientId: 'your-client',
    clientSecret: 'your-secret',
    redirectUri: 'http://localhost:3000/auth/callback',
  },
})

Auth0

export default defineNitroConfig({
  oidc: {
    issuer: 'https://your-tenant.auth0.com',
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    redirectUri: 'http://localhost:3000/auth/callback',
  },
})

Azure AD

export default defineNitroConfig({
  oidc: {
    issuer: 'https://login.microsoftonline.com/your-tenant-id/v2.0',
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    redirectUri: 'http://localhost:3000/auth/callback',
    scopes: ['openid', 'profile', 'email', 'offline_access'],
  },
})

Google

export default defineNitroConfig({
  oidc: {
    issuer: 'https://accounts.google.com',
    clientId: 'your-client-id.apps.googleusercontent.com',
    clientSecret: 'your-client-secret',
    redirectUri: 'http://localhost:3000/auth/callback',
  },
})

Routes

The module automatically registers these routes:

| Route | Method | Description | |-------|--------|-------------| | /auth/login | GET | Initiates OIDC authentication flow | | /auth/callback | GET | Handles OIDC callback and creates session | | /auth/logout | GET | Ends session and redirects to provider logout | | /auth/me | GET | Returns current user info (requires authentication) |

Note: The base path /auth can be customized via the basePath configuration option.

Session Management

Sessions are stored in-memory and identified by secure HTTP-only cookies. The session includes:

  • User information from ID token
  • Access token for API calls
  • Refresh token (if provided)
  • Token expiration information

Automatic Token Refresh

The module automatically refreshes access tokens when they're close to expiring (configurable via refreshThreshold). This happens transparently in the middleware.

🛡️ Security Features

Implemented Security Best Practices

PKCE (RFC 7636): Proof Key for Code Exchange enabled by default for all clients ✅ State Parameter: CSRF protection via cryptographically secure state validation ✅ Nonce Parameter: ID token replay attack protection ✅ ID Token Signature Verification: JWKS-based JWT validation with jose library ✅ Claims Validation: Issuer (iss), audience (aud), expiration (exp), email_verified ✅ Encrypted Sessions: AES-256-GCM encryption for session data ✅ Cryptographically Secure Random: Web Crypto API for all random generation (128-192 bits) ✅ Secure Cookies: HTTP-only, Secure (in production), SameSite=Lax/Strict ✅ Automatic Token Refresh: Seamless access token renewal before expiration ✅ Session Expiration: Configurable TTL with automatic cleanup ✅ Audit Logging: Security event logging for compliance

OAuth 2.1 & OIDC Compliance

  • ✅ Authorization Code Flow with PKCE
  • ✅ Refresh token support
  • ✅ Provider discovery (.well-known/openid-configuration)
  • ✅ Dynamic client registration support
  • 🔄 Refresh token rotation (coming soon)
  • 🔄 Session fixation protection (coming soon)
  • 🔄 DPoP token binding (planned)

Security Headers & Cookies

All session cookies are set with:

  • HttpOnly: Prevents JavaScript access (XSS protection)
  • Secure: HTTPS-only in production
  • SameSite: Lax or Strict (CSRF protection)
  • Short TTL with automatic cleanup

Audit Logging

When security.auditLog is enabled, the following events are logged:

// Login events
AUDIT: Login initiated
AUDIT: User logged in { userId, email, timestamp }
AUDIT: Login failed { error, timestamp }

// Token events
AUDIT: Token refreshed { userId, timestamp }
AUDIT: Token refresh failed { error, timestamp }

// Logout events
AUDIT: User logged out { userId, timestamp }

TypeScript Support

Full TypeScript support with type definitions for all configuration options and user data:

import type { OIDCConfig, OIDCUser, OIDCSession } from 'nitro-oidc-auth'

The module also extends H3's event context:

declare module 'h3' {
  interface H3EventContext {
    oidc?: {
      session?: OIDCSession
      user?: OIDCUser
    }
  }
}

Environment Variables

You can also configure OIDC using environment variables in production:

NUXT_OIDC_ISSUER=https://your-provider.com
NUXT_OIDC_CLIENT_ID=your-client-id
NUXT_OIDC_CLIENT_SECRET=your-client-secret
NUXT_OIDC_REDIRECT_URI=https://your-app.com/auth/callback

Development

# Install dependencies
pnpm install

# Build module
pnpm build

# Watch mode
pnpm dev

# Lint
pnpm lint
pnpm lint:fix

License

MIT License