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

authservice-node

v1.0.0

Published

Node.js/Express SDK for Auth Service - Secure backend authentication and permission verification

Readme

Auth Service Node.js SDK

Secure backend SDK for Node.js/Express applications to integrate with the Auth Service. Provides authentication, authorization, and permission checking with built-in security features.

Features

  • 🔐 Secure Request Signing: HMAC-SHA256 request signatures
  • Built-in Caching: Reduce API calls with intelligent caching
  • 🔄 Automatic Retry: Exponential backoff for transient failures
  • 🛡️ Express Middleware: Drop-in middleware for permission checks
  • 📊 Performance Monitoring: Cache statistics and performance metrics
  • 🔍 Type Safety: Full TypeScript support

Installation

npm install @auth-service/node-sdk

Quick Start

const { createAuthService } = require('@auth-service/node-sdk');

// Initialize the SDK
const auth = createAuthService({
  authServiceUrl: 'https://auth.example.com',
  appId: process.env.APP_ID,
  appSecret: process.env.APP_SECRET
});

// Use in Express app
const express = require('express');
const app = express();

// Authenticate all routes
app.use(auth.authenticate());

// Protect specific routes
app.delete('/api/posts/:id', 
  auth.requirePermission('posts:delete'),
  async (req, res) => {
    // User has permission, proceed with deletion
    res.json({ success: true });
  }
);

Configuration

const auth = createAuthService({
  // Required
  authServiceUrl: 'https://auth.example.com',
  appId: 'your-app-id',
  appSecret: 'your-app-secret',
  
  // Optional
  cacheEnabled: true,      // Enable permission caching (default: true)
  cacheTTL: 60,           // Cache TTL in seconds (default: 60)
  timeout: 10000,         // Request timeout in ms (default: 10000)
  retryAttempts: 3,       // Number of retry attempts (default: 3)
  retryDelay: 1000        // Initial retry delay in ms (default: 1000)
});

Middleware Usage

Authentication Middleware

Validates user tokens and populates req.user:

// Authenticate all routes
app.use(auth.authenticate());

// Access user info in routes
app.get('/profile', (req, res) => {
  res.json({
    userId: req.user.id,
    permissions: req.user.permissions,
    roles: req.user.roles
  });
});

Permission Middleware

Single Permission

app.post('/api/posts', 
  auth.requirePermission('posts:create'),
  createPostHandler
);

Multiple Permissions (ANY)

app.put('/api/posts/:id',
  auth.requireAnyPermission(['posts:edit', 'posts:admin']),
  updatePostHandler
);

Multiple Permissions (ALL)

app.delete('/api/users/:id',
  auth.requireAllPermissions(['users:delete', 'admin:access']),
  deleteUserHandler
);

Middleware Options

app.delete('/api/posts/:id',
  auth.requirePermission('posts:delete', {
    failureStatusCode: 403,     // Custom status code
    failureMessage: 'Not authorized to delete posts',
    onPermissionDenied: (req, permission) => {
      // Log permission denial
      console.log(`User ${req.user.id} denied ${permission}`);
    }
  }),
  deletePostHandler
);

Direct Client Usage

For more control, use the client directly:

const { client } = auth;

// Get user permissions
const permissions = await client.getUserPermissions(userToken);

// Check single permission
const result = await client.checkPermission({
  userToken: token,
  permission: 'posts:delete',
  context: {
    ip: req.ip,
    userAgent: req.get('user-agent')
  }
});

// Check multiple permissions
const results = await client.checkPermissions({
  userToken: token,
  permissions: ['posts:create', 'posts:edit', 'posts:delete']
});

// Convenience methods
const hasAny = await client.hasAnyPermission(token, ['admin', 'moderator']);
const hasAll = await client.hasAllPermissions(token, ['posts:read', 'posts:write']);

Caching

The SDK includes intelligent caching to reduce API calls:

// Invalidate cache for a user
auth.invalidateCache(userId);

// Clear entire cache
auth.client.clearCache();

// Get cache statistics
const stats = auth.client.getCacheStats();
console.log(`Cache hit rate: ${stats.hitRate * 100}%`);

Error Handling

The SDK provides detailed error types:

const { AuthServiceError, TokenError, PermissionError } = require('@auth-service/node-sdk');

