diff --git a/open-api.yaml b/open-api.yaml index 8a6434950..859f5f422 100644 --- a/open-api.yaml +++ b/open-api.yaml @@ -584,9 +584,13 @@ components: title: key type: object properties: + uid: + type: string + description: A uuid v4 to identify the API Key. If not specified, it's generated by Meilisearch. + example: 01b4bc42-eb33-4041-b481-254d00cce834 key: type: string - description: The generated key. Generated by Meilisearch. + description: The derived key to use in the Authorization header to authorize requests. Generated by Meilisearch with a SHA-256 hash of the uid and the master key. example: d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4 readOnly: true actions: @@ -618,6 +622,12 @@ components: items: type: string example: movies + name: + type: + - string + - 'null' + description: A human-readable name for the key. null if empty. + default: null description: type: - string @@ -2643,20 +2653,22 @@ paths: example-1: value: results: - - key: d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4 + - uid: 01b4bc42-eb33-4041-b481-254d00cce834 + key: d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4 + name: An API Key + description: null actions: - documents.add indexes: - movies - description: An API Key expiresAt: '2022-11-12T10:00:00Z' createdAt: '2021-11-12T10:00:00Z' updatedAt: '2021-11-12T10:00:00Z' '401': $ref: '#/components/responses/401' - '/keys/{key}': + '/keys/{uid}': get: - summary: Get an API key + summary: Get an API key from its uid tags: - Keys security: @@ -2671,8 +2683,10 @@ paths: examples: Fetch an API Key details: value: - description: Indexing Products API key + uid: 01b4bc42-eb33-4041-b481-254d00cce834 key: d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4 + name: Indexing Products API key + description: null actions: - documents.add indexes: @@ -2717,8 +2731,10 @@ paths: examples: Patch an API Key Response: value: - description: Indexing Products API key + uid: 01b4bc42-eb33-4041-b481-254d00cce834 key: d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4 + name: Indexing Products API key + description: null actions: - documents.add indexes: @@ -2733,7 +2749,17 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/key' + type: object + properties: + name: + type: + - string + - 'null' + description: + type: + - string + - 'null' + additionalProperties: false examples: Patch an API Key Request: value: @@ -2755,8 +2781,10 @@ paths: examples: Create an API Key: value: - description: Indexing Products API key + uid: 01b4bc42-eb33-4041-b481-254d00cce834 key: d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4 + name: Indexing Products API key + description: null actions: - documents.add indexes: @@ -2774,7 +2802,7 @@ paths: examples: API Key Creation: value: - description: Indexing Products API key + name: Indexing Products API key actions: - documents.add indexes: diff --git a/text/0085-api-keys.md b/text/0085-api-keys.md index ef49134da..6a2db45b3 100644 --- a/text/0085-api-keys.md +++ b/text/0085-api-keys.md @@ -1,89 +1,81 @@ -- Title: API Keys -- Start Date: 2021-10-15 -- Specification PR: [#85](https://github.com/meilisearch/specifications/pull/85) -- Discovery Issue: [#51](https://github.com/meilisearch/product/issues/51) - # API Keys -## 1. Functional Specification +## 1. Summary -### 1.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. -Granular management of API keys is added to MeiliSearch. It is possible to restrict the access of an API key to certain actions on specific indexes. +## 2. Motivation -### 1.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. -To make MeiliSearch more reliable for teams, we extend the management and the possibilities of restrictions for the management of a MeiliSearch instance by introducing a concrete API resource (`API Key`). Security is a critical need, often tricky to negotiate as the stakes are high for a company. +## 3. Functional Specification -### 1.3 Glossary +### 3.1. Glossary | Term | Definition | |--------------------|------------| -| Master Key | This is the master key that allows you to create other API keys. The master key is defined by the user when launching MeiliSearch, thus gives access to the `/keys` API endpoint. | -| API Key | API keys are stored and managed from the endpoint `/keys` by the master key holder. These are the keys used by the technical teams to interact with MeiliSearch at the level of the client code. | - -### 1.4 Personas +| 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. | -| Persona | Role | -|---------|------| -| Anna | Anna has an `ssh` access to the MeiliSearch instance and manages it on a daily basis. | -| Mark | Mark is a developer from the same company as Anna. He will implement the code to communicate with MeiliSearch to solve technical/product needs. | +### 3.2. Explanation -### 1.5 `API Key` Explanations +#### 3.2.1 Summary Key Points -#### 1.5.1 Summary Key Points +- API keys management is restricted to the master key holder. +- 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 its `uid` and the master key. +- When a master key is set at Meilisearch first-launch, it generate two pre-configured default `API Key` resources. A `Default Search API Key` authorizing the search action on all indexes and a `Default Admin API Key` authorizing all actions on all indexes (except managing `/keys` resource). +- If the master-key changes, all `key` field are re-generated. +- Default API keys can be modified/deleted from the `/keys` endpoints but are not re-created if Meilisearch has already created them. +- The master key can only be used to manage API keys. Using the master-key for any other request other than on `/keys` returns an authorization error. +- API keys can have restrictions on which methods can be accessed via an `actions` list; they also `expiresAt` a specific date time and are restricted to a specific set of `indexes`. +- `name` and `description` fields are the only editable fields of an API key. +- API key resources are propagated to snapshots and dumps. -- `X-MEILI-API-KEY` header is replaced by the `Authorization` header. `API keys` must be specified with the bearer authorization method. See examples. -- `/keys` management is restricted to the master key. -- When a master key is set at MeiliSearch first-launch, we generate two pre-configured default `API Key` resources. A `Default Search API Key` restricted to the search action and a `Default Admin API Key` to handle all operations (except managing `/keys` resource) on MeiliSearch. -- If the master-key changes, all `API Keys` are re-generated. -- These default API Keys can be modified/deleted with the `/keys` endpoint but are not re-created if MeiliSearch has already created them. -- New endpoints are added to manage the `API Key` resource. -- `API keys` can have restrictions on which methods can be accessed via an `actions` list; they can also `expiresAt` a specific date time and be restricted to a specific set of `indexes`. -- There is no possibility to regenerate the value of the `key` field for a specific `API key` in this first iteration. -- New errors are added and the `missing_authorization_header` message is updated. -- The current state of the `API Keys` resource is propagated to snapshots and dumps. +#### 3.2.2. Master Key -#### 1.5.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. -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 only for the master key holder. It can be seen as a super admin key; It must be 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 can only be used to manage API Keys. Using the master key for any other request other than on `/keys` returns an authorization error. -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. +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. -At the first launch of MeiliSearch with a master key, MeiliSearch automatically generates two default API keys (See the `GET - /keys` example) to cover many of the most basic needs. 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 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 is mandatory. If the master key is omitted in that particular case, MeiliSearch launch is aborted and displays an error: -If MeiliSearch is launched with the `production` value for the `MEILI_ENV` environment variable or the `--env` CLI option, a master key is mandatory to force the user to secure his instance. If the master key is omitted in that particular case, MeiliSearch launch is aborted and displays the `Error: In production mode, the environment variable MEILI_MASTER_KEY is mandatory` error in stdout. +`Error: In production mode, the environment variable MEILI_MASTER_KEY is mandatory` -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 must be composed of valid utf-8 characters. It is advisable to enclose it in `'` when specified via the `--master-key` option. -> 🚨 A user coming from a version prior to v0.25.0 and having a master-key will have to update their code to use the newly generated default keys replacing the public and private, since we changed the previous `public` and `private` API Key generation, is it mandatory for that specific version upgrade. Now, a prefix of an API Key is generated uniquely and the final value of the `key` field is a hash of that randomized prefix with the master-key. See 2.1 API Key Generation part. +> 🚨 The master key should never be exposed to the public as it may compromise a Meilisearch instance. -> 🚨 The master-key should never be exposed to the public or bad-intentioned persons for security measures as it may compromise a MeiliSearch instance. +> 🚨 If the value of the master key changes, all the previously generated `API Keys` changes, thus allows to invalidate the set of API keys previously generated by regenerating a different value for their `key` field. This is particularly useful in the case where the master key might have been leaked and the user need to re-generate the whole set of keys at once to re-secure the instance. -> 🚨 If the value of the master key changes, all the previously generated `API Keys` changes, thus allows to invalidate the set of keys previously generated by regenerating to a different value for the `key` field. This is particularly useful in the case where the master key might have been leaked and the user need 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. -> Note that the master key does not appear on the `/keys` endpoints. +> The only route not secured in the presence of a master key is the `/health` route. -#### 1.5.3 Default API Keys +#### 3.2.3. Default API Keys -When the user accessing the machine launches MeiliSearch with a `master` key the first time, MeiliSearch will generate two API keys described below, as it did before with the `public` and `private` key. +The first time a Meilisearch 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 re-generated with a different `key` field. However, these two API keys can be changed using the `/keys` endpoints. +If the user changes the value of the master key later, these two default keys are not created again but re-generated with a different `key` field. However, these two API keys can be updated/deleted using the `/keys` endpoints. -MeiliSearch must know that it has already generated these Default API Keys internally so if the user delete them, the engine should not create them again when MeiliSearch is launched again with a `master` key. +If these API keys are deleted, the engine should not create them again when Meilisearch is launched again with a master key. -##### 1.5.3.1 Default Search API Key +##### 3.2.3.1. Default Search API Key -The `Default Search API key` gives access to the same rights as the old `public` 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. -```json +```jsonc { - "description": "Default Search API Key (Use it to search from the frontend)", - "key": "0a6e572506c52ab0bd6195921575d23092b7f0c284ab4ac86d12346c33057f99", //example + "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" ], @@ -91,21 +83,23 @@ Here is how the `Default Search API Key` is represented after its generation. "*" ], "expiresAt": null, - "createdAt": "2021-08-11T10:00:00Z", //example + "createdAt": "2021-08-11T10:00:00Z", "updatedAt": "2021-08-11T10:00:00Z" } ``` -##### 1.5.3.2 Default Admin API Key +##### 3.2.3.2. Default Admin API Key -The `Default Admin API key` gives access to the same rights as the old `private` key. +The `Default Admin API key` gives access to all actions on all indexes except managing the API Keys. Here is how the `Default Admin API Key` is represented after its generation. -```json +```jsonc { - "description": "Default Admin API Key (Use it for all other operations. Caution! Do not use it on a public frontend)", - "key": "380689dd379232519a54d15935750cc7625620a2ea2fc06907cb40ba5b421b6f", //example + "uid": "ac06a7e1-6956-4699-bb04-dbeb72a231df", //auto-generated value + "key": "380689dd379232519a54d15935750cc7625620a2ea2fc06907cb40ba5b421b6f", //auto-generated value + "name": "Default Admin API Key", + "description": "(Use it for all other than search operations. Caution! Do not expose it on a public frontend)", "actions": [ "*" ], @@ -113,46 +107,88 @@ Here is how the `Default Admin API Key` is represented after its generation. "*" ], "expiresAt": null, - "createdAt": "2021-08-11T10:00:00Z", //example + "createdAt": "2021-08-11T10:00:00Z", "updatedAt": "2021-08-11T10:00:00Z" } ``` -#### 1.5.3 Managing `API Key` - -![](https://i.imgur.com/mAUFnNb.png) - -`Anna` manages the MeiliSearch instance; she uses the master key she defined at startup to generate an `API Key` resource for `Mark` to use in his client code to communicate with the MeiliSearch instance. - -`Anna` can define access rights to certain indexes to define an expiration date and also authorized `actions` for an `API Key` (See API Key Actions List Definition Part). +#### 3.2.4. API Endpoints Definition -Only the master key allows managing the API keys. +Manipulate API keys of a Meilisearch instance. `/keys` endpoints are **only accessible by the master key holder.** -#### 1.5.4 `API Key` object representation +##### 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. | -| key | string | The generated key. **Generated by MeiliSearch**. | -| actions | array | A list of actions permitted for the key. `["*"]` for all actions. See Actions list definition part. | +| 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** | -#### 1.5.5 `POST`/ `PATCH` - `/keys` - API Key object payload definition +##### 3.2.4.2. `GET` - `/keys` + +Fetch the API keys of a Meilisearch instance. + +###### 3.2.4.2.1. Query Parameter Definition + +n/a + +###### 3.2.4.2.2. Response Definition + +Returns a `200 Success` HTTP code when the request is successful. + +| Field | Type | Required | +|-----------|----------------------------------------------------------|----------| +| `results` | Array of [API Key](#3241-api-key-resource-representation)| true | + +> API Keys are ordered by `createdAt` in `desc` order. (Most recent first) + +###### 3.2.4.2.3. Errors + +- 🔴 Accessing this route without the `Authorization` header returns a [missing_authorization_header](0061-error-format-and-definitions.md#missing_authorization_header) error. +- 🔴 Accessing this route without the master key returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. + +##### 3.2.4.3. `GET` - `/keys/:uid` + +Fetch a specific API key of a Meilisearch instance from it's `uid` 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](#3241-api-key-resource-representation) section for the response body. + +###### 3.2.4.3.3. Errors + +- 🔴 Accessing this route without the `Authorization` header returns a [missing_authorization_header](0061-error-format-and-definitions.md#missing_authorization_header) error. +- 🔴 Accessing this route without the master key returns an [invalid_api_key](0061-error-format-and-definitions.md#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 | |-------------|---------|----------|--------------------------------| -| indexes | array | Required | `[*]` for all indexes. **Default**: `No Default` | +| uid | string | Optional | A unique identifier represented by uuid v4. 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**. `*` character can be used as a wildcard. e.g. `documents.*` to authorize access on all documents endpoints. **Default**: `No default` | +| indexes | array | Required | `[*]` for all indexes. **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 -#### 1.5.6 Actions List Definition - -> `:authorizedIndexes` can be any value extracted from the `indexes` field of an `API key` resource. +> `:authorizedIndexes` can be any value extracted from the `indexes` field of an API key resource. | name | description | |---------|-------------| @@ -172,63 +208,16 @@ Only the master key allows managing the API keys. | dumps.get | Provides access to `GET` `/dumps/:dumpUid` route. **As dumps are not scoped by indexes, a restriction on `indexes` does not affect this action.** | | version | Provides access to `GET` `/version` route. ---- +###### 3.2.4.4.3. Response Definition -#### **As `Anna 👩`, I want to create an `API key` for `Mark 👨🏻` client-code, so that he can index some documents into MeiliSearch** +Returns a `201 Created` HTTP code when the request is successful. -##### Request Definition +See [API Key Resource Representation](#3241-api-key-resource-representation) section for the response body. -`POST` - `/keys` - -##### Headers - -``` -"Authorization: Bearer :masterKey" -"Content-Type: application/json" -``` - -##### Body Payload - -```json -{ - "description": "Indexing Products API key", - "actions": [ - "documents.add" - ], - "indexes": ["products"], - "expiresAt": "2021-11-13T00:00:00Z" -} -``` - -##### Response - -`201 Created` - -```json -{ - "description": "Indexing Products API key", - "key": "d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4", - "actions": [ - "documents.add" - ], - "indexes": ["products"], - "expiresAt": "2021-11-13T00:00:00Z", - "createdAt": "2021-11-12T10:00:00Z", - "updatedAt": "2021-11-12T10:00:00Z" -} -``` - -##### Requirements - -- `actions` is mandatory and should be an array of valid `actions`. -- `indexes` is mandatory and should be an array of string. -- `expiresAt` is mandatory and must be a valid `RFC 3339` datetime in the future or `null`. -- If set, `description` should be a string or `null`. - -##### Errors +###### 3.2.4.4.3. Errors - 🔴 Accessing this route without the `Authorization` header returns a [missing_authorization_header](0061-error-format-and-definitions.md#missing_authorization_header) error. -- 🔴 Accessing this route with a key that does not have permissions (i.e. other than the master-key) returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. +- 🔴 Accessing this route without the master key returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. - 🔴 Omitting Content-Type header returns a [missing_content_type](0061-error-format-and-definitions.md#missing_content_type) error. - 🔴 Sending an empty Content-Type returns an [invalid_content_type](0061-error-format-and-definitions.md#invalid_content_type) error. - 🔴 Sending a different Content-Type than `application/json` returns an [invalid_content_type](0061-error-format-and-definitions.md#invalid_content_type) error. @@ -238,111 +227,34 @@ Only the master key allows managing the API keys. - 🔴 Omitting `actions` field from the payload returns a [missing_parameter](0061-error-format-and-definitions.md#missing_parameter) error. - 🔴 Omitting `indexes` field from the payload returns a [missing_parameter](0061-error-format-and-definitions.md#missing_parameter) error. - 🔴 Omitting `expiresAt` field from the payload returns a [missing_parameter](0061-error-format-and-definitions.md#missing_parameter) error. +- 🔴 Sending an invalid value for the `uid` field returns an [invalid_api_key_uid](0061-error-format-and-definitions.md#invalid_api_key_uid). - 🔴 Sending an invalid value for the `actions` field returns an [invalid_api_key_actions](0061-error-format-and-definitions.md#invalid_api_key_actions) error. - 🔴 Sending an invalid value for the `indexes` field returns an [invalid_api_key_indexes](0061-error-format-and-definitions.md#invalid_api_key_indexes) error. - 🔴 Sending an invalid value for the `expiresAt` field returns an [invalid_api_key_expires_at](0061-error-format-and-definitions.md#invalid_api_key_expires_at) error. +- 🔴 Sending an invalid value for the `name` field returns an [invalid_api_key_name](0061-error-format-and-definitions.md#invalid_api_key_name) error. - 🔴 Sending an invalid value for the `description` field returns an [invalid_api_key_description](0061-error-format-and-definitions.md#invalid_api_key_description) error. ---- - -#### **As `Anna 👩`, I want to get details about an `API Key`** - -##### Request Definition - -`GET` - `/keys/:key` - -##### Headers - -``` -"Authorization: Bearer :masterKey" -``` - -##### Response - -`200 Success` - -```json -{ - "description": "Indexing API key", - "key": "d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4", - "actions": [ - "documents.add" - ], - "indexes": [ - "products" - ], - "expiresAt": "2021-11-13T00:00:00Z", - "createdAt": "2021-11-12T10:00:00Z", - "updatedAt": "2021-11-12T10:00:00Z" -} -``` - -##### Errors - -- 🔴 Accessing this route without the `Authorization` header returns a [missing_authorization_header](0061-error-format-and-definitions.md#missing_authorization_header) error. -- 🔴 Accessing this route with a key that does not have permissions (i.e. other than the master-key) returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. -- 🔴 Attempting to access an API key that does not exist returns an [api_key_not_found](0061-error-format-and-definitions.md#api_key_not_found) error. - ---- - -#### **As `Anna 👩`, I want to update API key to change its restrictions** - -##### Request Definition - -`PATCH` - `/keys/:key` - -##### Headers - -``` -"Authorization: Bearer :masterKey" -"Content-Type: application/json" -``` +##### 3.2.4.5. `PATCH` - `/keys/:uid` -##### Body Payload +Update an API key found by its `uid`. Only the `name` and `description` fields of an API key can be modified. -> PATCH method allows making partial changes to an existing resource. Thus the user is not obliged to send the complete API resource for each update. +###### 3.2.4.5.1. Payload Definition -```json -{ - "description": "Manage Products/Reviews Documents API key", //Update the description to specify the API Key purposes. - "actions": [ - "documents.add", - "documents.delete" //Has now access to documents deletion - ], - "indexes": [ - "products", - "reviews" - ], //Has now access to reviews - "expiresAt": "2021-12-31T23:59:59Z" //Extended to the end of the year -} -``` +| 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` | -##### Response +###### 3.2.4.5.2. Response Definition -`200 Success` +Returns a `200 Success` HTTP code when the request is successful. -```json -{ - "description": "Manage Products/Reviews Documents API key", - "key": "d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4", - "actions": [ - "documents.add", - "documents.delete" - ], - "indexes": [ - "products", - "reviews" - ], - "expiresAt": "2021-12-31T23:59:59Z", - "createdAt": "2021-11-12T10:00:00Z", - "updatedAt": "2021-10-12T15:00:00Z" -} -``` +See [API Key Resource Representation](#3241-api-key-resource-representation) section for the response body. -##### Errors +###### 3.2.4.5.3. Errors - 🔴 Accessing this route without the `Authorization` header returns a [missing_authorization_header](0061-error-format-and-definitions.md#missing_authorization_header) error. -- 🔴 Accessing this route with a key that does not have permissions (i.e. other than the master-key) returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. +- 🔴 Accessing this route without the master key returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. - 🔴 Attempting to access an API key that does not exist returns a [api_key_not_found](0061-error-format-and-definitions.md#api_key_not_found) error. - 🔴 Omitting Content-Type header returns a [missing_content_type](0061-error-format-and-definitions.md#missing_content_type) error. - 🔴 Sending an empty Content-Type returns an [invalid_content_type](0061-error-format-and-definitions.md#invalid_content_type) error. @@ -350,201 +262,79 @@ Only the master key allows managing the API keys. - 🔴 Sending an empty payload returns a [missing_payload](0061-error-format-and-definitions.md#missing_payload) error. - 🔴 Sending a different payload type than the Content-Type header returns a [malformed_payload](0061-error-format-and-definitions.md#malformed_payload) error. - 🔴 Sending an invalid json format returns a [malformed_payload](0061-error-format-and-definitions.md#malformed_payload) error. -- 🔴 Sending an invalid value for the `actions` field returns an [invalid_api_key_actions](0061-error-format-and-definitions.md#invalid_api_key_actions) error. -- 🔴 Sending an invalid value for the `indexes` field returns an [invalid_api_key_indexes](0061-error-format-and-definitions.md#invalid_api_key_indexes) error. -- 🔴 Sending an invalid value for the `expiresAt` field returns an [invalid_api_key_expires_at](0061-error-format-and-definitions.md#invalid_api_key_expires_at) error. +- 🔴 Sending an invalid value for the `name` field returns an [invalid_api_key_name](0061-error-format-and-definitions.md#invalid_api_key_name) error. - 🔴 Sending an invalid value for the `description` field returns an [invalid_api_key_description](0061-error-format-and-definitions.md#invalid_api_key_description) error. ---- - -#### **As `Anna 👩`, I want to list the API Keys** - -##### Request Definition +##### 3.2.4.6. `DELETE` - `/keys/:uid` -`GET` - `/keys` +Delete an API key found by its `uid`. -##### Headers +###### 3.2.4.6.1. Payload Definition +n/a -``` -"Authorization: Bearer :masterKey" -``` +###### 3.2.4.6.2. Response Definition -##### Response +Returns a `204 No-Content` HTTP code when the request is successful. -`200 Success` - -```json -{ - "results": [ - { - "description": "Manage Products/Reviews Documents API key", - "key": "d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4", - "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)", - "key": "0a6e572506c52ab0bd6195921575d23092b7f0c284ab4ac86d12346c33057f99", - "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)", - "key": "380689dd379232519a54d15935750cc7625620a2ea2fc06907cb40ba5b421b6f", - "actions": [ - "*" - ], - "indexes": [ - "*" - ], - "expiresAt": null, - "createdAt": "2021-08-11T10:00:00Z", - "updatedAt": "2021-08-11T10:00:00Z" - } - ] -} -``` - -> 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. - -> 👉 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). - -##### List details - -- `API Key` objects are returned in a `results` array. -- `API Keys` are ordered by `createdAt` in `desc` order. (Most recent first) -- No pagination yet. See Future Possibilities part. - -##### Errors +###### 3.2.4.6.3. Errors - 🔴 Accessing this route without the `Authorization` header returns a [missing_authorization_header](0061-error-format-and-definitions.md#missing_authorization_header) error. -- 🔴 Accessing this route with a key that does not have permissions (i.e. other than the master-key) returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. +- 🔴 Accessing this route without the master key returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. +- 🔴 Attempting to access an API key that does not exist returns a [`api_key_not_found`](0061-error-format-and-definitions.md#api_key_not_found) error. ---- +##### 3.2.4.7. Using an API key on client-code -#### **As `Anna 👩`, I want to delete an `API Key`** +###### 3.2.4.7.1 Authorization Bearer Header -##### Request Definition - -`DELETE` - `/keys/:key` - -##### Headers +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 :masterKey" -``` - -##### Response - -`204 No-Content` - -##### Errors - -- 🔴 Accessing this route without the `Authorization` header returns a [missing_authorization_header](0061-error-format-and-definitions.md#missing_authorization_header) error. -- 🔴 Accessing this route with a key that does not have permissions (i.e. other than the master-key) returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. -- 🔴 Attempting to access an API key that does not exist returns a `api_key_not_found`. - ---- - -#### Using `API Key` on client-code - -![](https://i.imgur.com/kRKcB43.png) - -`Mark 👨🏻` receives the `API Key` transmitted by `Anna 👩` on a secured channel of their choice. He uses it to authenticate requests from the client code to MeiliSearch. - -#### **As `Mark 👨🏻`, I am using an expired/deleted API Key** - -#### Request example - -`POST` - `/indexes/movies/search` - -#### Headers - -``` - "Authorization: Bearer :apiKey" + "Authorization: Bearer `:key`" "Content-Type: application/json" ``` -#### Response - -- 🔴 Accessing this route with an `API Key` that has expired or, been deleted returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. - ---- - -### **As `Mark 👨🏻`, I am using a valid API Key, but the permission set is not sufficient to access the requested API resource** - -#### Request example - -`POST` - `/indexes/movies/search` - -#### Headers - -``` - "Authorization: Bearer :apiKey" - "Content-Type: application/json" -``` - -#### Response - -- 🔴 Accessing this route with an `API Key` that don't have sufficient permissions to access it returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. +- 🔴 Accessing a route with an `API Key` that has expired, been deleted or don't have sufficient permissions returns an [invalid_api_key](0061-error-format-and-definitions.md#invalid_api_key) error. -## 2. Technical Aspects +## 4. Technical Aspects -### 2.1 API Key generation +### 4.1. API Key generation -A prefix of 8 characters is randomly generated per key and is stored within the instance. +An `uid` representing an uuid v4 is generated if not specified at creation by the user. -The final key is then a SHA-2556 hash made of the prefix and the master-key concatenation. +The final key is then a SHA-2556 hash made of the `uid` and the master key concatenation. -`SHA-256(:randomizedPrefix, :master-key)` gives the final `key` field to use. +`SHA-256(:uid, :master-key)` gives the final `key` field to use when authorizing requests. -### 2.2 Synchronous write of `API Key` resources +### 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. +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`. -### 2.3 Propagating `API Key` to a dump. +### 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 randomized prefixes are propagated in the dumps. +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. -### 2.4 Propagating `API Key` to snapshots. +### 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 randomized prefixes are propagated in the snapshots. +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. -### 2.5 API Keys storage size limit +### 4.5. API Keys storage size limit -The maximum size of the API key storage is `100GB`. +The maximum size of the API key storage layer is `100GB`. -## 3. Future Possibilities +## 5. Future Possibilities - Regenerate a specific `API Key`. -- Add a generated id field to paginate the list of API Key. -- Have a filer/dedicated route to fetch expired key if MeiliSearch do not display them by default on `/keys` in the future. - 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` \ No newline at end of file +- 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` \ No newline at end of file