# Security

> The admin PIN, the remote-control policy, protected settings, API token handling and guidance for keeping Kiosky on your local network.

A kiosk is usually a tablet on a wall that many people can touch, connected to your home or office network. Kiosky's defaults assume that. This page explains the controls and what each one protects.

## Admin PIN

The admin PIN protects leaving the kiosk and changing settings. Set it in the setup wizard, or under **Settings, Lock & security, Admin PIN**.

- A PIN is 4 to 12 digits. It is stored as a hash, never as text.
- **No PIN set:** the exit gesture opens Settings for anyone. Kiosky warns you with "No PIN set: the exit gesture opens settings for anyone."
- Wrong attempts are throttled. After 5 wrong PINs entry locks for 30 seconds, and each further failure doubles the lock, up to 15 minutes. The lockout survives reboots.
- Each wrong PIN and each exit gesture is published as an event (`wrong_pin`, `exit_gesture`), so you can be alerted. See [Home Assistant integration](home-assistant.md#events).

The exit gesture is five quick taps on the top-left corner.

## Remote-control policy

Commands can reach the tablet from several places: the on-device UI, local voice, MQTT, the REST API, a web page through the bridge, and the app's own schedules. Every command passes one central policy, whatever its source.

Commands fall into two classes:

| Class | Commands | Effect |
|---|---|---|
| Benign | `reload`, `load_url`, `screen`, `brightness`, `screensaver`, `dashboard`, `tts`, `play`, `stop_audio`, `volume`, `toast`, `popup`, `dismiss_popup`, `snapshot`, `microphone`, `kiosk_resume`, `kiosk_lock on` | Change what is shown or heard. The kiosk stays locked. |
| Sensitive | `kiosk_pause`, `kiosk_lock off`, `launch_app`, `exit_app_mode`, `restart_app`, `clear_cache`, `reboot` | Unlock the tablet, open other apps, or restart the device or app. |

Two switches on the tablet control what the network may do. Both are **off by default** and live under **Settings, Lock & security, Security**:

| Switch | Default | What it allows |
|---|---|---|
| Allow remote unlock & app control | Off | Lets MQTT and the REST API run the sensitive commands above. |
| Allow remote security changes | Off | Lets `PUT /api/config` change [protected settings](#protected-settings). |

Turning either on asks you to confirm, because anyone who can publish to your MQTT broker or holds the REST token could then unlock the tablet and open other apps, or switch off the kiosk lock, point Kiosky at another server or inject scripts. Only turn them on with an authenticated broker on a network you trust.

What each source may do:

| Source | Benign | Sensitive |
|---|---|---|
| On-device UI, local voice, the app's schedules | yes | yes |
| MQTT and REST | yes | only with **Allow remote unlock** on |
| A web page (the `window.kiosk` bridge) | a short allow-list only | never |

A refused REST command returns `403` with "Remote unlock is turned off on this tablet". A refused MQTT command produces a `command_rejected` event. `reboot` additionally needs full lock (Device Owner) and returns `409` otherwise. When **Allow remote unlock** is off, Home Assistant does not even get the **Kiosk lock**, **Restart app** and **Relaunch app** entities.

## Protected settings

Some configuration decides who can reach or control the tablet. Over the network, `PUT /api/config` can change these only when **Allow remote security changes** is on, and the `remote` switches themselves can never be changed over REST:

`kiosk`, `remote`, `server`, `camera.stream`, `homeAssistant.baseUrl`, `browser.injections`, `browser.allowedHosts`, `browser.bridgeOrigins`, `browser.mediaOrigins`, `mqtt.host`, `mqtt.port`, `mqtt.tls`, `mqtt.username` and `mqtt.publishNetworkInfo`.

A blocked change returns `403` with `"error": "protected"` and the list of paths, and saves nothing. Settings changed on the tablet itself, or imported on the tablet by QR, file or URL after a review of the differences, are not limited this way. See the [REST API reference](rest-api.md#protected-settings).

## Secrets

These are never part of the configuration, exports, logs or REST responses:

- the Home Assistant token
- the MQTT password
- the admin PIN (stored as a hash)
- the REST API token
- the Immich API key and the battery webhook URL

Secrets are kept in encrypted storage on the device. Exports from **Settings, Device, Backup & restore** leave them out. Logs mask tokens and passwords. Changing the Home Assistant origin or the MQTT host deletes the matching saved token or password, so a secret never follows an address change.

## The API token

- It is generated on the tablet when you first turn remote access on: 32 random bytes, 43 characters.
- Show or copy it under **Settings, Connections, Remote access, API token**. The copy is marked sensitive, so Android hides it from clipboard previews where it can.
- **Regenerate** replaces it. The old token stops working at once, so update every client.
- Send it only in an `Authorization: Bearer` header. Do not put it in URLs, chat messages, screenshots, tickets, issue trackers or public repositories. Keep it in a password manager, a Home Assistant `secrets.yaml` or your platform's secret store.
- The one exception is the camera stream, which accepts HTTP Basic with the user `kiosky` and the token as the password, because Home Assistant's MJPEG camera cannot send a header.
- If a token leaks, regenerate it and check that **Allow remote unlock** and **Allow remote security changes** are still off.
- Repeated wrong tokens are rate limited per address (5 failures in 60 seconds lock that address out), with a global ceiling on top. See [REST API reference](rest-api.md#rate-limits).

## Keep it on your local network

The REST server uses plain HTTP, so its token and responses travel unencrypted. Settings says so in the Security card: "The REST API runs over plain HTTP: its token can be read by anyone on this Wi-Fi. TLS is coming later."

- **Never forward port 2323 (or whatever port you chose) to the internet**, and do not expose it through a reverse proxy, a tunnel or a cloud service without your own authentication and TLS in front of it.
- Put tablets on a trusted network or a separate VLAN, and use a guest network for visitors.
- Turn the REST server off when you do not use it: **Settings, Connections, Remote access**.
- Use an MQTT broker with a user account and TLS. The Security card warns about an anonymous broker and about MQTT without TLS.
- Use `https` for Home Assistant on public addresses. A Home Assistant token is not sent to a plain `http` address outside your local network.
- Pages only get the `window.kiosk` bridge, the microphone or the camera if you list their origin, and the microphone and camera also need `https`.
- Keep injected scripts (**Custom CSS and JavaScript**) to code you trust.

## Privacy

Camera analysis and voice wake word detection run on the tablet. Audio goes to Home Assistant only after the wake word. Camera frames never leave the device except snapshots you request and the optional live stream. See [Camera & sensors](camera-sensors.md#privacy-at-a-glance). The Security card summarises warnings (anonymous broker, no TLS, token over plain HTTP) in one place, or shows **No warnings**.
