npm package: @flowpay-io/embed-auth
Description: Flowpay SDK - Embed client - Authentication utilities
Author: Flowpay
Latest version: 1.2.0

# @flowpay-io/embed-auth

Authentication utilities for secure embed authentication. Provides functions for canonicalizing, encoding, and signing Flowpay launch payloads using HMAC-SHA256.

## Installation

```bash
pnpm add @flowpay-io/embed-auth
```

## Package Exports

The package provides separate exports for client-side and server-side usage:

- Main export: `@flowpay-io/embed-auth` - Contains all functions
- Client export: `@flowpay-io/embed-auth/client` - Client-side functions
- Server export: `@flowpay-io/embed-auth/server` - Server-side functions

## Usage

The recommended approach is to use `createSignedLogin` on the client-side, which delegates signature generation to your server using the `generateSignature` function. Launch payloads can be either **merchant** (onboarding) or **customer** (login of an existing Flowpay customer).

### Client-side

**Merchant launch (new or previously activated merchant):**

```typescript
import { createSignedLogin } from "@flowpay-io/embed-auth/client";
import {
  IsoCountryCode,
  type MerchantLaunchPayload,
} from "@flowpay-io/shared/types";

const inputPayload: MerchantLaunchPayload = {
  country: IsoCountryCode.CZ,
  createdAt: new Date().toISOString(), // createdAt must be provided if not auto-generated by the client in @flowpay-io/embed-core
  merchantId: "merchant-123",
  partnerCode: "partner-abc",
  regNum: "12345678",
  userId: "user-456",
  email: "user@example.com",
  phone: "+420123456789",
};

const { payload, signature } = await createSignedLogin(
  inputPayload,
  async (canonicalPayload: string) => {
    const response = await fetch("/api/sign-payload", {
      method: "POST",
      body: JSON.stringify({ payload: canonicalPayload }),
    });
    const { signature } = await response.json();
    return signature;
  },
  "merchant",
);
// Returns: { payload: string, signature: string }
```

**Customer launch (existing Flowpay customer entity previously activated by partner):**

```typescript
import { createSignedLogin } from "@flowpay-io/embed-auth/client";
import type { CustomerLaunchPayload } from "@flowpay-io/shared/types";

const inputPayload: CustomerLaunchPayload = {
  partnerCode: "partner-abc",
  createdAt: new Date().toISOString(), // createdAt must be provided if not auto-generated by the client in @flowpay-io/embed-core
  customerId: "flowpay-customer-id",
  repId: "rep-123",
  userId: "user-456",
};

const { payload, signature } = await createSignedLogin(
  inputPayload,
  async (canonicalPayload: string) => {
    const response = await fetch("/api/sign-payload", {
      method: "POST",
      body: JSON.stringify({ payload: canonicalPayload }),
    });
    const { signature } = await response.json();
    return signature;
  },
  "customer",
);
// Returns: { payload: string, signature: string }
```

### Server-side

```typescript
import { generateSignature } from "@flowpay-io/embed-auth/server";

// This endpoint is called by the client-side handleSign callback
app.post("/api/sign-payload", async (req, res) => {
  const { payload: canonicalPayload } = req.body;

  const signature = await generateSignature(
    canonicalPayload,
    async () => process.env.PARTNER_SHARED_SECRET, // Store securely
  );

  res.json({ signature });
});
```

## API Reference

### Client Functions

#### `createSignedLogin(inputPayload, handleSign)`

Canonicalizes, encodes, and signs a Flowpay launch payload. This function:

- Automatically sets `createdAt` if not provided
- Canonicalizes the payload according to Flowpay's specification
- Base64url-encodes the canonical payload
- Delegates signature generation to the provided `handleSign` callback

**Parameters:**

- `inputPayload: FlowpayLaunchPayload` - The launch payload object (either `MerchantLaunchPayload` for onboarding or `CustomerLaunchPayload` for existing customer login)
- `handleSign: (canonicalPayload: string) => Promise<string>` - Async function that signs the canonical payload and returns the base64url-encoded signature

**Returns:** `Promise<{ payload: string; signature: string }>`

#### `createRemoteSigner(endpointUrl)`

Creates a signing function that calls a remote signing server endpoint. This is a convenience helper that simplifies integration with a backend signing service. The returned function can be used directly as the `handleSign` parameter in `createSignedLogin`.

**Parameters:**

- `endpointUrl: string` - The full URL of the signing server endpoint (e.g., `"http://localhost:3003/api/sign-payload"`)

**Returns:** `(canonicalPayload: string) => Promise<string>` - A function that can be used as the `handleSign` parameter in `createSignedLogin`

**Example:**

```typescript
import {
  createSignedLogin,
  createRemoteSigner,
} from "@flowpay-io/embed-auth/client";

const signer = createRemoteSigner("http://localhost:3003/api/sign-payload");
const { payload, signature } = await createSignedLogin(inputPayload, signer);
```

**Note:** The remote endpoint should accept a POST request with a JSON body containing `{ payload: string }` and return a JSON response with `{ signature: string }`.

#### `unsafe_clientGenerateSignature(canonicalPayload, secretProvider)`

**UNSAFE - Testing Only**: Generates a signature in the browser using HMAC-SHA256. **Never use this in production** as it requires exposing your secret key to the client.

**Parameters:**

- `canonicalPayload: string` - The canonicalized JSON payload string
- `secretProvider: () => Promise<string>` - Function that provides the secret key

**Returns:** `Promise<string>` - Base64url-encoded signature

### Server Functions

#### `generateSignature(canonicalPayload, secretProvider)`

Generates a base64url-encoded HMAC-SHA256 signature for the canonical payload. Use this function server-side only.

**Parameters:**

- `canonicalPayload: string` - The canonicalized JSON payload string
- `secretProvider: () => Promise<string>` - Function that provides the secret key

**Returns:** `Promise<string>` - Base64url-encoded signature

#### `calculateHmacSignature(canonicalPayload, secretKey)`

Low-level function that calculates raw HMAC-SHA256 bytes. Returns `Uint8Array` of signature bytes.

**Parameters:**

- `canonicalPayload: string` - The canonicalized JSON payload string
- `secretKey: string` - The secret key

**Returns:** `Promise<Uint8Array>` - Raw signature bytes

## Security Notes

- **Never expose your secret key** in client-side code
- Always use `generateSignature` on the server-side in production
- The `unsafe_clientGenerateSignature` function is only for testing purposes
- Store your `PARTNER_SHARED_SECRET` securely (environment variables, secret management services, etc.)

## Links

- **Homepage**: [https://www.flowpay.io](https://www.flowpay.io)
- **Documentation**: [https://developers.flowpay.io](https://developers.flowpay.io)