# Service Token Bridge

Exchange a first-party app session for a short-lived Hub JWT scoped to a single merchant — required to drive MPC ceremonies from a downstream product (e.g. aurea-pay).

## Overview

Aurea's MPC Hub authenticates every relay/sign/DKG call with a JWT that carries `(sub, tenantId)`. First-party apps that orchestrate MPC for many merchants (typically a payment-link or POS product) cannot reuse their own session token — they need a scoped token per merchant.

This endpoint accepts a service credential (shared between the app and the Hub) plus the target `tenantId` and `userId`, and returns a short-lived Hub JWT that the merchant's browser can then use for `/v1/mpc/*` calls.

> ⚠️ The service credential is shared between trusted backends only. Never expose it to a browser or mobile client.

### `POST /v1/mpc/service/token`

Authentication: bearer token required.

Mints a short-lived Hub JWT scoped to (tenantId, userId).

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `tenantId` | string | yes | Target merchant's tenant id |
| `userId` | string | yes | Target user (typically the merchant operator) |
| `ttl` | integer | no | Token lifetime in seconds (default: 300, max: 3600) |

**Responses**

`200` OK

```json
{
  "token":      "eyJhbGciOiJIUzI1NiIs…",
  "expires_in": 300
}
```

## Implementation

```javascript
// Server-side proxy: mint a Hub JWT for the active merchant, hand it to the browser
app.post('/api/mpc/hub-token', async (req, res) => {
  const { merchantTenantId, operatorUserId } = req.body;
  const r = await fetch('https://api.aureahub.com/v1/mpc/service/token', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.AUREA_HUB_SERVICE_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ tenantId: merchantTenantId, userId: operatorUserId })
  });
  res.json(await r.json()); // { token, expires_in }
});
```

---

Web version: https://docs.aureahub.com/#mpc-service-token
