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

# Authentication

> API keys: issuing, format, headers, scopes, and the identity a key acts as.

## The header

Send your key as a bearer token:

```http theme={null}
Authorization: Bearer ont_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8
```

An `X-Api-Key` header is also accepted with the same value:

```http theme={null}
X-Api-Key: ont_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8
```

Prefer `Authorization: Bearer` — it is what the API Reference playground uses and what most HTTP clients handle natively.

## Key format

```text theme={null}
ont_<8 hex chars><32 hex chars>
```

The first twelve characters (`ont_` plus eight hex) are the **public prefix**. OnTime indexes on it to find the key row, then verifies the full value against a stored hash.

<Note>
  The prefix is not secret and is safe to log — it identifies which key was used without revealing it. The remaining 32 characters are the secret.
</Note>

## Issuing a key

In the admin console: **API & webhooks → Issue key**. Requires the `api:manage` permission.

<Warning>
  **The plaintext key is returned exactly once**, at the moment of issue. OnTime stores only a bcrypt hash of it. Lose it and your only option is to revoke and reissue.
</Warning>

## Revoking

Immediate — a revoked key is refused on its next request with `401`.

<Note>
  **There is no rotate action.** To rotate without downtime: issue a new key, deploy it to your consumer, confirm it works, *then* revoke the old one.
</Note>

## Scopes

A key is issued with a scope of `ReadOnly` or `ReadWrite`.

<Warning>
  **Both scopes currently grant identical access.** Every key resolves to `employee:read` and `attendance:read` — the exact permissions the two public endpoints need.

  A `ReadWrite` key does **not** grant write access, because there is no public write route to grant it against. The scope column records your operational intent and is the seam a future write endpoint would gate on. Do not build on the assumption that `ReadWrite` means anything today.
</Warning>

This is deliberate. Granting `employee:write` to a credential with nothing to write it against would mean that the day a write route is mounted under a path a key can reach, every `ReadWrite` key ever issued silently acquires it — retroactively, with no reissue and no audit trail.

## What a key acts as

A key belongs to an **organization**, not to a person.

* Every request under a key is scoped to that organization. There is no way to reach another organization's data with it.
* The key's permissions come from its scope, not from any employee's role.
* Requests are attributed in logs to the key, not to a user.

<Note>
  This differs from the **MCP server**, where a key is bound to a specific *employee* and acts with exactly that employee's permissions and scope. If you need an integration that acts as a person — respecting their approval scope — that is MCP's model, not the REST API's. See the **AI & MCP** tab.
</Note>

## Session-cookie authentication

The non-public routes under `/api/*` authenticate differently: a signed, httpOnly **session cookie** set at login, checked on every request against a live session record.

This is what the OnTime web and mobile apps use. It is stateful — revoking a session takes effect immediately rather than waiting for a token to expire.

<Warning>
  **Do not build an integration on session cookies.** It would mean storing a user's password, the session can be revoked out from under you by any administrator, and the routes behind it are internal and may change without notice. Use an API key.
</Warning>

## Handling keys safely

<Steps>
  <Step title="Never commit one">
    Environment variables or a secrets manager. The `ont_` prefix makes keys easy to detect in secret-scanning tools — use one.
  </Step>

  <Step title="One key per consumer">
    So you can revoke a single integration without breaking every other one, and so the last-used timestamp tells you something.
  </Step>

  <Step title="Log the prefix, never the key">
    The first twelve characters identify which key was used and are safe to record.
  </Step>

  <Step title="Revoke on personnel change">
    A key does not belong to a person, so nothing revokes it automatically when someone leaves.
  </Step>
</Steps>
