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

@carisls/sso-resource-api

v1.3.0

Published

A middleware implementing resource api SSO

Readme

@carisls/sso-resource-api

A middleware implementing resource API SSO for Express.js applications. This package validates JWT tokens from Authorization headers and injects user information into requests. Perfect for API servers that receive tokens from authenticated clients.

Features

  • 🔐 JWT token validation from Authorization headers
  • 🔑 JWKS-based public key validation with caching
  • 👤 User token mapping and request injection
  • 🛡️ Built-in authorization middleware
  • 🌐 Multi-provider support (Keycloak, Okta, and other OIDC providers)
  • 📦 Supports both ESM and CommonJS
  • ⚡ Lightweight and performant
  • 🔒 Automatic token validation on each request

Installation

npm install @carisls/sso-resource-api

Quick Start

ESM (ECMAScript Modules)

import express from 'express';
import { router } from '@carisls/sso-resource-api';

const app = express();

app.use(router({
  // Simple format: comma-separated string
  providers: 'https://auth.example.com',
  // Or array format: providers: [{ ssoUrl: 'https://auth.example.com' }],
}));

// Protected route - user is automatically available via req.user
app.get('/api/data', (req, res) => {
  if (!req.user) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  res.json({ message: 'Protected data', user: req.user });
});

app.listen(3000);

CommonJS

const express = require('express');
const { router } = require('@carisls/sso-resource-api');

const app = express();

app.use(router({
  // Simple format: comma-separated string
  providers: 'https://auth.example.com',
  // Or array format: providers: [{ ssoUrl: 'https://auth.example.com' }],
}));

// Protected route - user is automatically available via req.user
app.get('/api/data', (req, res) => {
  if (!req.user) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  res.json({ message: 'Protected data', user: req.user });
});

app.listen(3000);

API Reference

router(options)

Creates Express middleware that validates JWT tokens from Authorization headers and injects user information into requests.

Parameters:

  • options (Object): Configuration object with the following properties:
    • providers (string | Array, required): Provider configuration(s). Can be:
      • A comma-separated string of provider URLs (e.g., 'https://auth1.example.com,https://auth2.example.com')
      • An array of provider configuration objects:
        • ssoUrl (string): Base URL for the provider (usually equal to iss). Used to discover OpenID Connect configuration
        • iss (string, optional): Issuer identifier. If not provided, defaults to ssoUrl
        • publicKey (string, optional): Static public key in PEM format (if not using JWKS)
    • publicKeyCache (number, optional): Public key caching expiration in seconds (default: 300)
    • expOffset (number, optional): Force renewal of tokens earlier (in seconds) to handle clock skew issues (default: 0)
    • userMapper (function, optional): Custom function to map tokens to user object. Signature: (token) => userObject

Returns: Express middleware function (req, res, next) => void

The middleware:

  • Validates JWT tokens from Authorization: Bearer <token> headers
  • On successful validation, sets req.user with user information
  • On failed validation, logs error but continues (does not block request - you can check req.user in your routes)
  • Sets req.token with the validated token

Example:

import express from 'express';
import { router } from '@carisls/sso-resource-api';

const app = express();

app.use(router({
  // Simple format: comma-separated string (iss defaults to ssoUrl)
  providers: 'https://auth.example.com',
  // Or detailed format: array of objects
  // providers: [
  //   {
  //     ssoUrl: 'https://auth.example.com',
  //     // iss defaults to ssoUrl if not provided
  //   }
  // ],
  publicKeyCache: 600,
  userMapper: (token) => {
    return {
      id: token.sub,
      email: token.email,
      name: token.name,
      roles: token.roles || []
    };
  }
}));

// Protected route - check req.user to verify authentication
app.get('/api/users', (req, res) => {
  if (!req.user) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  res.json({ users: [], user: req.user });
});

// Access token in route
app.get('/api/profile', (req, res) => {
  if (!req.user) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  res.json({ 
    user: req.user,
    token: req.token // Access the validated token if needed
  });
});

app.listen(3000);

authorize(role, exceptions, redirectToLogin)

Express.js middleware for authorization filtering based on user roles. This middleware works in conjunction with the router to provide role-based access control.

Parameters:

  • role (string | string[] | undefined, optional): Role(s) to filter by. If undefined, only checks for authenticated user.
  • exceptions (string[] | undefined, optional): Array of URL paths to skip authorization checks.
  • redirectToLogin (boolean, default: false): If true, redirects to login page instead of returning 401.

