---
title: Client Authentication
description: Secure client-side API requests with signing keys and security modes
---

# Client Authentication

The User API is designed for client-side use — it powers in-app inboxes, notification feeds, and preference screens. Because it runs in the browser, securing it requires two layers: **authentication** (proving who the user is) and **allowed origins** (restricting which domains can make requests).

This page covers authentication. See [Allowed Origins](/docs/learn/security/allowed-origins) for domain restrictions.

## Security Modes

Notiflows supports two security modes for the User API:

### Secure Mode (Recommended)

When **Security Mode** is enabled (default), each request requires:

- `x-notiflows-api-key` — your project's public API key
- `x-notiflows-user-key` — a JWT signed with your Application Signing Key (RS256)

Your backend signs JWTs with the **private key**. Notiflows verifies them with the **public key** stored in your project. The private key never leaves your infrastructure.

### Development Mode

When Security Mode is disabled, each request requires:

- `x-notiflows-api-key` — your project's public API key
- `x-notiflows-user-id` — the user's external ID (no signing)

<Callout type="warn">
Development mode is NOT safe for production. Anyone with your API key can impersonate any user. Always enable Security Mode for production deployments.
</Callout>

## Setting Up Signing Keys

1. Go to **Projects** → **Settings** → **API Keys**
2. Find the **Client Authentication** section
3. Click **Generate signing key**
4. **Save the private key** — it is only shown once

The private key is provided in two formats:
- **Base64-encoded PEM** — single-line, ideal for environment variables
- **Raw PEM** — standard format for file storage

Security Mode is enabled by default. If disabled, re-enable it in the same section.

## Generating User Tokens

Your backend generates a JWT for each user. The token payload:

```json
{
  "sub": "user_external_id",
  "iat": 1608600116,
  "exp": 1608603716
}
```

| Claim | Required | Description |
|-------|----------|-------------|
| `sub` | Yes | The user's external ID (must match a user in Notiflows) |
| `iat` | Recommended | Unix timestamp when the token was issued |
| `exp` | Recommended | Unix timestamp when the token expires |

For code examples in Node.js, Python, and Ruby, see the [Authentication API reference](/docs/api/user/authentication#code-examples).

## Best Practices

- **Short-lived tokens** — set expiry to 1 hour or less and implement token refresh
- **Store keys securely** — use environment variables or a secrets manager, never client-side code or version control
- **Rotate keys** when compromised — regenerating a key invalidates all existing tokens immediately

## Next Steps

- [Allowed Origins](/docs/learn/security/allowed-origins) — Restrict which domains can call the User API
- [Authentication API Reference](/docs/api/user/authentication) — Full details with code examples
