# Secrets

A secret is a setting that must never leave the server, such as a password
or an API key. Mark it with `secret: true`. Some types are always secret
and need no flag: `PostgresUrl`, `RedisUrl` and `SigningKey`. Here the
database's address, a `PostgresUrl`, is read by the connection that uses
it:

```jadpo
config {
    database_url: PostgresUrl
}

application {
    connections: {
        main: {
            driver: Driver.postgres
            url: config.database_url
        }
    }
}
```

Your code can use a secret only where Jadpo itself takes the value and
keeps it on the server:

- a connection's `url:`;
- an integration's `credential:`, and its webhook `secret:`
  ([Connecting in `app.jadpo`](connecting-in-app-jadpo.md));
- an authentication `signing_key:`
  ([The application and revocation](the-application-and-revocation.md)).

All of these are written in `app.jadpo` or `authentication.jadpo`. The one
other place is a `crypto` call's `key:`, written `key: config.<name>` with
an `EncryptionKey`, `SigningKey` or `PrivateKey` setting
([Hashing and cryptography](hashing-and-cryptography.md)).

Anywhere else in a function, action, query or test, reading a secret at all
is an error, `configuration.secret_flow`. That covers returning it, storing
it, logging it, putting it in a failure, building another value from it,
passing it on, and even comparing it: `key == config.api_key` is refused,
because a yes-or-no answer gives the secret away one guess at a time.

Because code never reads the secret, nothing your app prints, stores,
returns or logs can hold it. `jadpo config check`, `jadpo dev` and the check
before the app starts say which setting and which variable is wrong, never
the value.
