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

@geekmidas/auth

v2.0.0

Published

JWT and OIDC authentication with token verification, Hono middleware, and Lambda authorizers

Readme

@geekmidas/auth

A comprehensive authentication library providing JWT and OIDC token verification, Hono middleware, AWS Lambda authorizers, and client-side token management for TypeScript applications.

Features

  • JWT Verification: Verify tokens using secrets or JWKS endpoints
  • OIDC Support: Auto-discovery from .well-known/openid-configuration
  • Hono Middleware: Ready-to-use middleware for Hono applications
  • Lambda Authorizers: TOKEN and REQUEST authorizers for AWS API Gateway
  • Token Management: Client-side token storage and automatic refresh
  • Type-Safe: Full TypeScript support with generic claims types
  • Multiple Storage Options: LocalStorage, Memory, and Cache-based token storage

Installation

pnpm add @geekmidas/auth

Package Exports

The package provides multiple entry points for different use cases:

  • @geekmidas/auth/jwt - JWT verification
  • @geekmidas/auth/oidc - OIDC verification with auto-discovery
  • @geekmidas/auth/hono/jwt - Hono JWT middleware
  • @geekmidas/auth/hono/oidc - Hono OIDC middleware
  • @geekmidas/auth/lambda/jwt - Lambda JWT authorizer
  • @geekmidas/auth/lambda/oidc - Lambda OIDC authorizer
  • @geekmidas/auth/client - Client-side token management
  • @geekmidas/auth/server - Server-side token management

JWT Verification

Basic Usage

import { JwtVerifier } from '@geekmidas/auth/jwt';
import { EnvironmentParser } from '@geekmidas/envkit';

// Parse environment configuration
const env = new EnvironmentParser(process.env)
  .create((get) => ({
    jwt: {
      secret: get('JWT_SECRET').string(),
      issuer: get('JWT_ISSUER').string().optional(),
      audience: get('JWT_AUDIENCE').string().optional(),
    },
  }))
  .parse();

// With secret (HS256)
const verifier = new JwtVerifier({
  secret: env.jwt.secret,
  issuer: env.jwt.issuer,
  audience: env.jwt.audience,
});

const claims = await verifier.verify(token);
console.log('User:', claims.sub);

// Returns null instead of throwing for invalid tokens
const claimsOrNull = await verifier.verifyOrNull(token);

With JWKS (RS256, ES256, etc.)

import { JwtVerifier } from '@geekmidas/auth/jwt';

const verifier = new JwtVerifier({
  jwksUri: 'https://auth.example.com/.well-known/jwks.json',
  issuer: 'https://auth.example.com',
  audience: 'my-api',
});

const claims = await verifier.verify(token);

Custom Claims Type

interface MyClaims {
  sub: string;
  role: string;
  permissions: string[];
}

const verifier = new JwtVerifier<MyClaims>({
  secret: env.jwt.secret, // From envkit parser
});

const claims = await verifier.verify(token);
console.log('Role:', claims.role); // Typed!

Decode Without Verification

import { decodeJwt } from '@geekmidas/auth/jwt';

// Decode token without verification (useful for debugging)
const claims = decodeJwt(token);

OIDC Verification

OIDC verifier automatically discovers JWKS URI and other configuration from the issuer's .well-known/openid-configuration endpoint.

import { OidcVerifier } from '@geekmidas/auth/oidc';

const verifier = new OidcVerifier({
  issuer: 'https://auth.example.com',
  audience: 'my-client-id',
});

// Verify token (auto-discovers JWKS)
const claims = await verifier.verify(token);

// Fetch user info from userinfo endpoint
const userInfo = await verifier.fetchUserInfo(token);
console.log('Email:', userInfo?.email);

// Get discovery document
const discovery = await verifier.getDiscovery();
console.log('Token endpoint:', discovery.token_endpoint);

Hono Middleware

JWT Middleware

import { Hono } from 'hono';
import { JwtMiddleware } from '@geekmidas/auth/hono/jwt';

const app = new Hono();

const jwt = new JwtMiddleware({
  config: {
    secret: env.jwt.secret,
    issuer: env.jwt.issuer,
  },
  contextKey: 'jwtClaims', // Where to store claims in context
});

// Protected routes
app.use('/api/*', jwt.handler());

app.get('/api/profile', (c) => {
  const claims = c.get('jwtClaims');
  return c.json({ userId: claims.sub });
});

// Optional authentication (doesn't fail if no token)
app.use('/public/*', jwt.optional());

