Skip to content

Commit 700e37d

Browse files
Merge #1738
1738: v0.28: API key updates r=guimachiavelli a=maryamsulemani97 closes #1699 Co-authored-by: Maryam Sulemani <[email protected]> Co-authored-by: Maryam <[email protected]>
2 parents be72894 + 1f6241d commit 700e37d

File tree

6 files changed

+190
-86
lines changed

6 files changed

+190
-86
lines changed

.code-samples.meilisearch.yaml

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,11 @@ get_all_tasks_paginating_2: |-
9999
-X GET 'http://localhost:7700/tasks?limit=2&from=8
100100
get_one_key_1: |-
101101
curl \
102-
-X GET 'http://localhost:7700/keys/d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4' \
102+
-X GET 'http://localhost:7700/keys/6062abda-a5aa-4414-ac91-ecd7944c0f8d' \
103103
-H 'Authorization: Bearer MASTER_KEY'
104104
get_all_keys_1: |-
105105
curl \
106-
-X GET 'http://localhost:7700/keys' \
106+
-X GET 'http://localhost:7700/keys?limit=3' \
107107
-H 'Authorization: Bearer MASTER_KEY'
108108
create_a_key_1: |-
109109
curl \
@@ -118,24 +118,16 @@ create_a_key_1: |-
118118
}'
119119
update_a_key_1: |-
120120
curl \
121-
-X PATCH 'http://localhost:7700/keys/d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4' \
121+
-X PATCH 'http://localhost:7700/keys/6062abda-a5aa-4414-ac91-ecd7944c0f8d' \
122122
-H 'Authorization: Bearer MASTER_KEY' \
123123
-H 'Content-Type: application/json' \
124124
--data-binary '{
125-
"description": "Manage documents: Products/Reviews API key",
126-
"actions": [
127-
"documents.add",
128-
"documents.delete"
129-
],
130-
"indexes": [
131-
"products",
132-
"reviews"
133-
],
134-
"expiresAt": "2042-04-02T00:42:42Z"
125+
"name": "Products/Reviews API key",
126+
"description": "Manage documents: Products/Reviews API key"
135127
}'
136128
delete_a_key_1: |-
137129
curl \
138-
-X DELETE 'http://localhost:7700/keys/d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4' \
130+
-X DELETE 'http://localhost:7700/keys/6062abda-a5aa-4414-ac91-ecd7944c0f8d' \
139131
-H 'Authorization: Bearer MASTER_KEY'
140132
get_settings_1: |-
141133
curl \
@@ -786,10 +778,10 @@ security_guide_search_key_1: |-
786778
-H 'Authorization: Bearer API_KEY'
787779
security_guide_update_key_1: |-
788780
curl \
789-
-X PATCH 'http://localhost:7700/keys/d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4' \
781+
-X PATCH 'http://localhost:7700/keys/74c9c733-3368-4738-bbe5-1d18a5fecb37 \
790782
-H 'Authorization: Bearer MASTER_KEY' \
791783
-H 'Content-Type: application/json' \
792-
--data-binary '{ "indexes": ["doctors"] }'
784+
--data-binary '{ "description": "Default Search API Key" }'
793785
security_guide_create_key_1: |-
794786
curl \
795787
-X POST 'http://localhost:7700/keys' \
@@ -807,7 +799,7 @@ security_guide_list_keys_1: |-
807799
-H 'Authorization: Bearer MASTER_KEY'
808800
security_guide_delete_key_1: |-
809801
curl \
810-
-X DELETE 'http://localhost:7700/keys/d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4' \
802+
-X DELETE 'http://localhost:7700/keys/ac5cd97d-5a4b-4226-a868-2d0eb6d197ab' \
811803
-H 'Authorization: Bearer MASTER_KEY'
812804
primary_field_guide_create_index_primary_key: |-
813805
curl \

learn/advanced/updating.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ docker run -it --rm \
102102

103103
::::
104104

105+
:::note
106+
If you are updating to v0.28, keys imported from the old version will have their `key` and `uid` fields regenerated.
107+
:::
108+
105109
### Proceed according to your database version
106110

107111
Now that you know which Meilisearch version your database is compatible with, proceed accordingly:

