> ## Documentation Index
> Fetch the complete documentation index at: https://docs.motioness.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Allowlist vs signed URLs

Two ways to authorize proxy URLs — pick one per project.

# Allowlist vs signed URLs

Every Motioness project picks one of two auth modes. Each protects the same thing — preventing third parties from burning your generation quota by hot-linking proxy URLs.

## Allowlist mode (default)

Source URL is plain text in the path. The worker resolves the source origin and rejects requests where it isn't in your `allowed_origins` list.

```text
https://motioness.com/v1/pk_abc/cdn.acme.com/hero.png.mp4
                                └────────────┬────────────┘
                                  cdn.acme.com must be in allowed_origins
```

**Best for:** first-party use, where the source images live on a domain you control.

**Trade-off:** anyone who knows your project key + a source URL on your allowlist can hit the proxy. That's fine for public marketing assets, less fine for paywalled or short-lived content.

### Configure

Project → Settings → Proxy → Allowed origins, or via API:

```bash
curl -X PUT https://motioness.com/api/projects/$PROJECT_ID/proxy-config \
  -H 'Content-Type: application/json' -b cookie.txt \
  -d '{
    "allowed_origins": ["https://acme.com", "https://cdn.acme.com"]
  }'
```

Subdomain matching: `https://acme.com` accepts `https://www.acme.com`, `https://app.acme.com`, etc.

## Signed mode

Source URL is base64url-encoded in the path. Path includes `?sig=…&exp=…`. The worker verifies an HMAC-SHA256 against your project's signing secret.

```text
https://motioness.com/v1/pk_abc/aHR0cHM6Ly9jZG4uYWNtZS5jb20vaGVyby5wbmc.mp4
  ?sig=a7e3f1...&exp=1714808400
```

**Best for:** server-to-server use, ephemeral URLs, sharing across origins, paywalled content.

**Trade-off:** can't be hand-written. The signing secret never leaves your backend; URLs are minted server-side and embedded in pages.

### Enable

Project → Settings → Proxy → Enable signing **OR** set `enable_signing: true`:

```bash
curl -X PUT https://motioness.com/api/projects/$PROJECT_ID/proxy-config \
  -H 'Content-Type: application/json' -b cookie.txt \
  -d '{ "enable_signing": true }'
```

Toggling it ON mints a fresh signing secret on first save. Toggling it OFF revokes the secret. Use [`POST /api/projects/:id/keys/rotate?which=signing`](/api/projects/rotate-keys) to rotate without changing the toggle.

### Sign URLs server-side

```ts
import { buildProxyUrl } from '@motioness/proxy-client';

const exp = Math.floor(Date.now() / 1000) + 60 * 60; // 1h
const srcUrl = 'https://cdn.acme.com/hero.png';
const projectKey = 'pk_abc';

// HMAC-SHA256(secret, `${projectKey}:${srcUrl}:${exp}`) → hex
const sig = await hmacSha256Hex(SIGNING_SECRET, `${projectKey}:${srcUrl}:${exp}`);

const urls = buildProxyUrl({
  origin: 'https://motioness.com',
  projectKey,
  src: srcUrl,
  signature: sig,
  exp,
});
// urls.mp4 is now signed and expires in 1h
```

See [signed URLs guide](/guides/signed-urls) for the full HMAC recipe in Node, Workers, Python, and Go.

## Comparison

| Capability | Allowlist | Signed |
|---|---|---|
| Hand-writeable URLs | ✅ | ❌ (need HMAC) |
| Source origins fixed | ✅ (via `allowed_origins`) | ❌ (sign any URL) |
| Short-lived URLs | ❌ | ✅ (`exp` controls) |
| Cross-origin | ❌ | ✅ |
| Hot-link protection | Origin-based | Token-based |
| Setup cost | Lowest | Server-side signing required |

## Both at once?

Not supported per project. A request hitting a project keyed for one mode but using the other mode's auth shape returns 403. If you need both — e.g. some pages signed, some allowlist — create two projects and use the right key on each surface.

## What about CSP?

Both modes survive any CSP. The browser sees a normal mp4 URL on `motioness.com`; you just need:

```
img-src 'self' https://motioness.com;
media-src 'self' https://motioness.com;
```