app.get('/public/posts', (c) => {
  const claims = c.get('jwtClaims'); // May be undefined
  return c.json({ authenticated: !!claims });
});

OIDC Middleware

import { OidcMiddleware } from '@geekmidas/auth/hono/oidc';

const oidc = new OidcMiddleware({
  config: {
    issuer: 'https://auth.example.com',
    audience: 'my-client-id',
  },
  fetchUserInfo: true, // Also fetch user info
});

app.use('/api/*', oidc.handler());

app.get('/api/profile', (c) => {
  const claims = c.get('oidcClaims');
  const userInfo = c.get('oidcUserInfo');
  return c.json({ sub: claims.sub, email: userInfo?.email });
});

Custom Error Handling

const jwt = new JwtMiddleware({
  config: { secret: env.jwt.secret },
  onError: (c, error) => {
    console.error('Auth error:', error.message);
    return c.json({ error: 'Authentication failed' }, 401);
  },
});

Token Extraction Options

const jwt = new JwtMiddleware({
  config: { secret: env.jwt.secret },
  extraction: {
    headerName: 'x-auth-token', // Custom header (default: 'authorization')
    tokenPrefix: 'Token ',      // Custom prefix (default: 'Bearer ')
    cookieName: 'auth_token',   // Also check cookies
  },
});

Lambda Authorizers

JWT Authorizer

import { JwtAuthorizer } from '@geekmidas/auth/lambda/jwt';

const authorizer = new JwtAuthorizer({
  config: {
    secret: env.jwt.secret,
    issuer: env.jwt.issuer,
  },
  // Extract principal ID from claims
  getPrincipalId: (claims) => claims.sub ?? 'unknown',
  // Add claims to request context
  getContext: (claims) => ({
    userId: claims.sub!,
    role: claims.role,
  }),
  // Custom authorization logic
  authorize: async (claims) => {
    return claims.role === 'admin';
  },
});

// For TOKEN authorizers (API Gateway v1)
export const tokenHandler = authorizer.tokenHandler();

// For REQUEST authorizers (API Gateway v1/v2)
export const requestHandler = authorizer.requestHandler();

OIDC Authorizer

import { OidcAuthorizer } from '@geekmidas/auth/lambda/oidc';

const authorizer = new OidcAuthorizer({
  config: {
    issuer: 'https://auth.example.com',
    audience: 'my-api',
  },
  getContext: (claims) => ({
    userId: claims.sub!,
    email: claims.email,
  }),
});

export const handler = authorizer.requestHandler();

Token Extraction for REQUEST Authorizers

const authorizer = new JwtAuthorizer({
  config: { secret: env.jwt.secret },
  extraction: {
    headerName: 'authorization',
    tokenPrefix: 'Bearer ',
    cookieName: 'auth_token', // Also check cookies
  },
  // Use specific resource ARN vs wildcard
  wildcardResource: true, // Default: true (enables caching)
});

Client-Side Token Management

Basic Token Client

import { TokenClient, LocalStorageTokenStorage } from '@geekmidas/auth/client';

const client = new TokenClient({
  storage: new LocalStorageTokenStorage(),
  refreshEndpoint: '/api/auth/refresh',
  onTokenRefresh: (tokens) => {
    console.log('Tokens refreshed');
  },
  onTokenExpired: () => {
    window.location.href = '/login';
  },
});

// Store tokens after login
await client.setTokens('access_token', 'refresh_token');

// Get a valid access token (automatically refreshes if expired)
const accessToken = await client.getValidAccessToken();

// Create authorization headers
const headers = await client.createValidAuthHeaders();
// Returns: { Authorization: 'Bearer access_token' }

Token Storage Options

LocalStorage (Browser)

import { LocalStorageTokenStorage } from '@geekmidas/auth/client';

const storage = new LocalStorageTokenStorage(
  'my_access_token',  // Custom access token key
  'my_refresh_token'  // Custom refresh token key
);

Memory Storage

import { MemoryTokenStorage } from '@geekmidas/auth/client';

// Ideal for server-side applications or testing
const storage = new MemoryTokenStorage();

Cache Storage

import { CacheTokenStorage } from '@geekmidas/auth/client';
import { InMemoryCache } from '@geekmidas/cache/memory';

const cache = new InMemoryCache<string>();
const storage = new CacheTokenStorage(cache);

// Supports TTL for automatic expiration
await storage.setAccessToken('token', 3600); // 1 hour TTL

