npm package: @finitless/auth-sdk
Description: Parent-side SDK for embedding finitless-auth (iframe/popup)
Latest version: 0.1.0

# @finitless/auth-sdk

Parent-side SDK for embedding [finitless-auth](https://github.com/Finitless-com/finitless-auth) as an iframe or popup.

Zero dependencies. Works with any framework or plain HTML.

## Installation

```bash
npm install @finitless/auth-sdk
```

## Quick Start

### Iframe

```js
import { FinitlessAuth } from "@finitless/auth-sdk";

const auth = new FinitlessAuth({
  url: "https://auth.finitless.com/auth?project_code=MY_PROJECT&language_code=en",
  mode: "iframe",
  container: document.getElementById("auth-container"),
  origin: "https://auth.finitless.com",
  onSuccess: (data) => {
    console.log("Token:", data.token);
    console.log("User:", data.user);
    auth.destroy();
  },
});

auth.open();
```

### Popup

```js
import { FinitlessAuth } from "@finitless/auth-sdk";

const auth = new FinitlessAuth({
  url: "https://auth.finitless.com/auth?project_code=MY_PROJECT&language_code=es&theme_style=light&site_code=my-site",
  mode: "popup",
  origin: "https://auth.finitless.com",
  popupOptions: { width: 480, height: 640 },
  onSuccess: (data) => {
    console.log("Authenticated:", data.token);
  },
});

document.getElementById("login-btn").addEventListener("click", () => {
  auth.open();
});
```

## URL Parameters

Configuration is passed to the auth app via URL query parameters:

| Parameter | Required | Description |
|---|---|---|
| `project_code` | Yes | Project identifier |
| `language_code` | No | Language (`en`, `es`, `fr`, `ar`). Defaults to `en` |
| `site_code` | No | Site code for multi-site projects |
| `theme_style` | No | `light` for light theme. Dark by default |
| `via` | No | Internal product name of the parent app |

## Constructor Options

```js
new FinitlessAuth(options)
```

| Option | Type | Required | Description |
|---|---|---|---|
| `url` | `string` | Yes | Full URL of the auth app including query params |
| `mode` | `"iframe" \| "popup"` | Yes | Embedding mode |
| `container` | `HTMLElement` | Iframe only | DOM element to append the iframe to |
| `origin` | `string` | Yes | Origin of the auth app (e.g. `https://auth.finitless.com`) |
| `config` | `object` | No | Extra config sent to auth app on handshake |
| `popupOptions` | `object` | No | `{ width: 480, height: 640 }` for popup dimensions |
| `onReady` | `function` | No | Called when auth app is loaded and ready |
| `onSuccess` | `function` | No | Called with auth data when user authenticates |
| `onError` | `function` | No | Called with error data on failure |
| `onResize` | `function` | No | Called with `{ height }` when iframe content resizes |
| `onRouteChange` | `function` | No | Called with `{ path, search }` on internal navigation |
| `onClose` | `function` | No | Called when user requests to close |

## Methods

| Method | Description |
|---|---|
| `auth.open()` | Creates the iframe or opens the popup |
| `auth.logout()` | Sends logout command to the auth app |
| `auth.close()` | Requests close and destroys the instance |
| `auth.destroy()` | Removes iframe/popup and cleans up event listeners |

## Callbacks

### onSuccess

```js
onSuccess: (data) => {
  data.user;      // User object from API
  data.token;     // JWT access token
  data.session;   // { access_token, token_type, expires_in }
  data.loginType; // "password" | "otp" | "social" | "signup"
  data.provider;  // "email" | "cellphone" | "google" | "facebook" | "apple"
}
```

### onError

```js
onError: (data) => {
  data.error; // Error message string
}
```

### onResize

Called when the auth app content height changes. In iframe mode, the SDK automatically adjusts the iframe height.

```js
onResize: ({ height }) => {
  console.log("New height:", height);
}
```

### onRouteChange

Called when the user navigates within the auth app.

```js
onRouteChange: ({ path, search }) => {
  console.log("Current view:", path); // e.g. "/auth", "/auth/signup", "/auth/verify"
}
```

## Communication Protocol

The SDK communicates with the auth app via `postMessage`. Messages use this format:

```js
{
  type: "FINITLESS_AUTH",
  id: "msg_1710000000000_abc",
  action: "AUTH_SUCCESS",
  payload: { ... },
  ack: null
}
```

### Handshake

When the auth app loads, it sends `AUTH_READY` to the parent. The SDK responds with an `ACK` containing any config. The auth app retries `AUTH_READY` every 500ms for up to 3 seconds until it receives the `ACK`.

### Security

- The SDK validates `event.origin` on every incoming message against the configured `origin`
- The auth app validates the parent origin against `site.domain` (from the API) and `*.finitless.com` subdomains
- `postMessage` always specifies the target origin — never uses wildcard `"*"`

## License

MIT