# Protecting Your Function

Sinch Functions can require authentication on any handler. When enabled, callers must provide your project's API key and secret (or an admin login) via Basic Auth or a browser session. This lets you expose HTTP endpoints that only your systems, or you, can reach.

## How it works

1. You mark which handlers require auth (or all of them)
2. The runtime checks incoming requests for an `Authorization: Basic` header or a session cookie
3. Credentials are validated against `PROJECT_ID_API_KEY`/`PROJECT_ID_API_SECRET`, or `ADMIN_USER`/`ADMIN_PASSWORD` if you've set that pair
4. Invalid or missing credentials get redirected to a branded `/login` page (a browser navigation) or a `401` JSON body (anything else — curl, a script, a `fetch()` call)


The gate **fails closed**: with no credential pair configured at all, a protected route is never authenticated — there is no local-dev bypass. Set `PROJECT_ID_API_KEY`/`PROJECT_ID_API_SECRET` or `ADMIN_USER`/`ADMIN_PASSWORD` to exercise a protected handler locally.

Voice callbacks (`voiceWebhook` on v2, ICE/ACE/DiCE/PIE on legacy v1) and health checks are **never** auth-gated — they come from the Sinch platform and use webhook signature validation instead.

## Declaring protected handlers

Node.js
Export an `auth` array with the handler names you want to protect:

```typescript
import type { FunctionContext, FunctionRequest } from '@sinch/functions-runtime';

// Protect the 'webhook' handler — callers must authenticate
export const auth = ['webhook'];

export async function webhook(context: FunctionContext, request: FunctionRequest) {
  // Only reachable with valid credentials
  return { received: request.body };
}

export async function status(context: FunctionContext, request: FunctionRequest) {
  // No auth required — not listed in the auth array
  return { ok: true };
}
```

To protect **all** handlers:

```typescript
export const auth = '*';
```

C#
Add the `[Authorize]` attribute to controller actions:

```csharp
using Microsoft.AspNetCore.Authorization;

public class FunctionController : SinchController
{
    [Authorize]
    public IActionResult Webhook()
    {
        // Only reachable with valid credentials
        return Ok(new { received = "data" });
    }

    public IActionResult Status()
    {
        // No auth required — no [Authorize] attribute
        return Ok(new { ok = true });
    }
}
```

## Credentials

Auth accepts your Sinch project's API key and secret — the same credentials you use with `sinch auth login` — and, if you set it, a separate `ADMIN_USER`/`ADMIN_PASSWORD` pair for a human login. When deployed, the project pair is injected automatically as environment variables:

- `PROJECT_ID_API_KEY` — your project's API key
- `PROJECT_ID_API_SECRET` — your project's API secret


`ADMIN_USER` (a variable) and `ADMIN_PASSWORD` (a secret) are yours to set — use them for a login separate from the project's API credentials, for example one you hand to a teammate without giving them the project key.

## Local development

The gate **fails closed** — there is no local-dev bypass. If neither credential pair is set, a protected route rejects every request, including your own during `sinch functions dev`.

To test auth locally, set the environment variables before starting dev mode:

Node.js
```bash
PROJECT_ID_API_KEY=mykey PROJECT_ID_API_SECRET=mysecret sinch functions dev
```

C#
```bash
PROJECT_ID_API_KEY=mykey PROJECT_ID_API_SECRET=mysecret sinch functions dev
```

## Testing with curl

Once auth is enabled (locally with env vars or after deployment):

```bash
# Authenticated request
curl -u YOUR_API_KEY:YOUR_API_SECRET https://your-function-url/webhook

# This is equivalent to:
curl -H "Authorization: Basic $(echo -n 'YOUR_API_KEY:YOUR_API_SECRET' | base64)" \
  https://your-function-url/webhook

# Without credentials — returns 401
curl https://your-function-url/webhook
```

A browser hitting a protected page directly (a GET with `Accept: text/html`) gets redirected to a
branded `/login` page instead of a 401 — sign in there once and a session cookie covers the rest
of the browser session. `login`/`logout` are built in; export your own handlers under those names
to replace either one.

## What's not protected

These endpoints bypass auth regardless of your configuration:

| Endpoint | Reason |
|  --- | --- |
| Voice callbacks (`voiceWebhook`, or v1 ICE/ACE/DiCE/PIE) | Validated by webhook signature, not Basic Auth |
| Health checks (`/health`) | Used by infrastructure for liveness probes |