JSPM

@sp-uvb/fastify

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

    Fastify plugin for Universal Verification Broker (UVB)

    Package Exports

    • @sp-uvb/fastify

    Readme

    @sp-uvb/fastify

    Fastify plugin for Universal Verification Broker (UVB) authentication.

    Installation

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

    Quick Start

    import Fastify from 'fastify';
    import uvbPlugin, { requireFactors } from '@sp-uvb/fastify';
    
    const fastify = Fastify();
    
    // Register UVB authentication plugin
    await fastify.register(uvbPlugin, {
      tenantId: 'my-tenant',
      uvbUrl: 'http://localhost:8080',
      excludePaths: ['/login', '/health', '/public'],
    });
    
    // Access the authenticated user
    fastify.get('/profile', async (request, reply) => {
      const session = request.uvbSession;
      return {
        userId: session?.userId,
        factors: session?.factorsVerified,
      };
    });
    
    // Require specific MFA factors for sensitive routes
    fastify.post(
      '/admin/delete',
      { preHandler: requireFactors(['totp', 'webauthn']) },
      async (request, reply) => {
        return { message: 'Admin action completed' };
      }
    );
    
    await fastify.listen({ port: 3000 });

    API

    Plugin Options

    When registering the plugin, you can provide these 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 Request:

    After successful authentication, request.uvbSession contains:

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

    requireFactors(factors: string[])

    Pre-handler to require specific MFA factors for a route.

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

    getSession(request: FastifyRequest)

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

    import { getSession } from '@sp-uvb/fastify';
    
    fastify.get('/info', async (request, reply) => {
      const session = getSession(request);
      if (!session) {
        return reply.code(401).send({ error: 'Not authenticated' });
      }
      return { userId: session.userId };
    });

    Examples

    Protecting Specific Routes

    import Fastify from 'fastify';
    import uvbPlugin from '@sp-uvb/fastify';
    
    const fastify = Fastify();
    
    // Public routes
    fastify.get('/health', async (request, reply) => {
      return { status: 'ok' };
    });
    
    // Protected routes
    await fastify.register(async (protectedRoutes) => {
      await protectedRoutes.register(uvbPlugin, {
        tenantId: 'my-tenant',
        uvbUrl: process.env.UVB_URL,
      });
    
      protectedRoutes.get('/api/data', async (request, reply) => {
        // User is authenticated
        return { data: 'protected' };
      });
    });
    
    await fastify.listen({ port: 3000 });

    Custom Error Handling

    await fastify.register(uvbPlugin, {
      tenantId: 'my-tenant',
      onError: (err, request, reply) => {
        fastify.log.error('UVB auth error:', err);
        return reply.code(401).send({
          error: 'Authentication failed',
          details: err.message,
        });
      },
    });

    Conditional MFA Requirements

    import { requireFactors } from '@sp-uvb/fastify';
    
    fastify.post('/transfer', async (request, reply) => {
      const amount = request.body.amount;
    
      // Require additional auth for large transfers
      if (amount > 10000) {
        await requireFactors(['totp', 'webauthn'])(request, reply);
      }
    
      return { message: 'Transfer initiated' };
    });

    Multiple Route Groups

    const fastify = Fastify();
    
    // Public API
    fastify.get('/public/info', async () => ({ info: 'public' }));
    
    // Basic auth required
    await fastify.register(async (basicRoutes) => {
      await basicRoutes.register(uvbPlugin, { tenantId: 'my-tenant' });
    
      basicRoutes.get('/user/profile', async (request) => ({
        userId: request.uvbSession?.userId,
      }));
    });
    
    // Admin routes with strict MFA
    await fastify.register(async (adminRoutes) => {
      await adminRoutes.register(uvbPlugin, { tenantId: 'my-tenant' });
    
      adminRoutes.addHook('onRequest', requireFactors(['totp', 'webauthn']));
    
      adminRoutes.delete('/admin/user/:id', async (request) => ({
        message: 'User deleted',
      }));
    });

    TypeScript

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

    import { FastifyRequest, FastifyReply } from 'fastify';
    
    fastify.get('/test', async (request: FastifyRequest, reply: FastifyReply) => {
      // TypeScript knows about uvbSession
      const userId = request.uvbSession?.userId;
      return { userId };
    });

    License

    MIT