# API Keys
# 1. Summary
API keys allows to define which actions and which indexes are accessible by the holder of an API key. The use of API keys allows to secure the access to the routes in a fine-grained manner of a Meilisearch instance.
# 2. Motivation
To make Meilisearch more reliable for teams and more adapted to production cases, we extend the management and the possibilities of restrictions regarding write and read requests on a Meilisearch instance by introducing a way to manage custom API keys.
# 3. Functional Specification
# 3.1. Glossary
Term | Definition |
---|---|
Master Key | This is the master key that allows managing API keys. The master key is defined by the user when launching Meilisearch, thus gives access to the /keys API endpoint and requiring requests to be authorized. |
API Key | API keys are stored and managed from the endpoint /keys by the master key holder. |
# 3.2. Explanation
# 3.2.1 Summary Key Points
- API keys management is restricted to the master key or API keys having
keys.get
,keys.create
,keys.update
,keys.delete
or*
actions. - API keys must be provided via the
Authorization
header using the bearer method to authorize a request. - The value of the
key
field of an API Key is generated from itsuid
and the master key. - When a master key is set at Meilisearch first-launch, it generate two pre-configured default
API Key
resources. ADefault Search API Key
authorizing the search action on all indexes and aDefault Admin API Key
authorizing all actions. - If the master-key changes, the
key
field is re-generated. - Default API keys can be modified/deleted from the
/keys
endpoints but are not re-created if Meilisearch has already created them. - API keys can have restrictions on which methods can be accessed via an
actions
list; they alsoexpiresAt
a specific date time and are restricted to a specific set ofindexes
. name
anddescription
fields are the only editable fields of an API key.- API key resources are propagated to snapshots and dumps.
# 3.2.2. Master Key
The master key exists to secure a Meilisearch instance. As soon as a master key is set via the MEILI_MASTER_KEY
environment variable or the --master-key
CLI option, the endpoint /keys
is accessible for the master key holder. It can be seen as a super admin key; It must be securely shared only with people who have to manage the security of a Meilisearch instance.
This master key is not an API key, thus is not stored and fetchable from the /keys
API endpoint. It must be seen as a runtime lock that activates the security of Meilisearch as soon as an instance is launched with it. The master key should only be used to fetch API Keys the first time. The default Admin API key should be preferred to manage the API keys resources.
At the first launch of Meilisearch with a master key, Meilisearch automatically generates two default API keys to cover the basic needs a user may encounter. It generates a Default Search API Key
dedicated to the search that can be used on the client-side and a Default Admin API Key
to manipulate a MeiliSearch instance from a backend side.
If the master key is removed at Meilisearch launch, the previously generated API keys no longer secure the Meilisearch instance.
If Meilisearch is launched with the production
value for the MEILI_ENV
environment variable or the --env
CLI option, a master key of at least 16 bytes is mandatory.
If the master key is omitted in that particular case, or is too short, Meilisearch launch is aborted and displays an error.
If Meilisearch is launched with the development
value for the MEILI_ENV
environment variable or the --env
CLI option, Meilisearch displays warning messages given different cases.
See MEILI_MASTER_KEY
/--master-key
launch option.
The master key must be composed of valid utf-8 characters. It is advisable to enclose it in '
when specified via the --master-key
option.
π¨ The master key should never be exposed to the public as it may compromise a Meilisearch instance.
π¨ If the value of the master key changes, all the previously generated
API Keys
changes, thus allowing to invalidate the set of API keys previously generated by regenerating a different value for theirkey
field. This is particularly useful in the case where the master key might have been leaked and the user needs to re-generate the whole set of keys at once to re-secure the instance.
The master key does not appear on the
/keys
endpoints and can't be used to authorize requests other than on the/keys
endpoint.
The only route not secured in the presence of a master key is the
/health
route.
# 3.2.3. Default API Keys
The first time a Meilisearch instance is launched with a master key
, Meilisearch will generate two API keys described below.
If the user changes the value of the master key later, these two default keys are not created again but the key
field is re-generated. However, these two API keys can be updated/deleted using the /keys
endpoints.
If these API keys are deleted, the engine should not create them again when Meilisearch is launched again with a master key.
# 3.2.3.1. Default Search API Key
The Default Search API key
gives access to the search endpoints on all indexes.
Here is how the Default Search API Key
is represented after its generation.
{
"uid": "01b4bc42-eb33-4041-b481-254d00cce834", //auto-generated value
"key": "0a6e572506c52ab0bd6195921575d23092b7f0c284ab4ac86d12346c33057f99", //auto-generated value
"name": "Default Search API Key",
"description": "Use it to search from the frontend",
"actions": [
"search"
],
"indexes": [
"*"
],
"expiresAt": null,
"createdAt": "2021-08-11T10:00:00Z",
"updatedAt": "2021-08-11T10:00:00Z"
}
# 3.2.3.2. Default Admin API Key
The Default Admin API key
gives access to all actions by default.
Here is how the Default Admin API Key
is represented after its generation.
{
"uid": "ac06a7e1-6956-4699-bb04-dbeb72a231df", //auto-generated value
"key": "380689dd379232519a54d15935750cc7625620a2ea2fc06907cb40ba5b421b6f", //auto-generated value
"name": "Default Admin API Key",
"description": "Use it for anything that is not a search operation. Caution! Do not expose it on a public frontend",
"actions": [
"*"
],
"indexes": [
"*"
],
"expiresAt": null,
"createdAt": "2021-08-11T10:00:00Z",
"updatedAt": "2021-08-11T10:00:00Z"
}
# 3.2.4. API Endpoints Definition
Manipulate API keys of a Meilisearch instance. /keys
endpoints are only accessible by the master key holder.
# 3.2.4.1. API Key
Resource Representation
field | type | description |
---|---|---|
uid | string | A unique identifier represented by a uuid v4. Can be specified at creation or generated by Meilisearch if ommited. |
key | string | The generated key to use when in the Authorization header when making requests. Generated by MeiliSearch by a combination of uid and the master key. |
name | string | A non unique human readable name to ease identification of the API key. null if empty. |
description | string | A description for the key. null if empty. |
actions | array | A list of actions permitted for the key. ["*"] for all actions. See Actions List Definition part. |
indexes | array | A list of indexes permitted for the key. ["*"] for all indexes. |
expiresAt | string | Represent the expiration date and time as RFC 3339 format. null equals to no expiration time. |
createdAt | string | Represent the date and time as RFC 3339 format when the API key has been created. Generated by MeiliSearch |
updatedAt | string | Represent the date and time as RFC 3339 format when the API key has been updated. Default: Value of createdAt . Generated by MeiliSearch |
# 3.2.4.2. GET
- /keys
Fetch the API keys of a Meilisearch instance.
# 3.2.4.2.1. Query Parameter Definition
Field | Type | Required |
---|---|---|
offset | Integer / null | false |
limit | Integer / null | false |
# offset
- Type: Integer
- Required: False
- Default:
0
Sets the starting point in the results, effectively skipping over a given number of API keys.
- π΄ Sending a value with a different type than
Integer
foroffset
returns an invalid_api_key_offset error.
# limit
- Type: Integer
- Required: False
- Default:
20
Sets the maximum number of documents to be returned by the current request.
- π΄ Sending a value with a different type than
Integer
forlimit
returns an invalid_api_key_limit error.
# 3.2.4.2.2. Response Definition
Returns a 200 Success
HTTP code when the request is successful.
Field | Type | Required |
---|---|---|
results | Array of APIKey | true |
offset | Integer | true |
limit | Integer | true |
total | Integer | true |
# results
- Type: Array[APIKey]
- Required: True
An array containing the fetched API keys.
# offset
- Type: Integer
- Required: True
Gives the offset
parameter used for the query.
# limit
- Type: Integer
- Required: True
Gives the limit
parameter used for the query.
# total
- Type: Integer
- Required: True
Gives the total number of API keys that can be browsed.
API Keys are ordered by
createdAt
indesc
order. (Most recent first)
Expired API keys can be found on the
/keys
endpoints. An archiving system or a filter could allow to not display them by default. See Future Possibilities part.
# 3.2.4.2.3. Errors
- π΄ Accessing this route while a master key is not set for the instance returns a missing_master_key error.
- π΄ Accessing this route without the
Authorization
header returns a missing_authorization_header error. - π΄ Accessing this route without the master key returns an invalid_api_key error.
# 3.2.4.2.4. Example
200 Success
{
"results": [
{
"description": "Manage Products/Reviews Documents API key",
"uid": "ac06a7e1-6956-4699-bb04-dbeb72a231df",
"key": "2fcdddd16ab75a4aeea6b74577874bc2888938a69ffafe3d05547560fa72e15b",
"actions": [
"documents.add",
"documents.delete"
],
"indexes": [
"products",
"reviews"
],
"expiresAt": "2021-12-31T23:59:59Z",
"createdAt": "2021-10-12T00:00:00Z",
"updatedAt": "2021-10-13T15:00:00Z"
},
{
"description": "Default Search API Key (Use it to search from the frontend code)",
"uid": "87861fb0-e948-41da-ae7f-89617d57d5f5",
"key": "0fe6fc6d94a21b5ca0b5a714bcb338865108039efc048e99e5ba2e7a976fa330",
"actions": [
"search"
],
"indexes": [
"*"
],
"expiresAt": null,
"createdAt": "2021-08-11T10:00:00Z",
"updatedAt": "2021-08-11T10:00:00Z"
},
{
"description": "Default Admin API Key (Use it for all other operations. Caution! Do not share it on the client side)",
"uid": "ad9af94e-d2db-420f-9ee3-9375f091e565",
"key": "1846b591d7fd0454bc2b7f1c7ad80c411b1cfe46a51b0d44e6554a30f4bc0a18",
"actions": [
"*"
],
"indexes": [
"*"
],
"expiresAt": null,
"createdAt": "2021-08-11T10:00:00Z",
"updatedAt": "2021-08-11T10:00:00Z"
}
],
"offset": 0,
"limit": 20,
"total": 3
}
π Note the two default generated API keys here. When a master key is set at MeiliSearch's launch, it generates two pre-configured
API Keys
. A Default Search API Key restricted to the search action on all indexes and a Default Admin API Key on all indexes to handle all operations (except managing API Keys).
# 3.2.4.3. GET
- /keys/:uid_or_key
Fetch a specific API key of a Meilisearch instance from it's uid
or key
field.
# 3.2.4.3.1. Query Parameter Definition
n/a
# 3.2.4.3.2. Response Definition
Returns a 200 Success
HTTP code when the request is successful.
See API Key Resource Representation section for the response body.
# 3.2.4.3.3. Errors
- π΄ Accessing this route while a master key is not set for the instance returns a missing_master_key error.
- π΄ Accessing this route without the
Authorization
header returns a missing_authorization_header error. - π΄ Accessing this route without the master key or an API key missing the
keys.get
permission returns an invalid_api_key error.
# 3.2.4.4. POST
- /keys
Create an API key.
# 3.2.4.4.1. Payload Definition
field | type | required | description |
---|---|---|---|
uid | string | Optional | A unique identifier represented by a uuid v4 (opens new window). Specified at creation or generated by Meilisearch if ommited. |
name | string | Optional | A non unique human readable name to ease identification of the API key. Default: null |
description | string | Optional | A description for the API key. Default: null |
actions | array | Required | A list of actions permitted for the API key. ["*"] for all actions. See Actions list definition part. The * character can be used as a wildcard when located at the last position. e.g. documents.* to authorize access on all documents endpoints. Default: No default |
indexes | array | Required | [*] for all indexes. The * character can be used as a wildcard when located in the last position. e.g. products_* to allow access to all indexes whose names start with products_ . Default: No Default |
expiresAt | string | Required | The expiration date and time as RFC 3339 format. null equals to no expiration time. Sending only the date part e.g 2021-12-01 leads to having an expiresAt value set to 2021-12-01T00:00:00 . Default: No Default |
# 3.2.4.4.2. actions
List Definition
:authorizedIndexes
can be any value extracted from theindexes
field of an API key resource.
name | description |
---|---|
search | Provides access to GET and POST methods on /indexes/:authorizedIndexes/search routes. |
documents.add | Provides access to POST and PUT on /indexes/:authorizedIndexes/documents routes. |
documents.get | Provides access to GET methods on /indexes/:authorizedIndexes/documents , /indexes/:authorizedIndexes/documents/:documentId and POST methods on /indexes/:authorizedIndexes/documents/fetch routes. |
documents.delete | Provides access to DELETE method on /indexes/:authorizedIndexes/documents/:documentId , indexes/:authorizedIndexes/documents/:documentId and POST method on /indexes/:authorizedIndexes/documents/delete-batch and /indexes/:authorizedIndexes/documents/delete routes. |
indexes.create | Provides access to POST /indexes . β οΈ indexes field should indicate the newly created index or having [*] to permits access on it.. |
indexes.get | Provides access to GET /indexes and /indexes/:authorizedIndexes . β οΈNon-authorized indexes are omitted from the response on /indexes . |
indexes.update | Provides access to PUT /indexes/:authorizedIndexes . |
indexes.delete | Provides access to DELETE /indexes/:authorizedIndexes . |
indexes.swap | Provides access to POST /swap-indexes . See Swap Indexes API specification. |
tasks.get | Provides access to GET /tasks . β οΈNon-authorized indexes are omitted from the response on /tasks . Also add access to GET /indexes/:authorizedIndexes/tasks routes. |
tasks.cancel | Provides access to POST /tasks/cancel . route. |
tasks.delete | Provides access to DELETE /tasks route. |
settings.get | Provides access to GET /indexes/:authorizedIndexes/settings and /indexes/:authorizedIndexes/settings/* routes. |
settings.update | Provides access to POST / DELETE /indexes/:authorizedIndexes/settings and /indexes/:authorizedIndexes/settings/* routes. |
stats.get | Provides access to GET /stats . β οΈNon-authorized indexes are omitted from the response on /stats . Also add access to GET /indexes/:authorizedIndexes/stats . |
metrics.get | Provides access to GET /metrics route. A restriction on indexes stops you from calling the route. |
dumps.create | Provides access to POST /dumps route. As dumps are not scoped by indexes, a restriction on indexes does not affect this action. |
snapshots.create | Provides access to POST /snapshots route. As snapshots are not scoped by indexes, a restriction on indexes does not affect this action. |
version | Provides access to GET /version route. |
keys.get | Provides access to GET /keys route. |
keys.create | Provides access to POST /keys route. |
keys.update | Provides access to PATCH /keys routes. |
keys.delete | Provides access to DELETE /keys routes. |
experimental.get | Provides access to GET /experimental-features routes. |
experimental.update | Provides access to PATCH /experimental-features routes. |
# 3.2.4.4.3. Response Definition
Returns a 201 Created
HTTP code when the request is successful.
See API Key Resource Representation section for the response body.
# 3.2.4.4.3. Errors
- π΄ Accessing this route while a master key is not set for the instance returns a missing_master_key error.
- π΄ Accessing this route without the
Authorization
header returns a missing_authorization_header error. - π΄ Accessing this route without the master key or an API key missing the
keys.create
permission returns an invalid_api_key error. - π΄ Omitting Content-Type header returns a missing_content_type error.
- π΄ Sending an empty Content-Type returns an invalid_content_type error.
- π΄ Sending a different Content-Type than
application/json
returns an invalid_content_type error. - π΄ Sending an empty payload returns a missing_payload error.
- π΄ Sending a different payload type than the Content-Type header returns a malformed_payload error.
- π΄ Sending an invalid json format returns a malformed_payload error.
- π΄ Omitting
actions
field from the payload returns a missing_api_key_actions error. - π΄ Omitting
indexes
field from the payload returns a missing_api_key_indexes error. - π΄ Omitting
expiresAt
field from the payload returns a missing_api_key_expires_at error. - π΄ Sending an
uid
field that already exists returns an api_key_already_exists error. - π΄ Sending an invalid value for the
uid
field returns an invalid_api_key_uid error. - π΄ Sending an invalid value for the
actions
field returns an invalid_api_key_actions error. - π΄ Sending an invalid value for the
indexes
field returns an invalid_api_key_indexes error. - π΄ Sending an invalid value for the
expiresAt
field returns an invalid_api_key_expires_at error. - π΄ Sending an invalid value for the
name
field returns an invalid_api_key_name error. - π΄ Sending an invalid value for the
description
field returns an invalid_api_key_description error.
# 3.2.4.5. PATCH
- /keys/:uid_or_key
Update an API key found by it's uid
or key
field. Only the name
and description
fields of an API key can be modified.
# 3.2.4.5.1. Payload Definition
field | type | required | description |
---|---|---|---|
name | string | Optional | A name for the API Key. Default: null |
description | string | Optional | A description for the API key. Default: null |
# 3.2.4.5.2. Response Definition
Returns a 200 Success
HTTP code when the request is successful.
See API Key Resource Representation section for the response body.
# 3.2.4.5.3. Errors
- π΄ Accessing this route while a master key is not set for the instance returns a missing_master_key error.
- π΄ Accessing this route without the
Authorization
header returns a missing_authorization_header error. - π΄ Accessing this route without the master key or an API key missing the
keys.update
permission returns an invalid_api_key error. - π΄ Attempting to access an API key that does not exist returns a api_key_not_found error.
- π΄ Omitting Content-Type header returns a missing_content_type error.
- π΄ Sending an empty Content-Type returns an invalid_content_type error.
- π΄ Sending a different Content-Type than
application/json
returns an invalid_content_type error. - π΄ Sending an empty payload returns a missing_payload error.
- π΄ Sending a different payload type than the Content-Type header returns a malformed_payload error.
- π΄ Sending an invalid json format returns a malformed_payload error.
- π΄ Sending an invalid value for the
name
field returns an invalid_api_key_name error. - π΄ Sending an invalid value for the
description
field returns an invalid_api_key_description error. - π΄ Sending
uid
in the payload request returns an immutable_api_key_uid error. - π΄ Sending
key
in the payload request returns an immutable_api_key_key error. - π΄ Sending
actions
in the payload request returns an immutable_api_key_actions error. - π΄ Sending
indexes
in the payload request returns an immutable_api_key_indexes error. - π΄ Sending
expiresAt
in the payload request returns an immutable_api_key_expires_at error. - π΄ Sending
createdAt
in the payload request returns an immutable_api_key_created_at error. - π΄ Sending
updatedAt
in the payload request returns an immutable_api_key_updated_at error.
# 3.2.4.6. DELETE
- /keys/:uid_or_key
Delete an API key found by it's uid
or key
field.
# 3.2.4.6.1. Payload Definition
n/a
# 3.2.4.6.2. Response Definition
Returns a 204 No-Content
HTTP code when the request is successful.
# 3.2.4.6.3. Errors
- π΄ Accessing this route while a master key is not set for the instance returns a missing_master_key error.
- π΄ Accessing this route without the
Authorization
header returns a missing_authorization_header error. - π΄ Accessing this route without the master key or an API key missing the
keys.delete
permission returns an invalid_api_key error. - π΄ Attempting to access an API key that does not exist returns a
api_key_not_found
error.
# 3.2.4.7. Using an API key on client-code
# 3.2.4.7.1 Authorization Bearer Header
When the Meilisearch API is secured by the presence of a master key, the Authorization
header must be used with a bearer to authorize requests. The specified value must be the value of the key
field of an API key.
"Authorization: Bearer `:key`"
"Content-Type: application/json"
- π΄ Accessing a route with an
API Key
that has expired, been deleted or don't have sufficient permissions returns an invalid_api_key error.
# 4. Technical Aspects
# 4.1. API Key generation
An uid
representing by a uuid v4 is generated if not specified at creation by the user.
The final key is then an HMAC with the master key, as the secret, and the uid
, a hyphenated Uuidv4, as the data. HMAC uses an SHA-256 algorithm internally.
The final key could be generated with openssl as below:
echo -n $HYPHENATED_UUID | openssl dgst -sha256 -hmac $MASTER_KEY
# 4.2. Synchronous write of API Key
resources
Writing to /keys
endpoints are synchronous in order to return errors directly to the user when he performs an operation on them. This means that API key management operations do not appear as a task on /tasks
.
# 4.3. Propagating API Key
to dumps.
The generated API keys must also transit within a dump to facilitate the upgrade of a MeiliSearch instance.
π¨ As a reminder, dumps must be stored in secure areas not accessible to the public or unaccredited persons. In general, you should avoid moving them off the host machine or do so via a secure channel as a security measure.
If the dumps ever leak, the api keys cannot be spoofed from the dump inspection because it needs the master key to have the full value of a valid API key. Only the uid
value is propagated in the dumps.
# 4.4. Propagating API Key
to snapshots.
The generated API keys must also transit within a snapshot to facilitate the recovery of a MeiliSearch instance.
π¨ As a reminder, snapshots must be stored in secure areas not accessible to the public or unaccredited persons. In general, you should avoid moving them off the host machine or do so via a secure channel as a security measure.
If the snapshot ever leak, the API keys
cannot be spoofed from the snapshot inspection because it needs the master key to have the full value of a valid API key
. Only the uid
value is propagated in the snapshots.
# 4.5. API Keys storage size limit
The maximum size of the API key storage layer is 100GB
.
# 5. Future Possibilities
- Regenerate a specific
API Key
. - Have an "archive" state where manually deleted API Keys can be restored for a certain amount of time.
- Add rate-limiting per API Key.
- A restriction on the maximum offset/limit.
- Add search parameters restrictions for an API Key.
- Add rfc2822 format expression for
expiredAt
field. e.g.Wed, 18 Feb 2022 23:16:09 GMT
- Add an alias that can only be associated to one API Key to retrieve it easily on client side. e.g.
GET /keys/:uid_or_alias
- Supports wildcard expressions at the start/middle of a string.
β Words position limit Tenant tokens β