Skip to main content

Operator Authentication

The Dashboard API key

Quill reads its Dashboard API key from the QUILL_API_KEY environment variable when the container starts.
You supply it through the -e QUILL_API_KEY=... option in the docker run command.

The key is required for protected operational access:

  • If Quill starts without the key, it rejects all requests to protected operational API endpoints.
    It does not allow anonymous access or use a default key.
  • When the key is configured, it can be used to create a browser session or authenticate an API request directly.

For validation, Quill stores a salted SHA-256 hash in its configuration database and compares hashes using a constant-time operation. Quill does not expose the original key through its dashboard or API.

The original value remains in your deployment configuration or secret store and in the container environment.
Protect access to that configuration as you would any other secret.

Do not confuse the two signup keys

The signup email contains two different credentials:

CredentialEnvironment variableUsed for
License keyQUILL_LICENSE_KEYRetrieving the setup package during activation
Dashboard API keyQUILL_API_KEYOperator sign-in and API authentication

Use the value assigned to QUILL_API_KEY when signing in or authenticating an API request.
Using the License key instead results in 401 Unauthorized.

If you replace the signup-issued Dashboard API key with a value of your own, use a high-entropy value.
Quill logs a warning the first time it validates a Dashboard API key if QUILL_API_KEY is shorter than 16 characters.

Signing in to the dashboard

Open https://dashboard.<domain>/ and enter the Dashboard API key on the login screen.

After validating the key, Quill issues a browser session cookie.
The browser sends this cookie with later requests, so you do not need to enter the key again during the session.

PropertyValue
Cookie namequill.session
FlagsHttpOnly, Secure, SameSite=Strict
Authentication expiryAfter 8 hours of inactivity; continued activity renews it
Sign outDeletes the cookie from the current browser

Quill validates the session cookie independently and does not re-check it against the Dashboard API key.
Signing out does not invalidate a copy of the cookie held elsewhere.

A session created before the Dashboard API key is changed therefore remains valid until it expires after eight hours of inactivity. Recreating the container with the same persistent volume does not invalidate it. See Replacing an exposed key.

The sign-in rate limit is per client IP address

  • The login endpoint accepts 10 attempts per minute from each client IP address and returns 429 Too Many Requests when that address's limit is exceeded.

  • nginx passes the original caller address to Quill, as described in Network Architecture.
    Login attempts from different client IP addresses therefore use separate rate-limit buckets.

  • If a client exhausts its limit, wait up to one minute before trying again from that address.

Authenticating programmatic calls

Scripts, monitoring tools, and integrations do not create browser sessions.
They send the Dashboard API key with every protected request.

The following examples both request the list of apps configured in your Quill.
They differ only in the authentication header used.

Using the X-Api-Key header:

curl -H "X-Api-Key: <dashboard-api-key>" \
https://api.<domain>/api/apps/

Using the Authorization header with the Bearer scheme:

curl -H "Authorization: Bearer <dashboard-api-key>" \
https://api.<domain>/api/apps/

Both requests return the configured apps as JSON when the key is valid.
A missing or incorrect key returns 401 Unauthorized.

