JSPM

@sp-uvb/koa

0.1.0
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • Downloads 4
    • Score
      100M100P100Q26725F
    • License MIT

    Koa middleware for Universal Verification Broker (UVB)

    Package Exports

    • @sp-uvb/koa

    Readme

    @sp-uvb/koa

    Koa middleware for Universal Verification Broker (UVB) authentication.

    Installation

    npm install @sp-uvb/koa
    # or
    yarn add @sp-uvb/koa
    # or
    pnpm add @sp-uvb/koa

    Quick Start

    import Koa from 'koa';
    import Router from '@koa/router';
    import { uvbMiddleware, requireFactors } from '@sp-uvb/koa';
    
    const app = new Koa();
    const router = new Router();
    
    // Apply UVB authentication to all routes
    app.use(
      uvbMiddleware({
        tenantId: 'my-tenant',
        uvbUrl: 'http://localhost:8080',
        excludePaths: ['/login', '/health', '/public'],
      })
    );
    
    // Access the authenticated user
    router.get('/profile', async (ctx) => {
      const session = ctx.uvbSession;
      ctx.body = {
        userId: session?.userId,
        factors: session?.factorsVerified,
      };
    });
    
    // Require specific MFA factors for sensitive routes
    router.post('/admin/delete', requireFactors(['totp', 'webauthn']), async (ctx) => {
      ctx.body = { message: 'Admin action completed' };
    });
    
    app.use(router.routes());
    app.listen(3000);

    API

    uvbMiddleware(options)

    Main authentication middleware.

    Options:

    • tenantId (required): Your UVB tenant ID
    • uvbUrl (optional): UVB server URL, defaults to http://localhost:8080
    • apiKey (optional): API key for server-to-server authentication
    • cookieName (optional): Cookie name for session token, defaults to uvb_session
    • excludePaths (optional): Array of paths to exclude from authentication, defaults to []
    • onError (optional): Custom error handler function

    Attached to Context:

    After successful authentication, ctx.uvbSession contains:

    interface UVBSession {
      userId: string;
      tenantId: string;
      factorsVerified: string[];
      sessionId: string;
      expiresAt: Date;
    }

    requireFactors(factors: string[])

    Middleware to require specific MFA factors for a route.

    router.get('/sensitive', requireFactors(['totp', 'webauthn']), async (ctx) => {
      // Only accessible if user has verified both TOTP and WebAuthn
      ctx.body = { message: 'Sensitive data' };
    });

    getSession(ctx: Context)

    Helper function to get the current UVB session from a context.

    import { getSession } from '@sp-uvb/koa';
    
    router.get('/info', async (ctx) => {
      const session = getSession(ctx);
      if (!session) {
        ctx.status = 401;
        ctx.body = { error: 'Not authenticated' };
        return;
      }
      ctx.body = { userId: session.userId };
    });

    Examples

    Protecting Specific Routes

    import Koa from 'koa';
    import Router from '@koa/router';
    import { uvbMiddleware } from '@sp-uvb/koa';
    
    const app = new Koa();
    const publicRouter = new Router();
    const protectedRouter = new Router();
    
    // Public routes
    publicRouter.get('/health', async (ctx) => {
      ctx.body = { status: 'ok' };
    });
    
    // Protected routes
    protectedRouter.use(
      uvbMiddleware({
        tenantId: 'my-tenant',
        uvbUrl: process.env.UVB_URL,
      })
    );
    
    protectedRouter.get('/api/data', async (ctx) => {
      // User is authenticated
      ctx.body = { data: 'protected' };
    });
    
    app.use(publicRouter.routes());
    app.use(protectedRouter.routes());
    app.listen(3000);

    Custom Error Handling

    app.use(
      uvbMiddleware({
        tenantId: 'my-tenant',
        onError: (err, ctx) => {
          console.error('UVB auth error:', err);
          ctx.status = 401;
          ctx.body = {
            error: 'Authentication failed',
            details: err.message,
          };
        },
      })
    );

    Conditional MFA Requirements

    router.post(
      '/transfer',
      async (ctx, next) => {
        const amount = ctx.request.body.amount;
    
        // Require additional auth for large transfers
        if (amount > 10000) {
          await requireFactors(['totp', 'webauthn'])(ctx, next);
        } else {
          await next();
        }
      },
      async (ctx) => {
        ctx.body = { message: 'Transfer initiated' };
      }
    );

    Combining Multiple Middlewares

    import compose from 'koa-compose';
    import { uvbMiddleware, requireFactors } from '@sp-uvb/koa';
    
    // Create a composed middleware for admin routes
    const adminAuth = compose([
      uvbMiddleware({ tenantId: 'my-tenant' }),
      requireFactors(['totp', 'webauthn']),
    ]);
    
    router.delete('/admin/user/:id', adminAuth, async (ctx) => {
      ctx.body = { message: 'User deleted' };
    });

    Per-Route Authentication

    import Koa from 'koa';
    import Router from '@koa/router';
    import { uvbMiddleware } from '@sp-uvb/koa';
    
    const app = new Koa();
    const router = new Router();
    
    // Create auth middleware
    const auth = uvbMiddleware({ tenantId: 'my-tenant' });
    
    // Apply selectively to routes
    router.get('/public', async (ctx) => {
      ctx.body = { message: 'Public data' };
    });
    
    router.get('/private', auth, async (ctx) => {
      ctx.body = {
        message: 'Private data',
        userId: ctx.uvbSession?.userId,
      };
    });
    
    app.use(router.routes());
    app.listen(3000);

    TypeScript

    This package includes TypeScript definitions. The Context type is automatically extended:

    import { Context } from 'koa';
    
    router.get('/test', async (ctx: Context) => {
      // TypeScript knows about uvbSession
      const userId = ctx.uvbSession?.userId;
      ctx.body = { userId };
    });

    License

    MIT