Returns: Express middleware function (req, res, next) => void

Example:

import express from 'express';
import { router, authorize } from '@carisls/sso-resource-api';

const app = express();

// Setup SSO router
app.use(router({
  // Simple format: comma-separated string
  providers: 'https://auth.example.com',
  // Or array format: providers: [{ ssoUrl: 'https://auth.example.com' }],
}));

// Require any authenticated user
app.use(authorize());

// Require specific role
app.get('/api/admin', authorize('admin'), (req, res) => {
  res.json({ message: 'Admin access granted', user: req.user });
});

// Require one of multiple roles
app.get('/api/dashboard', authorize(['admin', 'user']), (req, res) => {
  res.json({ message: 'Dashboard access', user: req.user });
});

// With exceptions and redirect
app.use(authorize('user', ['/api/public', '/api/health'], false));

app.listen(3000);

Complete Example

import express from 'express';
import { router, authorize } from '@carisls/sso-resource-api';

const app = express();

// Configure SSO middleware
app.use(router({
  // Simple format: comma-separated string (iss defaults to ssoUrl)
  providers: process.env.SSO_URL,
  // Or array format with custom iss:
  // providers: [
  //   {
  //     ssoUrl: process.env.SSO_URL,
  //     iss: process.env.SSO_ISSUER // optional, defaults to ssoUrl
  //   }
  // ],
  publicKeyCache: 600
}));

// Public routes (no authentication required)
app.get('/api/health', (req, res) => {
  res.json({ status: 'ok' });
});

// Protected routes - require authentication
app.get('/api/dashboard', authorize(), (req, res) => {
  res.json({
    message: 'Dashboard',
    user: req.user
  });
});

// Admin routes - require admin role
app.get('/api/admin', authorize('admin'), (req, res) => {
  res.json({
    message: 'Admin panel',
    user: req.user
  });
});

// API routes with role-based access
app.get('/api/users', authorize(['admin', 'user-manager']), (req, res) => {
  res.json({ users: [] });
});

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

How It Works

  1. Token Validation: On each request, the middleware checks for an Authorization: Bearer <token> header.

  2. Token Parsing: If present, the token is extracted from the header.

  3. Token Validation: The token is validated against the configured identity provider(s) using JWKS:

    • The issuer is identified from the token
    • The appropriate provider's public key is fetched and cached
    • Token signature, expiration, and issuer are validated
  4. User Injection: On successful validation:

    • req.user is set with user information (mapped from the token)
    • req.token is set with the validated token
  5. Error Handling: On validation failure, an error is logged but the request continues. Your routes should check req.user to determine if authentication was successful.

Supported Providers

This package works with any OIDC-compliant identity provider, including:

  • Keycloak
  • Okta
  • Auth0
  • Azure AD
  • Google Identity Platform
  • Any other OIDC/OAuth2 provider

User Object Structure

By default, the req.user object follows this structure (can be customized with userMapper):

{
  iss: string;              // Issuer
  id: string;               // User ID (from 'sub')
  sid?: string;             // Session ID
  sa: boolean;              // Service account flag
  azp?: string;             // Authorized party
  name?: {                  // Name object (if available)
    full: string;
    familyName: string;
    givenName: string;
  };
  email?: string;           // Email (if available)
  roles: string[];          // User roles
}

Environment Variables

For production use, store sensitive values in environment variables:

SSO_URL=https://auth.example.com
SSO_ISSUER=https://auth.example.com

Security Considerations

  • Token Validation: All tokens are validated using JWKS before use
  • Public Key Caching: Public keys are cached to reduce network requests and improve performance
  • No Token Storage: This package does not store tokens - it only validates them from request headers
  • Authorization Header: Tokens must be sent in the standard Authorization: Bearer <token> format

Differences from @carisls/sso-standard

This package is designed for resource API servers that receive tokens from authenticated clients:

  • ✅ Validates tokens from Authorization headers
  • ✅ No login/logout flows (handled by client)
  • ✅ No cookie management
  • ✅ Lightweight and focused on token validation
  • ✅ Perfect for microservices and API gateways

Use @carisls/sso-standard if you need:

  • Complete OAuth2 authorization code flow
  • Cookie-based session management
  • Login/logout endpoints
  • Automatic token refresh

Dependencies

  • @carisls/sso-core: Core SSO utilities (token validation, issuer selection, etc.)

License

MIT

Author

Mihovil Strujic [email protected]