Server-Side Token Management

Token Manager

import { TokenManager } from '@geekmidas/auth/server';
import { EnvironmentParser } from '@geekmidas/envkit';

const env = new EnvironmentParser(process.env)
  .create((get) => ({
    auth: {
      accessTokenSecret: get('ACCESS_TOKEN_SECRET').string(),
      refreshTokenSecret: get('REFRESH_TOKEN_SECRET').string(),
    },
  }))
  .parse();

const tokenManager = new TokenManager({
  accessTokenSecret: env.auth.accessTokenSecret,
  refreshTokenSecret: env.auth.refreshTokenSecret,
  accessTokenExpiresIn: '15m',
  refreshTokenExpiresIn: '7d',
});

// Generate token pair
const tokens = tokenManager.generateTokenPair({
  userId: 'user123',
  email: '[email protected]',
  role: 'admin',
});

// Verify tokens
const payload = tokenManager.verifyAccessToken(accessToken);

// Refresh access token
const newAccessToken = tokenManager.refreshAccessToken(refreshToken);

API Reference

JwtVerifier

class JwtVerifier<TClaims extends JwtClaims = JwtClaims> {
  constructor(config: JwtConfig);
  verify(token: string): Promise<TClaims>;
  verifyOrNull(token: string): Promise<TClaims | null>;
  clearCache(): void;
}

interface JwtConfig {
  secret?: string;           // For HS256
  jwksUri?: string;          // For RS256, ES256, etc.
  issuer?: string;           // Expected issuer
  audience?: string;         // Expected audience
  algorithms?: string[];     // Allowed algorithms
}

OidcVerifier

class OidcVerifier<TClaims, TUserInfo> {
  constructor(config: OidcConfig);
  verify(token: string): Promise<TClaims>;
  verifyOrNull(token: string): Promise<TClaims | null>;
  fetchUserInfo(token: string): Promise<TUserInfo | null>;
  getDiscovery(): Promise<OidcDiscovery>;
  clearCache(): void;
}

interface OidcConfig {
  issuer: string;            // OIDC issuer URL
  audience?: string;         // Expected audience
  algorithms?: string[];     // Allowed algorithms
}

JwtMiddleware / OidcMiddleware

class JwtMiddleware<TClaims> {
  constructor(options: JwtMiddlewareOptions<TClaims>);
  handler(): MiddlewareHandler;   // Required auth
  optional(): MiddlewareHandler;  // Optional auth
}

interface JwtMiddlewareOptions<TClaims> {
  config: JwtConfig;
  extraction?: TokenExtractionOptions;
  contextKey?: string;
  onError?: (c: Context, error: Error) => Response;
  transformClaims?: (claims: JwtClaims) => TClaims;
}

JwtAuthorizer / OidcAuthorizer

class JwtAuthorizer<TClaims> {
  constructor(options: JwtAuthorizerOptions<TClaims>);
  tokenHandler(): Handler;    // TOKEN authorizer
  requestHandler(): Handler;  // REQUEST authorizer
}

interface JwtAuthorizerOptions<TClaims> {
  config: JwtConfig;
  extraction?: TokenExtractionOptions;
  wildcardResource?: boolean;
  getPrincipalId?: (claims: TClaims) => string;
  getContext?: (claims: TClaims) => Record<string, string | number | boolean>;
  authorize?: (claims: TClaims) => boolean | Promise<boolean>;
}

TokenExtractionOptions

interface TokenExtractionOptions {
  headerName?: string;   // Default: 'authorization'
  tokenPrefix?: string;  // Default: 'Bearer '
  cookieName?: string;   // Optional cookie fallback
}

Security Best Practices

  1. Use Strong Secrets: Ensure your JWT secrets are cryptographically secure.

  2. Short Access Token Expiration: Keep access tokens short-lived (15 minutes recommended).

  3. Use JWKS for Production: Prefer JWKS over shared secrets for better key rotation.

  4. Validate Claims: Always validate issuer and audience claims.

  5. HTTPS Only: Always use HTTPS in production to prevent token interception.

  6. Token Rotation: Implement refresh token rotation for enhanced security.

Dependencies

  • jose - JWT/JWS/JWE operations
  • @geekmidas/cache - Cache storage support (optional)
  • hono - Hono framework (peer dependency for middleware)
  • @types/aws-lambda - AWS Lambda types (peer dependency for authorizers)

License

MIT License - see the LICENSE file for details.