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

# Authentication

> Protect the API with Basic Auth, then pair each WhatsApp account by QR code, pairing code or passkey.

GOWA has two separate kinds of authentication:

1. **API access**: who may call GOWA. This is HTTP Basic Auth.
2. **WhatsApp pairing**: linking a WhatsApp account to a device slot, as you would link WhatsApp Web.

## API access: Basic Auth

Basic Auth is the only API authentication method. There are no API keys or JWTs for REST calls.

Set one or more `user:password` pairs, comma-separated:

```bash theme={null}
# environment
APP_BASIC_AUTH=admin:changeme,ops:another-secret
# or flag
./whatsapp rest --basic-auth=admin:changeme,ops:another-secret
```

A malformed entry (for example one without `:`) stops the server at startup. When `APP_BASIC_AUTH` is empty, the API is **unauthenticated**; only do this on a trusted network.

Send credentials on every request:

```bash theme={null}
curl -u admin:changeme http://localhost:3000/app/info
# same as
curl -H "Authorization: Basic YWRtaW46Y2hhbmdlbWU=" http://localhost:3000/app/info
```

A missing or wrong credential returns `401 Unauthorized`.

### What is not behind Basic Auth

| Route | Why |
| - | - |
| `GET /health` | Liveness probe. Always at the root, ignoring `APP_BASE_PATH`. |
| `POST /chatwoot/webhook`, `POST /chatwoot/webhook/{device_id}` | Called by Chatwoot. Registered only when `CHATWOOT_ENABLED=true` and protected by `CHATWOOT_WEBHOOK_SECRET` instead. See [Chatwoot](https://gowa-docs.mintlify.site/integrations/chatwoot.md). |
| MCP OAuth discovery and `/oauth/*` endpoints | Only when `MCP_OAUTH_ENABLED=true`. See [MCP server](https://gowa-docs.mintlify.site/integrations/mcp.md). |
| `GET /statics/*` | Static files: QR images, uploads and downloaded media. Served before Basic Auth, so anyone who knows a file name can fetch it. File names are random, but keep `statics/` off public networks or block it at your proxy if that matters. |

Everything else, including the dashboard at `/`, `/mcp` and `/ws`, requires Basic Auth when it is configured.

### WebSocket

Browsers cannot set headers on WebSocket connections, so `/ws` takes the credential in the query string:

```text theme={null}
ws://localhost:3000/ws?device_id=my-device&authorization=YWRtaW46Y2hhbmdlbWU=
```

`authorization` is `base64(user:password)`. Use TLS (`wss://`), since the credential is visible in the URL and in proxy logs.

### CORS

CORS allows any origin by default. Restrict it for browser clients with `APP_CORS_ALLOWED_ORIGINS=https://ui.example.com` (comma-separated). Allowed request headers are `Origin`, `Content-Type`, `Accept`, `Authorization` and `X-Device-Id`.

## WhatsApp pairing

Every WhatsApp account lives in a **device slot**. Create the slot first, then pair it. Routes under `/devices/{device_id}` take the device from the path. The equivalent `/app/*` routes use the `X-Device-Id` header.

```bash theme={null}
curl -u admin:changeme -X POST http://localhost:3000/devices \
  -H "Content-Type: application/json" -d '{"device_id": "sales"}'
```

### QR code

```bash theme={null}
curl -u admin:changeme http://localhost:3000/devices/sales/login
```

```json theme={null}
{
  "code": "SUCCESS",
  "message": "Login success",
  "results": {
    "device_id": "sales",
    "qr_link": "http://localhost:3000/statics/qrcode/scan-qr-b0b7bb43-....png",
    "qr_duration": 30
  }
}
```

Open `qr_link` and scan it from the phone: **Settings → Linked devices → Link a device**. Request a new code after `qr_duration` seconds. The dashboard at `/` shows the QR directly and updates live over the WebSocket.

### Pairing code

```bash theme={null}
curl -u admin:changeme -X POST \
  "http://localhost:3000/devices/sales/login/code?phone=628123456789"
```

The response contains `results.pair_code`, an 8-character code. On the phone, choose **Link with phone number instead** and type it in. `phone` must be the number of the account being linked, with country code.

### Passkey

If the phone asks for passkey verification during QR login, GOWA stores a WebAuthn challenge and broadcasts `PASSKEY_REQUEST` on the WebSocket. The dashboard handles this flow. To drive it yourself:

1. `GET /app/passkey` returns the pending challenge.
2. `POST /app/passkey/response` submits the WebAuthn assertion (`PublicKeyCredential.toJSON()` format).
3. If the assertion arrives after the 5-minute handoff window, GOWA emits `PASSKEY_CONFIRMATION` with a code. Confirm it matches the phone, then call `POST /app/passkey/confirm`.

Send `X-Device-Id` on all three calls.

### Check the result

```bash theme={null}
curl -u admin:changeme http://localhost:3000/devices/sales/status
```

`results.is_connected` and `results.is_logged_in` are both `true` once the account is linked. Sessions persist in `storages/`, so restarts do not require pairing again.

## Logging out and removing

| Action | Endpoint | Effect |
| - | - | - |
| Log out | `POST /devices/{device_id}/logout` or `GET /app/logout` | Unlinks the account from WhatsApp and clears its session. The slot stays, so you can pair it again under the same ID. |
| Reconnect | `POST /devices/{device_id}/reconnect` or `GET /app/reconnect` | Reopens the WhatsApp connection without pairing again. |
| Remove | `DELETE /devices/{device_id}` | Logs out, then deletes the slot together with its session and chat data. |

An account unlinked from the phone (Linked devices → Log out) is logged out the same way: the slot remains and needs pairing again.

## Security checklist

* Always set `APP_BASIC_AUTH` with strong passwords on anything reachable from a network.
* Terminate TLS at a reverse proxy; Basic Auth credentials are only base64-encoded.
* Restrict `APP_CORS_ALLOWED_ORIGINS` when a browser UI calls the API.
* Change `WHATSAPP_WEBHOOK_SECRET` from its default `secret`.
* Treat `storages/` as sensitive: it contains the WhatsApp session keys of every linked account.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.