npm package: @sp-uvb/express
Description: Express middleware for Universal Verification Broker (UVB)
Author: UVB Team
Latest version: 0.1.0

# @sp-uvb/express

Express middleware for Universal Verification Broker (UVB) authentication.

## Installation

```bash
npm install @sp-uvb/express
# or
yarn add @sp-uvb/express
# or
pnpm add @sp-uvb/express
```

## Quick Start

```typescript
import express from 'express';
import { uvbMiddleware, requireFactors } from '@sp-uvb/express';

const app = express();

// Apply UVB authentication to all routes
app.use(
  uvbMiddleware({
    tenantId: 'my-tenant',
    uvbUrl: 'http://localhost:8080',
    excludePaths: ['/login', '/health', '/public'],
  })
);

// Access the authenticated user
app.get('/profile', (req, res) => {
  const session = req.uvbSession;
  res.json({
    userId: session?.userId,
    factors: session?.factorsVerified,
  });
});

// Require specific MFA factors for sensitive routes
app.post('/admin/delete', requireFactors(['totp', 'webauthn']), (req, res) => {
  res.json({ message: 'Admin action completed' });
});

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
- `sessionKey` (optional): Custom key for storing session in req object, defaults to `uvbSession`
- `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, `req.uvbSession` contains:

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

### `requireFactors(factors: string[])`

Middleware to require specific MFA factors for a route.

```typescript
app.get(
  '/sensitive',
  uvbMiddleware({ tenantId: 'my-tenant' }),
  requireFactors(['totp', 'webauthn']),
  (req, res) => {
    // Only accessible if user has verified both TOTP and WebAuthn
  }
);
```

### `getSession(req: Request)`

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

```typescript
import { getSession } from '@sp-uvb/express';

app.get('/info', (req, res) => {
  const session = getSession(req);
  if (!session) {
    return res.status(401).send('Not authenticated');
  }
  res.json({ userId: session.userId });
});
```

## Examples

### Protecting Specific Routes

```typescript
// Public routes
app.get('/health', (req, res) => res.json({ status: 'ok' }));

// Protected routes
app.use(
  '/api',
  uvbMiddleware({
    tenantId: 'my-tenant',
    uvbUrl: process.env.UVB_URL,
  })
);

app.get('/api/data', (req, res) => {
  // User is authenticated
  res.json({ data: 'protected' });
});
```

### Custom Error Handling

```typescript
app.use(
  uvbMiddleware({
    tenantId: 'my-tenant',
    onError: (err, req, res, next) => {
      console.error('UVB auth error:', err);
      res.status(401).json({
        error: 'Authentication failed',
        details: err.message,
      });
    },
  })
);
```

### Conditional MFA Requirements

```typescript
app.post(
  '/transfer',
  uvbMiddleware({ tenantId: 'my-tenant' }),
  (req, res, next) => {
    const amount = req.body.amount;
    // Require additional auth for large transfers
    if (amount > 10000) {
      return requireFactors(['totp', 'webauthn'])(req, res, next);
    }
    next();
  },
  (req, res) => {
    res.json({ message: 'Transfer initiated' });
  }
);
```

## TypeScript

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

```typescript
import { Request } from 'express';

app.get('/test', (req: Request, res) => {
  // TypeScript knows about uvbSession
  const userId = req.uvbSession?.userId;
});
```

## License

MIT