API version: dev

---

# Security

## Password hashing

User accounts store a password hash, never the plaintext password. Hashing uses PHP's
[`password_hash()`](https://www.php.net/manual/en/function.password-hash.php) with the `PASSWORD_ARGON2I` algorithm.
The hash is kept in the internal `_passwordHash` property, which - like all underscore-prefixed properties - can never
be read or written directly through the API.

A user's password is only ever needed to obtain a new token via [`POST /token`](/api/post-token.md) or during
[`POST /register`](/api/post-register.md). Regular requests authenticate with a token instead, as described below.

## Token format and hashing

Tokens are generated by the API, not chosen by the user, and follow the
[`secret-token:` URI scheme from RFC 8959](https://www.rfc-editor.org/rfc/rfc8959.html):

```
secret-token:<base58(16 random bytes)>
```

The plaintext token is only ever sent to the client once, in the response to the request that created it. Internally,
only its SHA-3-256 hash is stored. Unlike passwords, tokens don't need a slow, salted password-hashing algorithm -
a random 16-byte value already has enough entropy that brute-forcing the hash is infeasible.

## Authenticating a request

Every request is evaluated as one of the following:

- **No `Authorization` header**: the request is treated as coming from the [anonymous user](/reference/access-model/anonymous-user.md).
- **A well-formed `secret-token:...` bearer token**: the API hashes the token and looks it up, first in a Redis cache,
  then - on a cache miss - in the graph database, where the cache is refilled for subsequent requests.
- **A malformed, unknown, expired or revoked token**: the request is rejected with `401 Unauthorized`. An invalid
  token is never silently downgraded to an anonymous request - if a request supplies a token, it only ever executes in
  that token's context, or fails outright.

## Token lifecycle

Tokens generated through the API have a default lifetime of 3 hours, which can be changed to a duration between 30
minutes and 13 months.

The limits are [configurable](/reference/configuration.md).

**Tokens can become immortal**, when the property `expirationDate` is absent. This can not happen through API requests,
i.e. it requires the import of a specially crafted backup or direct manipulation of the token inside the Neo4j database.

## Revoking tokens

Should multiple or all tokens need to be revoked, then command [`token:revoke`](/command/token-revoke.md) can be used. It
supports filtering by user, group, and issue date, and can run as a dry run first to preview which tokens would be
affected.

Revocation takes effect immediately: the token's cache entry is cleared as part of the same command, so a revoked
token stops working right away rather than only after its cached entry would have expired on its own.

## Rate limits

Rate limiting is a [planned feature](https://github.com/ember-nexus/api/issues/104) and not yet enforced - the API
does not currently reject requests for exceeding a request rate.

## Reserved data types

A handful of node types are reserved for the API itself and can't be used as the `type` of an element you create:
`User`, `Token`, and `Upload`. Attempting to create an element with one of these types is rejected.

More generally, any property or type name starting with an underscore (`_`) is treated as internal to the API - for
example the `_passwordHash` property on `User` nodes. These are set and read by the API itself and are never exposed
through regular read/write operations. Sticking to non-underscore-prefixed names for your own data avoids clashes with
current or future internal properties.

## Reserved properties

A handful of non-underscore-prefixed properties are also reserved: the API sets them itself as a side effect of
other operations, and rejects any [`POST /<uuid>`](/api/post-element.md)/[`PUT /<uuid>`](/api/put-element.md)/
[`PATCH /<uuid>`](/api/patch-element.md) request that tries to set them directly, with `400 Bad Request`.

On every element:

- `id` - assigned once, when the element is created.
- `created` / `updated` - timestamps maintained automatically: `created` is set once, `updated` on every change.
- `file` / `hasFile` - set as a side effect of uploading, replacing, or deleting the element's file; see
  [Metadata](/reference/file.md#metadata) in the file reference.

Additionally, on `User` nodes: the property configured as the registration identifier (`email` by default). On
`Token` nodes: `token`.

---

Home: [Ember Nexus API docs](/index.md)

Full site map: [llms.txt](/llms.txt)

Previous: [Configuration](/reference/configuration.md)

Next: [File](/reference/file.md)
