npm package: @ownid/azure-b2c
Description: Server-side library for integrating OwnID passwordless authentication with Azure Active Directory B2C
Author: OwnID
Latest version: 1.0.0

# OwnID Azure B2C Integration

A server-side Node.js library for integrating OwnID passwordless authentication with Azure Active Directory B2C.

## Overview

This package provides a server-side solution for integrating OwnID with Azure B2C by exposing three required endpoints:

- `/setOwnIDDataByLoginId` - Store OwnID data for a user
- `/getOwnIDDataByLoginId` - Retrieve OwnID data for a user
- `/getSessionByLoginId` - Generate authentication tokens after successful OwnID authentication

## Installation

```bash
npm install @ownid/azure-b2c
```

## Prerequisites

- Node.js 16+ and npm
- Existing Azure B2C tenant
- OwnID account and application

## Server Integration

### 1. Configure Environment Variables

Create a `.env` file with your Azure and OwnID credentials:

```env
AZURE_TENANT_ID=your-tenant-id
AZURE_CLIENT_ID=your-client-id
AZURE_CLIENT_SECRET=your-client-secret
AZURE_B2C_EXTENSION_APP_ID=your-extension-app-id
B2C_TENANT_NAME=yourtenant.onmicrosoft.com
OWNID_SHARED_SECRET=your-ownid-shared-secret
```

### 2. Add OwnID Router to Your Express App

```javascript
// server.js
require('dotenv').config();
const express = require('express');
const { createOwnIdAzureB2CRouter } = require('@ownid/azure-b2c');

const app = express();
const port = process.env.PORT || 3000;

// Required middleware for parsing JSON requests
app.use(express.json());

// Create and mount the OwnID router
const ownidRouter = createOwnIdAzureB2CRouter({
  azureTenantId: process.env.AZURE_TENANT_ID,
  azureClientId: process.env.AZURE_CLIENT_ID,
  azureClientSecret: process.env.AZURE_CLIENT_SECRET,
  azureB2cExtensionAppId: process.env.AZURE_B2C_EXTENSION_APP_ID,
  b2cTenantName: process.env.B2C_TENANT_NAME,
  ownIdSharedSecret: process.env.OWNID_SHARED_SECRET,
  // disableRequestVerification: true // Uncomment to disable request verification (not recommended for production)
});

// Mount the router at /ownid
app.use('/ownid', ownidRouter);

// Start the server
app.listen(port, () => {
  console.log(`Server running on port ${port}`);
  console.log(`Endpoints available:`);
  console.log(`  POST http://localhost:${port}/ownid/setOwnIDDataByLoginId`);
  console.log(`  POST http://localhost:${port}/ownid/getOwnIDDataByLoginId`);
  console.log(`  POST http://localhost:${port}/ownid/getSessionByLoginId`);
});
```

## API Endpoints

The library creates three Express endpoints required by OwnID:

1. **Set OwnID Data** - `POST /ownid/setOwnIDDataByLoginId`
   - Stores OwnID authentication data for a user identified by email address
   - Request includes: `loginId` (email) and `ownIdData` (OwnID data)

2. **Get OwnID Data** - `POST /ownid/getOwnIDDataByLoginId`
   - Retrieves OwnID authentication data for a user identified by email address
   - Request includes: `loginId` (email)

3. **Generate Session** - `POST /ownid/getSessionByLoginId`
   - Creates authentication tokens for a user after successful OwnID authentication
   - Request includes: `loginId` (email)
   - Returns access tokens that can be used for authentication

All endpoints include signature verification by default, requiring `ownIdSharedSecret` to be provided. Verification can be explicitly disabled with `disableRequestVerification: true`.

## Advanced Usage

### Custom Session Token Generation

You can provide your own session token generation logic, such as custom JWT creation:

```javascript
const { createOwnIdAzureB2CRouter } = require('@ownid/azure-b2c');
const jwt = require('jsonwebtoken');

// Custom session generator function
const customSessionGenerator = async (userId, email, user) => {
  // Create a custom JWT token
  const token = jwt.sign(
    { 
      sub: userId,
      email: email,
      name: user?.displayName,
      // Add custom claims as needed
    },
    process.env.JWT_SECRET,
    { expiresIn: '1h' }
  );
  
  return {
    accessToken: token,
    expiresIn: 3600,
    tokenType: 'Bearer'
  };
};

// Create router with custom session generator
const ownidRouter = createOwnIdAzureB2CRouter({
  azureTenantId: process.env.AZURE_TENANT_ID,
  azureClientId: process.env.AZURE_CLIENT_ID,
  azureClientSecret: process.env.AZURE_CLIENT_SECRET,
  azureB2cExtensionAppId: process.env.AZURE_B2C_EXTENSION_APP_ID,
  b2cTenantName: process.env.B2C_TENANT_NAME,
  ownIdSharedSecret: process.env.OWNID_SHARED_SECRET,
  customSessionGenerator: customSessionGenerator
});

app.use('/ownid', ownidRouter);
```

### Direct Access to Core Services

You can directly access the core services for custom integration:

```javascript
const { OwnIDB2CAuth, OwnIDB2CUserService } = require('@ownid/azure-b2c');

// Create auth service
const auth = new OwnIDB2CAuth({
  azureTenantId: process.env.AZURE_TENANT_ID,
  azureClientId: process.env.AZURE_CLIENT_ID,
  azureClientSecret: process.env.AZURE_CLIENT_SECRET,
  azureB2cExtensionAppId: process.env.AZURE_B2C_EXTENSION_APP_ID,
  b2cTenantName: process.env.B2C_TENANT_NAME,
  ownIdSharedSecret: process.env.OWNID_SHARED_SECRET
});

// Create user service
const userService = new OwnIDB2CUserService(auth);

// Use the services
async function findUser(email) {
  return await userService.findUserByEmail(email);
}
```

## Security

This library includes built-in request verification using HMAC signatures to ensure all incoming requests from OwnID are legitimate. By default, verification is required and you must provide `ownIdSharedSecret`.

The signature verification uses:
1. Request body
2. Request timestamp
3. Shared secret

Requests are rejected if:
- No shared secret is provided (unless explicitly disabled)
- Required headers are missing
- Signature doesn't match
- Request is too old (timestamp validation)

If you need to disable verification (not recommended for production), you can set `disableRequestVerification: true` in the configuration.

## Azure B2C Configuration

You'll need to register a dedicated application in your Azure B2C tenant and configure it with the appropriate permissions:

1. **Register an application** in your B2C tenant for OwnID integration
2. **Create a client secret** and note it down
3. **Configure API permissions**: Add `User.ReadWrite.All` permission to Microsoft Graph
4. **Grant admin consent** for the added permissions
5. **Find your B2C extension app ID** (the special b2c-extensions-app that's automatically created in your tenant)

For detailed step-by-step instructions, refer to [instructions.md](instructions.md) in the GitHub repository.

## License

MIT