api.<domain> exposes /api/* and the anonymous /healthz endpoint, but does not serve the dashboard UI.
The API endpoints are also reachable on dashboard.<domain> with the same authentication headers.

See the Quill hostnames.

One key per account

The Dashboard API key issued during signup belongs to the signup account, not to an individual Quill instance.
The same key is issued for every Quill instance registered under the same email address.

By default, you configure each of those Quill instances with the signup-issued key:

  • Every Quill instance that is still configured with that key accepts it.

  • If you replace QUILL_API_KEY on a Quill instance, that instance accepts the replacement value instead.
    The change does not rotate the signup-issued key or affect other Quill instances.

  • If the signup-issued key is exposed, treat every Quill instance that still accepts it as affected.
    Replace the key and recreate the container on each affected instance. See Replacing an exposed key.

Recovering a lost key

Quill cannot derive the original Dashboard API key from the salted hash in its configuration database,
and it does not expose the key through its dashboard or API.

First, check the deployment configuration or secret store from which QUILL_API_KEY was supplied.

If the Quill instance still uses the signup-issued key, you can also recover it in either of these ways:

  • Check the signup email.
    The email contains the Dashboard API key, the License key, and the registered domain.

  • Register the same domain again.
    Running the signup flow for a domain that your account already owns re-sends the same account-level
    Dashboard API key and issues a fresh setup package. It does not create or rotate the key.

If the Quill instance uses a locally chosen replacement key, the signup email does not contain that value.
If you cannot recover it from your deployment configuration, configure another key and recreate the container.
See Replacing an exposed key.

Replacing an exposed key

Quill does not currently provide a built-in command for rotating or revoking the Dashboard API key.
To replace the Dashboard API key for a Quill instance, configure a new high-entropy value for QUILL_API_KEY
and recreate the container.

Recreate the container

In these commands, <container-name> is the name specified after --name in your original docker run command.
By default, it matches your Quill name.
<recorded-volume-name> is the volume name specified before :/var/lib/quill in that command.

Remove the existing container, then rerun it with the new key and the same data volume:

docker rm -f <container-name>

docker run -d --name <container-name> \
--restart unless-stopped \
-p 443:443 \
-e QUILL_LICENSE_KEY="YOUR_EXISTING_LICENSE_KEY" \
-e QUILL_API_KEY="YOUR_NEW_DASHBOARD_API_KEY" \
-v <recorded-volume-name>:/var/lib/quill \
ravendb/quill:latest

If your original command used different ports, image tags, environment options, or volume names,
preserve those values when recreating the container.

Restarting the container is not enough

  • Quill reads QUILL_API_KEY from the container environment when it starts.
    Restarting the existing container reuses the same environment, so docker restart <container-name>
    keeps the exposed key in force.

  • A browser session is not re-checked against the Dashboard API key after login.
    Changing the key therefore does not revoke previously issued session cookies.

  • With the default container layout, the web application stores its cookie-protection keys beneath
    /var/lib/quill/.aspnet/DataProtection-Keys, inside the persistent volume.
    Recreating the container with that volume preserves the keys, so existing sessions remain valid until they expire after eight hours of inactivity. Continued activity renews the session.

  • Quill does not currently provide a built-in way to invalidate all active browser sessions.

Reuse the existing data volume

  • Recreating the container preserves the Quill data stored in the persistent volume mounted at
    /var/lib/quill, including its databases, activated setup package, and configured apps.

  • Do not delete that volume; doing so removes the persisted Quill data.

Which Quill instances to update

The instances you must update depend on which key was exposed:

  • If a locally chosen replacement key was exposed, replace it on that instance.

  • If the signup-issued key was exposed, replace it on every Quill instance that still accepts it.
    Changing QUILL_API_KEY locally does not rotate the account-level signup key or update other Quill instances.

  • Store each replacement key in your deployment secret store.
    The signup email continues to contain the original signup-issued key.

What the key does not cover

The Dashboard API key, and browser sessions created from it, control access to Quill's operational API endpoints.
Three surfaces use different access controls:

  • The public chat surface
    End users open embedded chat pages on public.<domain> without the Dashboard API key.
    Each embed URL contains a bearer token whose expiration and invocation limit constrain its use.

    The channel's allowed origins restrict where browsers may embed the page through Content Security Policy.
    They do not authenticate requests or prevent direct use of a disclosed embed token.

    Never place the Dashboard API key in a front-end application.
    See what is public.

  • Direct database access
    Applications connect to RavenDB on db.<domain> using a client certificate over mutual TLS.
    The Dashboard API key cannot authenticate this connection, and a client certificate does not grant dashboard access. See direct database access.

  • Health and activation endpoints
    /healthz and /api/bootstrap/status answer without authentication,
    allowing first-boot activation to be monitored before an operator can sign in.

Quill has a single operator credential

Quill does not provide separate operator accounts.
Anyone holding the Dashboard API key has full operator access to the dashboard and operational API.

Quill treats all key holders as the same operator and cannot distinguish which person performed an action.
If someone who knows the key should no longer have access, replace it on every affected Quill instance
and recreate those containers to load the new value. This prevents new authentication with the exposed key,
but does not invalidate browser sessions that were already issued.

Summary

  • The Dashboard API key is required for Quill's operational API.
    If Quill starts without the key, all requests to protected operational API endpoints are rejected.

  • Quill stores a salted hash in its configuration database and does not expose the original key through its dashboard or API. Keep the original value in your deployment secret store.

  • Dashboard sign-in creates a sliding session cookie that expires after eight hours of inactivity.
    Programmatic callers send the key with every request using X-Api-Key or Authorization: Bearer.

  • The login rate limit uses a separate bucket for each client IP address.

  • The signup-issued key belongs to the signup account and works on every Quill instance that is still configured with it. A locally chosen replacement applies only to the Quill instance on which it is configured.

  • Recover the signup-issued key from the signup email or by registering the same domain again.
    Recover a locally chosen key from your deployment configuration, or configure another key.

  • To replace an exposed key, update QUILL_API_KEY and recreate every affected container.
    Restarting an existing container does not load a changed environment. Neither restarting nor recreating the container with the same persistent volume invalidates existing browser sessions.

  • The Dashboard API key does not authenticate embed links, direct RavenDB connections, /healthz,
    or /api/bootstrap/status. Those surfaces use embed tokens, mTLS client certificates, or anonymous access.

In this article