# Security (/docs/products/dash-dots/developers/security)

People trust Dash with their money. Dash enforces some rules for every dot, and the rest on this page are up to you.

## Permissions

To use the camera, photos, files, contacts, the person's Dash account or payments, declare a permission in `dot.json` with a reason:

```json title="dot.json"
{
  "permissions": {
    "camera": "Scan the QR code on your ferry ticket",
    "contacts": "Choose a cousin to send airtime to"
  }
}
```

| Permission     | The calls it unlocks                                                                                                      |
| -------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `camera`       | `dash.media.pickPhoto({ source: 'camera' })` and `dash.media.scanCode()`                                                  |
| `photoLibrary` | `dash.media.pickPhoto({ source: 'library' })`                                                                             |
| `files`        | `dash.media.pickFile()`                                                                                                   |
| `contacts`     | `dash.contacts.pickPhone()`                                                                                               |
| `account`      | `dash.account.signIn()`. See [Sign the person in](/docs/products/dash-dots/developers/dash-apis#sign-the-person-in)       |
| `payments`     | `dash.payments.request()` and `get()`. See [Take payments](/docs/products/dash-dots/developers/payments#declare-payments) |
| `reminders`    | `dash.reminders.set()`, `cancel()` and `list()`. See [Reminders](/docs/products/dash-dots/developers/dash-apis#reminders) |

Ask only for what you use. Each one shows in your dot's About screen, and a long list makes people wary.

Dash asks the first time the dot needs a permission and shows your reason. "Scan the QR code on your ferry ticket" gets a yes far more often than "Camera access". People can change their answer later with the switches in About, in the dot's menu.

### When the answer is no

The call fails with `denied`. So does a call whose permission isn't in `dot.json`. Dash won't ask again while the dot is open. Offer another way instead:

```ts title="pages/send/controller.ts"
import { isDashError, unlessCancelled } from '@monimesl/dot-runtime';

// One of the page's actions
async chooseCousin() {
  try {
    const contact = await unlessCancelled(this.dash.contacts.pickPhone());
    if (contact) {
      this.setState({ phone: contact.phone });
    }
  } catch (error) {
    if (!isDashError(error, 'denied')) {
      throw error;
    }
    // No contacts. Let them type the number.
    this.setState({ typeNumber: true });
  }
},
```

[Handle errors](/docs/products/dash-dots/developers/dash-apis#handle-errors) explains `isDashError` and `unlessCancelled`.

## Keep secrets off the phone

Anyone who has your dot can read all of it, `.env` included. API keys, access tokens and passwords belong on your server. The dot calls your server, and your server calls the [Monime API](/docs/developer-resources/api-basics/authentication).

To keep someone signed in to your server, store their session token with [`dash.storage.secret`](/docs/products/dash-dots/developers/network-and-files#cache-and-secrets).

## Keep the host list short

Your dot can only reach the hosts in [`network.hosts`](/docs/products/dash-dots/developers/network-and-files#allowed-hosts). A short list also limits what bad code from a dependency could do with your customers' data. List `api.boenergy.sl` rather than `*.boenergy.sl` when one host will do.

## Limits Dash sets

- [How many dialogs a dot can open, and what it can't do while Dash isn't on screen](/docs/products/dash-dots/developers/dash-apis#when-dash-holds-a-call-back)
- [Alerts](/docs/products/dash-dots/developers/dash-apis#alerts) and [dial codes](/docs/products/dash-dots/developers/dash-apis#phone-features)
- [Navigation bar titles](/docs/products/dash-dots/developers/navigation#dashs-bars)
- [Servers on your computer or network](/docs/products/dash-dots/developers/network-and-files#a-server-on-your-computer)
- [Storage and network limits](/docs/products/dash-dots/developers/network-and-files#limits)

A page can't use the camera or microphone itself. Use [`dash.media`](/docs/products/dash-dots/developers/dash-apis#photos-files-and-qr-codes) instead.

## Keep personal details out of errors

If your [`onError` hook](/docs/products/dash-dots/developers/pages-and-state#errors) sends errors to your error tracker, keep names and numbers out of their messages. Write `throw new Error('No seat left on this ferry')`, not the person's name.

## Protect your server

Anyone can send requests to your server, not only your dot. Treat it like any public API:

- Check every request. Work out prices and amounts on the server, not from what the dot sends.
- Handle each order once, even when the dot retries. See [Send an order once](/docs/products/dash-dots/developers/network-and-files#send-an-order-once).
- [Confirm payments on your server](/docs/products/dash-dots/developers/payments#confirm-on-your-server), not with what the dot reports.
- Don't let an `accountIdToken` from [`dash.account.signIn`](/docs/products/dash-dots/developers/dash-apis#sign-the-person-in) alone open the person's records or money. Your server can't tell it from one someone made up.