learn/security/master_api_keys.md

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -82,52 +82,66 @@ Exposing your master key can give malicious users complete control over your Mei
8282

8383
Meilisearch gives you fine-grained control over which users can access which indexes, endpoints, and routes. When protecting your instance with a master key, you can ensure only authorized users can carry out sensitive tasks such as adding documents or altering index settings.
8484

85-
The master key is the only key with access to the [`/keys` route](/reference/api/keys.md). This route allows you to [create](#creating-an-api-key), [update](#updating-an-api-key), [list](#listing-api-keys), and [delete](#deleting-an-api-key) API keys.
85+
You can access the [`/keys` route](/reference/api/keys.md) using the master key or an API key with access to the `keys.get`, `keys.create`, `keys.update`, or `keys.delete` actions. This `/keys` route allows you to [create](#creating-an-api-key), [update](#updating-an-api-key), [list](#listing-api-keys), and [delete](#deleting-an-api-key) API keys.
8686

8787
Though the default API keys are usually enough to manage the security needs of most applications, this might not be the case when dealing with privacy-sensitive data. In these situations, the fine-grained control offered by the `/keys` endpoint allows you to clearly decide who can access what information and for how long.
8888

89+
The [`key`](/reference/api/keys.md#key) field is generated by hashing the master key and the [`uid`](/reference/api/keys.md#uid). As a result, `key` values are deterministic between instances sharing the same configuration. Since the `key` field depends on the master key, it is not propagated to dumps and snapshots. If a malicious user ever gets access to your dumps or snapshots, they will not have access to your instance's API keys.
90+
91+
It is, therefore, possible to determine the value of the `key` field by using the following command:
92+
93+
```bash
94+
echo -n $HYPHENATED_UUID | openssl dgst -sha256 -hmac $MASTER_KEY
95+
```
96+
97+
This is also useful in continuous deployment processes as you know the value of the `key` field in advance.
98+
8999
### Updating an API key
90100

91-
You can freely update an API key at any time, even after it expires. This includes editing the indexes, endpoints, and routes it can access, as well as its description and expiry date.
101+
You can only update the `name` and `description` of an API key, even after it expires.
92102

93-
We can update the `Default Search API Key` so regular users cannot perform search operations in our `patient_medical_records` index:
103+
For example, we can update the `Default Search API Key` and change its description:
94104

95105
<CodeSamples id="security_guide_update_key_1" />
96106

97107
```json
98108
{
109+
"name": "Default Search API Key",
99110
"description": "Default Search API Key",
100111
"key": "d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4",
112+
"uid":"74c9c733-3368-4738-bbe5-1d18a5fecb37",
101113
"actions": [
102114
"search"
103115
],
104116
"indexes": [
105-
"doctors"
117+
"*"
106118
],
107119
"expiresAt": null,
108120
"createdAt": "2022-01-01T10:00:00Z",
109121
"updatedAt": "2022-01-01T10:00:00Z"
110122
}
111123
```
112124

113-
To update an API key, you must use the [update API key endpoint](/reference/api/keys.md#update-a-key) which can only be accessed with the master key.
125+
To update an API key, you must use the [update API key endpoint](/reference/api/keys.md#update-a-key), which can only be accessed with the master key or an API key with the `keys.update` action.
114126

115-
Meilisearch supports partial updates with the `PATCH` route. This means your payload only needs to contain the data you want to update—in this case, `indexes`.
127+
Meilisearch supports partial updates with the `PATCH` route. This means your payload only needs to contain the data you want to update—in this case, `description`.
116128

117129
### Creating an API key
118130

119-
You can create API keys by using the [create key endpoint](/reference/api/keys.md#create-a-key). This endpoint is always protected and can only be accessed with the master key.
131+
You can create API keys by using the [create key endpoint](/reference/api/keys.md#create-a-key). This endpoint is always protected and can only be accessed with the master key or an API key with the `keys.create` action.
120132

121-
Since we have altered the permissions in our default search key, we need to create a new API key so authorized users can search through out `patient_medical_records` index:
133+
Let's create a new API key so authorized users can search through out `patient_medical_records` index:
122134

123135
<CodeSamples id="security_guide_create_key_1" />
124136

125137
All [`/keys` endpoints](/reference/api/keys.md) are synchronous, so your key will be generated immediately:
126138

127139
```json
128140
{
141+
"name": null,
129142
"description": "Search patient records key",
130143
"key": "d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4",
144+
"uid": "ac5cd97d-5a4b-4226-a868-2d0eb6d197ab",
131145
"actions": [
132146
"search"
133147
],
@@ -146,9 +160,9 @@ It is good practice to always set an expiry date when creating a new API key. If
146160

147161
You can use the [list keys endpoint](/reference/api/keys.md) to obtain information on any active key in your Meilisearch instance. This is useful when you need an overview of existing keys and their permissions.
148162

149-
[`GET /keys`](/reference/api/keys.md#get-all-keys) returns a full list of all existing keys. **Expired keys will appear in the response, but deleted keys will not**. As with creating, deleting, and updating API keys, you need the master key to access this endpoint.
163+
By default, [`GET /keys`](/reference/api/keys.md#get-all-keys) returns the 20 most recently created keys. You can change this using the [`limit`](/reference/api/keys.md#get-all-keys) query parameter. **Expired keys will appear in the response, but deleted keys will not**. As with creating, deleting, and updating API keys, you either need the master key or an API key with the `keys.get` action to access this endpoint.
150164

151-
[`GET /keys/{key}`](/reference/api/keys.md#get-one-key) returns information on a single key. `{key}` should be replaced with the full `key` value obtained during key creation.
165+
[`GET /keys/{key_or_uid}`](/reference/api/keys.md#get-one-key) returns information on a single key. `{key_or_uid}` should be replaced with the full `key` or `uid` value obtained during key creation.
152166

153167
We can query our instance to confirm which active keys can search our `patient_medical_records` index:
154168

@@ -158,34 +172,40 @@ We can query our instance to confirm which active keys can search our `patient_m
158172
{
159173
"results": [
160174
{
161-
"description": "Default Search API Key (Use it to search from the frontend code)",
162-
"key": "0a6e572506c52ab0bd6195921575d23092b7f0c284ab4ac86d12346c33057f99",
175+
"name": "Default Search API Key",
176+
"description": "Use it to search from the frontend",
177+
"key": "d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4",
178+
"uid":"74c9c733-3368-4738-bbe5-1d18a5fecb37",
163179
"actions": [
164-
"search"
180+
"search"
165181
],
166182
"indexes": [
167-
"doctors"
183+
"*"
168184
],
169185
"expiresAt": null,
170-
"createdAt": "2021-08-11T10:00:00Z",
171-
"updatedAt": "2021-08-11T10:00:00Z"
186+
"createdAt": "2022-01-01T10:00:00Z",
187+
"updatedAt": "2022-01-01T10:00:00Z"
172188
},
173189
{
174-
"description": "Default Admin API Key (Use it for all other operations. Caution! Do not share it on the client side)",
190+
"name": "Default Admin API Key",
191+
"description": "Use it for all other than search operations. Caution! Do not expose it on a public frontend",
175192
"key": "380689dd379232519a54d15935750cc7625620a2ea2fc06907cb40ba5b421b6f",
193+
"uid": "20f7e4c4-612c-4dd1-b783-7934cc038213",
176194
"actions": [
177-
"*"
195+
"*"
178196
],
179197
"indexes": [
180-
"*"
198+
"*"
181199
],
182200
"expiresAt": null,
183201
"createdAt": "2021-08-11T10:00:00Z",
184202
"updatedAt": "2021-08-11T10:00:00Z"
185203
},
186204
{
205+
"name": null,
187206
"description": "Search patient records key",
188207
"key": "d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4",
208+
"uid": "ac5cd97d-5a4b-4226-a868-2d0eb6d197ab",
189209
"actions": [
190210
"search"
191211
],
@@ -196,7 +216,10 @@ We can query our instance to confirm which active keys can search our `patient_m
196216
"createdAt": "2022-01-01T10:00:00Z",
197217
"updatedAt": "2022-01-01T10:00:00Z"
198218
}
199-
]
219+
],
220+
"offset":0,
221+
"limit":20,
222+
"total":3
200223
}
201224
```
202225

@@ -212,8 +235,6 @@ If we accidentally exposed our `Search patient records key`, we can delete it to
212235

213236
Once a key is past its `expiresAt` date, using it for API authorization will return an error. Expired keys will still be returned by the [list keys endpoint](/reference/api/keys.md#get-all-keys).
214237

215-
If you must continue using an expired key, you may use the [update key endpoint](/reference/api/keys.md#update-a-key) to set a new `expiresAt` date and effectively reactivate it.
216-
217238
## Changing the master key
218239

219240
To change the master key, first terminate your Meilisearch instance. Then relaunch it, [supplying a new value for the master key](#protecting-a-meilisearch-instance).

learn/security/tenant_tokens.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Using a third-party library for tenant token generation is fairly similar to cre
5858
const jwt = require('jsonwebtoken');
5959

6060
const apiKey = 'my_api_key';
61+
const apiKeyUid = 'ac5cd97d-5a4b-4226-a868-2d0eb6d197ab';
6162
const currentUserID = 'a_user_id';
6263

6364
const tokenPayload = {
@@ -66,18 +67,18 @@ const tokenPayload = {
6667
'filter': `user_id = ${currentUserID}`
6768
}
6869
},
69-
apiKeyPrefix: apiKey.substring(0, 8),
70+
apiKeyUid: apiKeyUid,
7071
exp: parseInt(Date.now() / 1000) + 20 * 60 // 20 minutes
7172
};
7273

7374
const token = jwt.sign(tokenPayload, apiKey, {algorithm: 'HS256'});
7475
```
7576

76-
`tokenPayload` contains the token payload. It must contain three fields: `searchRules`, `apiKeyPrefix`, and `exp`.
77+
`tokenPayload` contains the token payload. It must contain three fields: `searchRules`, `apiKeyUid`, and `exp`.
7778

7879
`searchRules` must be a JSON object containing a set of search rules. These rules specify restrictions applied to every query using this web token.
7980

80-
`apiKeyPrefix` must be the first 8 characters of a valid Meilisearch API key.
81+
`apiKeyUid` must be the `uid` of a valid Meilisearch API key.
8182

8283
`exp` is the only optional parameter of a tenant token. It must be a UNIX timestamp specifying the expiration date of the token.
8384

@@ -117,7 +118,7 @@ The token payload contains most of the relevant token data. It must be an object
117118
```json
118119
{
119120
"exp": 1646756934,
120-
"apiKeyPrefix": "12345678",
121+
"apiKeyUid": "ac5cd97d-5a4b-4226-a868-2d0eb6d197ab",
121122
"searchRules": {
122123
"patient_medical_records": {
123124
"filter": "user_id = 1"
@@ -188,7 +189,7 @@ The previous rules can be combined in one tenant token:
188189

189190
```json
190191
{
191-
"apiKeyPrefix": "rkDxFUHd",
192+
"apiKeyUid": "ac5cd97d-5a4b-4226-a868-2d0eb6d197ab",
192193
"exp": 1641835850,
193194
"searchRules": {
194195
"*": {

reference/api/error_codes.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,22 @@ The requested task does not exist. Please ensure that you are using the correct
165165

166166
The `minWordSizeForTypos` object is invalid. The value for both `oneTypo` and `twoTypos` should be between `0` and `255`, and `twoTypos` should be greater or equal to `oneTypo`.
167167

168+
### `immutable_field`
169+
170+
The field you are trying to modify is immutable.
171+
172+
### `api_key_already_exists`
173+
174+
A key with this `uid` already exists.
175+
176+
### `invalid_api_key_uid`
177+
178+
The given `uid` is invalid. The `uid` must follow the [uuid v4](https://www.sohamkamani.com/uuid-versions-explained) format.
179+
180+
### `invalid_api_key_name`
181+
182+
The given `name` is invalid. It should either be a string or `null`.
183+
168184
### `invalid_task_status`
169185

170186
The requested task status is invalid. Please use one of [these four possible values](/learn/advanced/asynchronous_operations.md#task-status).

0 commit comments

Comments
 (0)