app.use(async (req, res, next) => {
  try {
    await auth.requirePermission('admin:access')(req, res, next);
  } catch (error) {
    if (error instanceof TokenError) {
      // Handle token errors (expired, invalid)
      res.status(401).json({ error: 'Invalid token' });
    } else if (error instanceof PermissionError) {
      // Handle permission errors
      res.status(403).json({ 
        error: 'Permission denied',
        required: error.details.requiredPermissions 
      });
    } else {
      // Handle other errors
      res.status(500).json({ error: 'Internal error' });
    }
  }
});

Webhook Verification

Verify webhooks from the Auth Service:

app.post('/webhooks/auth', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const timestamp = req.headers['x-webhook-timestamp'];
  
  if (!auth.verifyWebhook(signature, timestamp, req.body)) {
    return res.status(401).json({ error: 'Invalid webhook signature' });
  }
  
  // Process webhook
  switch (req.body.event) {
    case 'user.created':
      // Handle new user
      break;
    case 'permission.changed':
      // Invalidate cache for user
      auth.invalidateCache(req.body.userId);
      break;
  }
  
  res.json({ received: true });
});

Advanced Usage

Custom Token Extraction

// The SDK automatically extracts tokens from:
// - Authorization: Bearer <token>
// - X-Access-Token: <token>
// - Query parameter: ?access_token=<token>

// For custom extraction, use the client directly
app.use(async (req, res, next) => {
  const token = req.cookies.authToken; // Custom extraction
  
  if (token) {
    const permissions = await auth.client.getUserPermissions(token);
    req.user = { permissions };
  }
  
  next();
});

Permission Guards in Route Handlers

const canDelete = auth.middleware.createPermissionGuard('posts:delete');

app.delete('/api/posts/:id', auth.authenticate(), async (req, res) => {
  // Check permission inside handler
  if (!await canDelete(req)) {
    return res.status(403).json({ error: 'Cannot delete post' });
  }
  
  // Additional business logic checks
  const post = await getPost(req.params.id);
  if (post.authorId !== req.user.id && !await canDelete(req)) {
    return res.status(403).json({ error: 'Not your post' });
  }
  
  // Delete the post
  await deletePost(req.params.id);
  res.json({ success: true });
});

Conditional Middleware

// Optional permission check - doesn't block request
app.get('/api/posts',
  auth.middleware.checkPermission('posts:admin'),
  async (req, res) => {
    const isAdmin = req.authContext?.hasPermission?.['posts:admin'];
    
    // Return different data based on permissions
    const posts = isAdmin 
      ? await getAllPosts() 
      : await getPublicPosts();
      
    res.json(posts);
  }
);

Best Practices

  1. Always verify permissions server-side - Never trust client-side checks
  2. Use caching wisely - Balance between performance and data freshness
  3. Handle errors gracefully - Provide clear error messages
  4. Monitor performance - Use cache statistics to optimize
  5. Secure your credentials - Never expose appSecret in client code
  6. Use specific permissions - Prefer posts:delete over generic admin

Troubleshooting

Common Issues

  1. "Invalid signature" errors

    • Ensure your system clock is synchronized
    • Verify appId and appSecret are correct
    • Check that authServiceUrl doesn't have trailing slash
  2. Cache not working

    • Verify cacheEnabled is true
    • Check cache statistics with getCacheStats()
    • Ensure unique user IDs in tokens
  3. Permissions always denied

    • Verify token includes correct appId
    • Check user has required roles assigned
    • Ensure permissions exist in the system

Debug Mode

Enable debug logging:

const auth = createAuthService({
  // ... config
  debug: true  // Logs all API calls and cache operations
});

TypeScript Support

Full TypeScript support with type definitions:

import { createAuthService, AuthenticatedRequest } from '@auth-service/node-sdk';

const auth = createAuthService({
  authServiceUrl: process.env.AUTH_SERVICE_URL!,
  appId: process.env.APP_ID!,
  appSecret: process.env.APP_SECRET!
});

app.get('/profile', auth.authenticate(), (req: AuthenticatedRequest, res) => {
  // req.user is fully typed
  res.json({
    id: req.user!.id,
    permissions: req.user!.permissions
  });
});

License

MIT