@picked/client 0.0.70-next.6 → 0.0.71-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -0
- package/dist/api-CH2FNa6S.cjs +1 -0
- package/dist/api-CgqRvuKL.js +38 -0
- package/dist/cjs/form/index.js +1 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/plugins/dom-observer/index.js +1 -1
- package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
- package/dist/cjs/server/index.js +1 -1
- package/dist/docs/actions.mdx +38 -18
- package/dist/docs/api/authentication.md +75 -48
- package/dist/docs/api/authorization-and-scopes.md +63 -47
- package/dist/docs/api/error-handling.md +70 -54
- package/dist/docs/api/index.md +41 -22
- package/dist/docs/api/pagination.md +30 -20
- package/dist/docs/api-keys.mdx +11 -6
- package/dist/docs/chrome-extension.md +22 -5
- package/dist/docs/conditions.mdx +32 -19
- package/dist/docs/content/asset-library.mdx +65 -34
- package/dist/docs/content/content-entries.mdx +8 -2
- package/dist/docs/content/layouts.mdx +45 -29
- package/dist/docs/content/pages.mdx +29 -14
- package/dist/docs/content/sections.mdx +19 -8
- package/dist/docs/delivery-api/experience-content.md +10 -5
- package/dist/docs/delivery-api/index.md +19 -12
- package/dist/docs/delivery-api/preview-caching-crawling.md +27 -14
- package/dist/docs/delivery-api/project-config.md +6 -4
- package/dist/docs/experiences.mdx +26 -10
- package/dist/docs/features.mdx +66 -25
- package/dist/docs/fields.mdx +42 -27
- package/dist/docs/flow-builder/building-flows.md +38 -20
- package/dist/docs/flow-builder/condition-builder.md +32 -21
- package/dist/docs/flow-builder/keyboard-shortcuts.md +18 -18
- package/dist/docs/flow-builder/nodes.md +26 -13
- package/dist/docs/flow-builder/overview.mdx +28 -15
- package/dist/docs/gtm-template.md +35 -26
- package/dist/docs/guides/build-a-personalized-page.mdx +36 -18
- package/dist/docs/image-optimisation-service.md +33 -17
- package/dist/docs/index.md +28 -17
- package/dist/docs/mcp.md +46 -38
- package/dist/docs/pickedql/data-sources.md +65 -43
- package/dist/docs/pickedql/dimensions.md +27 -12
- package/dist/docs/pickedql/examples.md +38 -26
- package/dist/docs/pickedql/filtering.md +10 -6
- package/dist/docs/pickedql/index.md +32 -14
- package/dist/docs/pickedql/schema.md +85 -76
- package/dist/docs/pickedql/virtual-functions.md +62 -36
- package/dist/docs/projects.mdx +14 -7
- package/dist/docs/reports.mdx +5 -3
- package/dist/docs/sdk/actions.md +33 -17
- package/dist/docs/sdk/conditions.md +8 -5
- package/dist/docs/sdk/content-security-policy.md +5 -4
- package/dist/docs/sdk/experiences.md +29 -11
- package/dist/docs/sdk/feature-allocation.md +79 -47
- package/dist/docs/sdk/features.md +130 -76
- package/dist/docs/sdk/fields.md +66 -42
- package/dist/docs/sdk/index.md +22 -13
- package/dist/docs/sdk/plugins/create-experience.md +18 -15
- package/dist/docs/sdk/plugins/dynamic-experiences.md +42 -16
- package/dist/docs/sdk/predicates.md +53 -37
- package/dist/docs/sdk/ssr/index.md +25 -8
- package/dist/docs/sdk/ssr/rendering-and-hydration.md +37 -16
- package/dist/docs/sdk/ssr/serialize.md +38 -20
- package/dist/docs/sdk/ssr/slots-and-placements.md +28 -10
- package/dist/docs/sdk/steps.md +100 -55
- package/dist/docs/steps.mdx +20 -11
- package/dist/docs/team-management.md +17 -11
- package/dist/docs/vite-plugin.md +26 -19
- package/dist/docs/workspace-versioning.mdx +14 -8
- package/dist/docs/workspaces.mdx +55 -24
- package/dist/{dom-BwmTHeT7.js → dom-BqcToNL0.js} +1 -3
- package/dist/{dom-CDrHc_j9.cjs → dom-DlLH3FxV.cjs} +1 -1
- package/dist/esm/form/index.js +2 -4
- package/dist/esm/index.js +50 -45
- package/dist/esm/plugins/dom-observer/index.js +1 -1
- package/dist/esm/plugins/dynamic-experiences/index.js +2 -2
- package/dist/esm/preview/index.js +1 -1
- package/dist/esm/server/index.js +12 -10
- package/dist/{experience-instance-DOJShRk5.js → experience-instance-DGk11d8a.js} +3 -3
- package/dist/experience-instance-Dej3P1sE.cjs +1 -0
- package/dist/{plugin-BxMR7fOV.js → plugin-D2UqFikQ.js} +2 -2
- package/dist/plugin-DCW-tnjO.cjs +1 -0
- package/dist/{preview-channel-DW9J8t4B.js → preview-channel-CSr96XAo.js} +1 -1
- package/dist/{protocol-DSqOlW2r.js → protocol-C5KkkiZc.js} +1 -1
- package/dist/types/client.d.ts +7 -6
- package/dist/types/entities/action/action.d.ts +5 -4
- package/dist/types/entities/action/action.d.ts.map +1 -1
- package/dist/types/entities/component/component.d.ts +6 -5
- package/dist/types/entities/component/component.d.ts.map +1 -1
- package/dist/types/entities/condition/condition.d.ts +5 -5
- package/dist/types/entities/content/content.d.ts +4 -3
- package/dist/types/entities/experience/experience.d.ts +11 -10
- package/dist/types/entities/experience/experience.d.ts.map +1 -1
- package/dist/types/entities/experience-instance/experience-instance.d.ts +10 -9
- package/dist/types/entities/feature/feature.d.ts +3 -2
- package/dist/types/entities/feature/feature.d.ts.map +1 -1
- package/dist/types/entities/field/field.d.ts +7 -6
- package/dist/types/entities/framework/framework.d.ts +7 -6
- package/dist/types/entities/framework/framework.d.ts.map +1 -1
- package/dist/types/entities/history/history.d.ts +6 -6
- package/dist/types/entities/plugin/plugin.d.ts +3 -2
- package/dist/types/entities/plugin/plugin.d.ts.map +1 -1
- package/dist/types/entities/predicate/predicate.d.ts +4 -3
- package/dist/types/entities/predicate/predicate.d.ts.map +1 -1
- package/dist/types/entities/response/response-validation.d.ts +3 -2
- package/dist/types/entities/response/response.d.ts +12 -11
- package/dist/types/entities/session/session.d.ts +2 -1
- package/dist/types/entities/step/step.d.ts +6 -5
- package/dist/types/exports.d.ts +2 -1
- package/dist/types/exports.d.ts.map +1 -1
- package/dist/types/form/build-responses.d.ts +2 -1
- package/dist/types/form/create-field-evaluator.d.ts +4 -3
- package/dist/types/form/create-field-validation.d.ts +5 -4
- package/dist/types/form/create-form.d.ts +7 -6
- package/dist/types/form/create-submit-pipeline.d.ts +7 -6
- package/dist/types/form/get-step-fields.d.ts +3 -2
- package/dist/types/lifecycle/condition-selection.d.ts +14 -4
- package/dist/types/lifecycle/lifecycle.d.ts +4 -3
- package/dist/types/lifecycle/rules-logic.d.ts +4 -3
- package/dist/types/lifecycle/state-snapshot.d.ts +4 -3
- package/dist/types/picked.d.ts +64 -62
- package/dist/types/picked.d.ts.map +1 -1
- package/dist/types/ping.d.ts +1 -1
- package/dist/types/ping.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/create-experience.d.ts +9 -8
- package/dist/types/plugins/create-experience/create-experience.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/plugin.d.ts +3 -2
- package/dist/types/plugins/create-experience/plugin.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/serialization.d.ts.map +1 -1
- package/dist/types/plugins/dom-observer/plugin.d.ts +1 -1
- package/dist/types/plugins/dynamic-experiences/plugin.d.ts +3 -3
- package/dist/types/plugins/dynamic-experiences/types.d.ts +8 -5
- package/dist/types/plugins/experience-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/experience-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/history-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/history-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/responses-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/responses-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/responses-indexeddb/plugin.d.ts +1 -1
- package/dist/types/plugins/single-page-app/plugin.d.ts +1 -1
- package/dist/types/plugins/single-page-app/plugin.d.ts.map +1 -1
- package/dist/types/plugins/web-components/plugin.d.ts +2 -1
- package/dist/types/plugins/window-object/plugin.d.ts +2 -2
- package/dist/types/preview-channel.d.ts +5 -1
- package/dist/types/preview-receiver/index.d.ts +18 -1
- package/dist/types/preview-receiver/protocol.d.ts +10 -1
- package/dist/types/server/index.d.ts +3 -3
- package/dist/types/server/serialize.d.ts +2 -2
- package/dist/types/utils/dom.d.ts +2 -1
- package/dist/types/utils/events.d.ts +6 -6
- package/dist/types/utils/events.d.ts.map +1 -1
- package/dist/types/utils/global-obj.d.ts +1 -1
- package/dist/types/utils/global-obj.d.ts.map +1 -1
- package/dist/types/utils/id.d.ts.map +1 -1
- package/dist/types/utils/logger.d.ts +2 -1
- package/dist/types/utils/logger.d.ts.map +1 -1
- package/dist/types/utils/node-tree/get-next-node-from-action.d.ts +2 -1
- package/dist/types/utils/node-tree/get-next-node-from-condition.d.ts +2 -1
- package/dist/types/utils/node-tree/get-next-node.d.ts +1 -1
- package/dist/types/utils/node-tree/get-next-node.d.ts.map +1 -1
- package/dist/types/utils/node-tree/get-origin-node.d.ts +1 -1
- package/dist/types/utils/node-tree/get-origin-node.d.ts.map +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts.map +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts.map +1 -1
- package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts +1 -1
- package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts.map +1 -1
- package/dist/types/utils/nodes.d.ts +1 -1
- package/dist/types/utils/picked-config.d.ts +2 -1
- package/dist/types/utils/rules-logic.d.ts +6 -2
- package/dist/types/utils/storage.d.ts +1 -1
- package/dist/types/utils/storage.d.ts.map +1 -1
- package/package.json +22 -23
- package/dist/api-CoUkIxIr.cjs +0 -1
- package/dist/api-ahdSBQ3Y.js +0 -40
- package/dist/experience-instance-DurC3pE-.cjs +0 -1
- package/dist/plugin-CASdGtTX.cjs +0 -1
|
@@ -4,11 +4,15 @@ layout: docs
|
|
|
4
4
|
|
|
5
5
|
# Authentication
|
|
6
6
|
|
|
7
|
-
The Picked API supports
|
|
7
|
+
The Picked API supports four ways to authenticate. They are a session from an email
|
|
8
|
+
address and a password, an OAuth provider, a magic link, and an API key. This guide
|
|
9
|
+
covers each one. It also covers how to control a session and how to use multi-factor
|
|
10
|
+
authentication (MFA).
|
|
8
11
|
|
|
9
|
-
##
|
|
12
|
+
## Sign in with an email address and a password
|
|
10
13
|
|
|
11
|
-
The `sessionCreate` mutation authenticates a user
|
|
14
|
+
The `sessionCreate` mutation authenticates a user from an email address and a
|
|
15
|
+
password. It returns a session.
|
|
12
16
|
|
|
13
17
|
```graphql
|
|
14
18
|
mutation {
|
|
@@ -36,13 +40,16 @@ mutation {
|
|
|
36
40
|
}
|
|
37
41
|
```
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
When the user has MFA on, the response sets `requiresMfa` to `true` and returns the
|
|
44
|
+
`mfaFactors` of that user. The caller must then complete an MFA challenge before it
|
|
45
|
+
receives a full session. See [MFA](#multi-factor-authentication-mfa) below.
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
When MFA is off, the response holds a `session` with an `accessToken`, a
|
|
48
|
+
`refreshToken`, and an `expiresAt` timestamp.
|
|
42
49
|
|
|
43
|
-
##
|
|
50
|
+
## Create an account
|
|
44
51
|
|
|
45
|
-
|
|
52
|
+
The `accountCreate` mutation creates a new account:
|
|
46
53
|
|
|
47
54
|
```graphql
|
|
48
55
|
mutation {
|
|
@@ -63,11 +70,14 @@ mutation {
|
|
|
63
70
|
}
|
|
64
71
|
```
|
|
65
72
|
|
|
66
|
-
The `metadata` field is optional
|
|
73
|
+
The `metadata` field is optional. It takes any JSON, and you can hold profile
|
|
74
|
+
information in it. When the account needs email verification, the session in the
|
|
75
|
+
response is `null` until the user verifies the email address.
|
|
67
76
|
|
|
68
|
-
##
|
|
77
|
+
## Verify an email address
|
|
69
78
|
|
|
70
|
-
After account
|
|
79
|
+
After you create the account, the user receives a verification email with a token.
|
|
80
|
+
The `accountVerifyEmail` mutation completes the verification:
|
|
71
81
|
|
|
72
82
|
```graphql
|
|
73
83
|
mutation {
|
|
@@ -83,7 +93,7 @@ mutation {
|
|
|
83
93
|
}
|
|
84
94
|
```
|
|
85
95
|
|
|
86
|
-
|
|
96
|
+
To send the verification email again:
|
|
87
97
|
|
|
88
98
|
```graphql
|
|
89
99
|
mutation {
|
|
@@ -95,11 +105,11 @@ mutation {
|
|
|
95
105
|
}
|
|
96
106
|
```
|
|
97
107
|
|
|
98
|
-
## OAuth flow
|
|
108
|
+
## The OAuth flow with Google
|
|
99
109
|
|
|
100
110
|
The API supports Google as an OAuth provider. The flow has two steps.
|
|
101
111
|
|
|
102
|
-
### Step 1:
|
|
112
|
+
### Step 1: get the authorization URL
|
|
103
113
|
|
|
104
114
|
```graphql
|
|
105
115
|
mutation {
|
|
@@ -113,9 +123,11 @@ mutation {
|
|
|
113
123
|
}
|
|
114
124
|
```
|
|
115
125
|
|
|
116
|
-
The caller
|
|
126
|
+
The caller sends the user to the `url` in the response. The user authenticates with
|
|
127
|
+
Google. Google then sends the user back to a URL on the same dashboard deployment,
|
|
128
|
+
with a `code` parameter. The caller exchanges that code for a session.
|
|
117
129
|
|
|
118
|
-
### Step 2:
|
|
130
|
+
### Step 2: exchange the code for a session
|
|
119
131
|
|
|
120
132
|
```graphql
|
|
121
133
|
mutation {
|
|
@@ -134,7 +146,7 @@ mutation {
|
|
|
134
146
|
|
|
135
147
|
## Magic links
|
|
136
148
|
|
|
137
|
-
|
|
149
|
+
A magic link authenticates a user through an email address, with no password.
|
|
138
150
|
|
|
139
151
|
### Send a magic link
|
|
140
152
|
|
|
@@ -149,7 +161,7 @@ mutation {
|
|
|
149
161
|
}
|
|
150
162
|
```
|
|
151
163
|
|
|
152
|
-
The user receives an email
|
|
164
|
+
The user receives an email with a link, and the link holds a token.
|
|
153
165
|
|
|
154
166
|
### Verify the magic link
|
|
155
167
|
|
|
@@ -167,11 +179,11 @@ mutation {
|
|
|
167
179
|
}
|
|
168
180
|
```
|
|
169
181
|
|
|
170
|
-
##
|
|
182
|
+
## Passwords
|
|
171
183
|
|
|
172
|
-
### Reset a
|
|
184
|
+
### Reset a password
|
|
173
185
|
|
|
174
|
-
Send
|
|
186
|
+
Send an email to reset the password:
|
|
175
187
|
|
|
176
188
|
```graphql
|
|
177
189
|
mutation {
|
|
@@ -184,7 +196,7 @@ mutation {
|
|
|
184
196
|
}
|
|
185
197
|
```
|
|
186
198
|
|
|
187
|
-
Complete the reset with the token from
|
|
199
|
+
Complete the reset with the token from that email:
|
|
188
200
|
|
|
189
201
|
```graphql
|
|
190
202
|
mutation {
|
|
@@ -201,9 +213,9 @@ mutation {
|
|
|
201
213
|
}
|
|
202
214
|
```
|
|
203
215
|
|
|
204
|
-
###
|
|
216
|
+
### Change a password
|
|
205
217
|
|
|
206
|
-
This mutation
|
|
218
|
+
This mutation needs authentication:
|
|
207
219
|
|
|
208
220
|
```graphql
|
|
209
221
|
mutation {
|
|
@@ -218,9 +230,11 @@ mutation {
|
|
|
218
230
|
|
|
219
231
|
## Multi-factor authentication (MFA)
|
|
220
232
|
|
|
221
|
-
MFA adds a second layer of security
|
|
233
|
+
MFA adds a second layer of security, and it uses a telephone to verify the user. The
|
|
234
|
+
API can add an MFA factor, send a challenge, verify a challenge, and remove a factor.
|
|
235
|
+
Every MFA mutation needs authentication.
|
|
222
236
|
|
|
223
|
-
###
|
|
237
|
+
### Add a factor
|
|
224
238
|
|
|
225
239
|
```graphql
|
|
226
240
|
mutation {
|
|
@@ -238,7 +252,7 @@ mutation {
|
|
|
238
252
|
}
|
|
239
253
|
```
|
|
240
254
|
|
|
241
|
-
A
|
|
255
|
+
A new factor has the status `UNVERIFIED` until a challenge confirms it.
|
|
242
256
|
|
|
243
257
|
### Send a challenge
|
|
244
258
|
|
|
@@ -252,7 +266,7 @@ mutation {
|
|
|
252
266
|
}
|
|
253
267
|
```
|
|
254
268
|
|
|
255
|
-
This sends a verification code to the
|
|
269
|
+
This sends a verification code to the telephone number of the factor.
|
|
256
270
|
|
|
257
271
|
### Verify the challenge
|
|
258
272
|
|
|
@@ -272,9 +286,10 @@ mutation {
|
|
|
272
286
|
}
|
|
273
287
|
```
|
|
274
288
|
|
|
275
|
-
On success, the session
|
|
289
|
+
On success, the session moves to Authenticator Assurance Level `AAL2`. The status of
|
|
290
|
+
the factor changes to `VERIFIED`.
|
|
276
291
|
|
|
277
|
-
###
|
|
292
|
+
### Remove a factor
|
|
278
293
|
|
|
279
294
|
```graphql
|
|
280
295
|
mutation {
|
|
@@ -286,30 +301,34 @@ mutation {
|
|
|
286
301
|
}
|
|
287
302
|
```
|
|
288
303
|
|
|
289
|
-
##
|
|
304
|
+
## Use a session
|
|
290
305
|
|
|
291
|
-
After
|
|
306
|
+
After the caller has a session, it puts the access token in the `Authorization`
|
|
307
|
+
header of every request that needs authentication:
|
|
292
308
|
|
|
293
309
|
```
|
|
294
310
|
Authorization: Bearer <accessToken>
|
|
295
311
|
```
|
|
296
312
|
|
|
297
|
-
The `expiresAt` field
|
|
313
|
+
The `expiresAt` field of the session gives the time at which the access token
|
|
314
|
+
expires. The caller must refresh the session before that time.
|
|
298
315
|
|
|
299
316
|
### Authenticator assurance levels
|
|
300
317
|
|
|
301
|
-
The session
|
|
318
|
+
The session holds an `aal` field, and it gives the strength of the authentication:
|
|
302
319
|
|
|
303
320
|
| Level | Meaning |
|
|
304
321
|
|-------|---------|
|
|
305
|
-
| `AAL1` |
|
|
306
|
-
| `AAL2` |
|
|
322
|
+
| `AAL1` | One factor: an email address and a password, OAuth, or a magic link |
|
|
323
|
+
| `AAL2` | More than one factor: the user completed an MFA challenge |
|
|
307
324
|
|
|
308
|
-
Some operations
|
|
325
|
+
Some operations need `AAL2`. When a caller at `AAL1` tries one of them, the API
|
|
326
|
+
returns an authorization error.
|
|
309
327
|
|
|
310
|
-
##
|
|
328
|
+
## Refresh a session
|
|
311
329
|
|
|
312
|
-
|
|
330
|
+
An access token has a short life. The `sessionRefresh` mutation exchanges a refresh
|
|
331
|
+
token for a new session:
|
|
313
332
|
|
|
314
333
|
```graphql
|
|
315
334
|
mutation {
|
|
@@ -325,11 +344,14 @@ mutation {
|
|
|
325
344
|
}
|
|
326
345
|
```
|
|
327
346
|
|
|
328
|
-
The response
|
|
347
|
+
The response holds a new `accessToken` and a new `refreshToken`. The API invalidates
|
|
348
|
+
the earlier refresh token. This mutation needs no `Authorization` header.
|
|
329
349
|
|
|
330
350
|
## API key authentication
|
|
331
351
|
|
|
332
|
-
API
|
|
352
|
+
An API key gives access to the API for a long time, inside a set of scopes. Most
|
|
353
|
+
callers use an API key for a server-to-server integration or for an automated
|
|
354
|
+
workflow.
|
|
333
355
|
|
|
334
356
|
To authenticate with an API key, include it in the `x-api-key` header:
|
|
335
357
|
|
|
@@ -337,13 +359,16 @@ To authenticate with an API key, include it in the `x-api-key` header:
|
|
|
337
359
|
x-api-key: pk_live_abc123...
|
|
338
360
|
```
|
|
339
361
|
|
|
340
|
-
API
|
|
362
|
+
An API key belongs to an organization, and it can also belong to one project. It
|
|
363
|
+
carries a set of [authorization scopes](./authorization-and-scopes.md), and those
|
|
364
|
+
scopes decide which operations the key can do.
|
|
341
365
|
|
|
342
|
-
See [API Keys](/api-keys) for
|
|
366
|
+
See [API Keys](/api-keys) for how to control a key from the dashboard.
|
|
343
367
|
|
|
344
|
-
###
|
|
368
|
+
### Create an API key
|
|
345
369
|
|
|
346
|
-
The `apiKeyCreate` mutation creates a new API key.
|
|
370
|
+
The `apiKeyCreate` mutation creates a new API key. Only a user with a session can
|
|
371
|
+
call it. Another API key cannot:
|
|
347
372
|
|
|
348
373
|
```graphql
|
|
349
374
|
mutation {
|
|
@@ -358,11 +383,13 @@ mutation {
|
|
|
358
383
|
}
|
|
359
384
|
```
|
|
360
385
|
|
|
361
|
-
The full API key string
|
|
386
|
+
The response holds the full API key string one time only. Keep it in a secure place, because
|
|
387
|
+
you cannot read it again.
|
|
362
388
|
|
|
363
|
-
The
|
|
389
|
+
The scopes that you ask for must all be scopes of the user who creates the key. See
|
|
390
|
+
[Authorization and Scopes](./authorization-and-scopes.md) for more detail.
|
|
364
391
|
|
|
365
|
-
###
|
|
392
|
+
### Revoke an API key
|
|
366
393
|
|
|
367
394
|
```graphql
|
|
368
395
|
mutation {
|
|
@@ -373,4 +400,4 @@ mutation {
|
|
|
373
400
|
}
|
|
374
401
|
```
|
|
375
402
|
|
|
376
|
-
|
|
403
|
+
The API invalidates a revoked key immediately. No later request can use it.
|
|
@@ -4,11 +4,14 @@ layout: docs
|
|
|
4
4
|
|
|
5
5
|
# Authorization and scopes
|
|
6
6
|
|
|
7
|
-
The Picked API
|
|
7
|
+
The Picked API controls access with scopes. Every authenticated caller carries a set
|
|
8
|
+
of scopes, and those scopes decide which operations the caller can do. A caller is
|
|
9
|
+
either a user with a session or an API key. This guide covers the scopes, the roles,
|
|
10
|
+
and how the API resolves a permission.
|
|
8
11
|
|
|
9
|
-
##
|
|
12
|
+
## The format of a scope name
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
A scope has the form `entity/action`:
|
|
12
15
|
|
|
13
16
|
```
|
|
14
17
|
organization/read
|
|
@@ -16,83 +19,87 @@ organization_members/create
|
|
|
16
19
|
organization_projects/delete
|
|
17
20
|
```
|
|
18
21
|
|
|
19
|
-
- **entity** — a lowercase name
|
|
20
|
-
|
|
22
|
+
- **entity** — a lowercase name. It uses an underscore between words, as in
|
|
23
|
+
`organization_members` and `organization_api_keys`.
|
|
24
|
+
- **action** — one of `create`, `read`, `update`, or `delete`.
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
The GraphQL schema holds the scopes in the `Scope` enum. There they are uppercase
|
|
27
|
+
with an underscore between words, as in `ORGANIZATION_READ` and
|
|
28
|
+
`ORGANIZATION_MEMBERS_CREATE`. The two forms name the same scope.
|
|
23
29
|
|
|
24
30
|
## Full scope list
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
These are the scopes:
|
|
27
33
|
|
|
28
34
|
### Organization
|
|
29
35
|
|
|
30
36
|
| Scope | GraphQL Enum | Description |
|
|
31
37
|
|-------|-------------|-------------|
|
|
32
|
-
| `organization/create` | `ORGANIZATION_CREATE` | Create
|
|
33
|
-
| `organization/read` | `ORGANIZATION_READ` |
|
|
34
|
-
| `organization/update` | `ORGANIZATION_UPDATE` | Update
|
|
38
|
+
| `organization/create` | `ORGANIZATION_CREATE` | Create an organization |
|
|
39
|
+
| `organization/read` | `ORGANIZATION_READ` | Read the detail of an organization |
|
|
40
|
+
| `organization/update` | `ORGANIZATION_UPDATE` | Update the name, the slug, and the settings of an organization |
|
|
35
41
|
| `organization/delete` | `ORGANIZATION_DELETE` | Delete an organization |
|
|
36
42
|
|
|
37
43
|
### Organization members
|
|
38
44
|
|
|
39
45
|
| Scope | GraphQL Enum | Description |
|
|
40
46
|
|-------|-------------|-------------|
|
|
41
|
-
| `organization_members/create` | `ORGANIZATION_MEMBERS_CREATE` | Add
|
|
42
|
-
| `organization_members/read` | `ORGANIZATION_MEMBERS_READ` |
|
|
43
|
-
| `organization_members/update` | `ORGANIZATION_MEMBERS_UPDATE` | Update member
|
|
44
|
-
| `organization_members/delete` | `ORGANIZATION_MEMBERS_DELETE` | Remove
|
|
47
|
+
| `organization_members/create` | `ORGANIZATION_MEMBERS_CREATE` | Add a member to an organization |
|
|
48
|
+
| `organization_members/read` | `ORGANIZATION_MEMBERS_READ` | Read the member list of an organization |
|
|
49
|
+
| `organization_members/update` | `ORGANIZATION_MEMBERS_UPDATE` | Update the role of a member |
|
|
50
|
+
| `organization_members/delete` | `ORGANIZATION_MEMBERS_DELETE` | Remove a member from an organization |
|
|
45
51
|
|
|
46
52
|
### Organization invitations
|
|
47
53
|
|
|
48
54
|
| Scope | GraphQL Enum | Description |
|
|
49
55
|
|-------|-------------|-------------|
|
|
50
|
-
| `organization_invitations/create` | `ORGANIZATION_INVITATIONS_CREATE` | Send
|
|
51
|
-
| `organization_invitations/read` | `ORGANIZATION_INVITATIONS_READ` |
|
|
52
|
-
| `organization_invitations/delete` | `ORGANIZATION_INVITATIONS_DELETE` | Revoke
|
|
56
|
+
| `organization_invitations/create` | `ORGANIZATION_INVITATIONS_CREATE` | Send an invitation to join an organization |
|
|
57
|
+
| `organization_invitations/read` | `ORGANIZATION_INVITATIONS_READ` | Read the invitations that wait for an answer |
|
|
58
|
+
| `organization_invitations/delete` | `ORGANIZATION_INVITATIONS_DELETE` | Revoke an invitation that waits for an answer |
|
|
53
59
|
|
|
54
60
|
### Organization projects
|
|
55
61
|
|
|
56
62
|
| Scope | GraphQL Enum | Description |
|
|
57
63
|
|-------|-------------|-------------|
|
|
58
|
-
| `organization_projects/create` | `ORGANIZATION_PROJECTS_CREATE` | Create
|
|
59
|
-
| `organization_projects/read` | `ORGANIZATION_PROJECTS_READ` |
|
|
60
|
-
| `organization_projects/update` | `ORGANIZATION_PROJECTS_UPDATE` | Update
|
|
61
|
-
| `organization_projects/delete` | `ORGANIZATION_PROJECTS_DELETE` | Delete
|
|
64
|
+
| `organization_projects/create` | `ORGANIZATION_PROJECTS_CREATE` | Create a project |
|
|
65
|
+
| `organization_projects/read` | `ORGANIZATION_PROJECTS_READ` | Read the detail of a project |
|
|
66
|
+
| `organization_projects/update` | `ORGANIZATION_PROJECTS_UPDATE` | Update the settings of a project |
|
|
67
|
+
| `organization_projects/delete` | `ORGANIZATION_PROJECTS_DELETE` | Delete a project |
|
|
62
68
|
|
|
63
69
|
### Organization API keys
|
|
64
70
|
|
|
65
71
|
| Scope | GraphQL Enum | Description |
|
|
66
72
|
|-------|-------------|-------------|
|
|
67
|
-
| `organization_api_keys/create` | `ORGANIZATION_API_KEYS_CREATE` | Create
|
|
68
|
-
| `organization_api_keys/read` | `ORGANIZATION_API_KEYS_READ` |
|
|
69
|
-
| `organization_api_keys/delete` | `ORGANIZATION_API_KEYS_DELETE` | Revoke API
|
|
73
|
+
| `organization_api_keys/create` | `ORGANIZATION_API_KEYS_CREATE` | Create an API key |
|
|
74
|
+
| `organization_api_keys/read` | `ORGANIZATION_API_KEYS_READ` | Read the API keys. This gives the prefix only, and not the full key. |
|
|
75
|
+
| `organization_api_keys/delete` | `ORGANIZATION_API_KEYS_DELETE` | Revoke an API key |
|
|
70
76
|
|
|
71
77
|
### Organization integrations
|
|
72
78
|
|
|
73
79
|
| Scope | GraphQL Enum | Description |
|
|
74
80
|
|-------|-------------|-------------|
|
|
75
|
-
| `organization_integrations/create` | `ORGANIZATION_INTEGRATIONS_CREATE` | Set up
|
|
76
|
-
| `organization_integrations/read` | `ORGANIZATION_INTEGRATIONS_READ` |
|
|
77
|
-
| `organization_integrations/update` | `ORGANIZATION_INTEGRATIONS_UPDATE` |
|
|
78
|
-
| `organization_integrations/delete` | `ORGANIZATION_INTEGRATIONS_DELETE` | Remove
|
|
81
|
+
| `organization_integrations/create` | `ORGANIZATION_INTEGRATIONS_CREATE` | Set up an integration |
|
|
82
|
+
| `organization_integrations/read` | `ORGANIZATION_INTEGRATIONS_READ` | Read the options of an integration |
|
|
83
|
+
| `organization_integrations/update` | `ORGANIZATION_INTEGRATIONS_UPDATE` | Change the settings of an integration |
|
|
84
|
+
| `organization_integrations/delete` | `ORGANIZATION_INTEGRATIONS_DELETE` | Remove an integration |
|
|
79
85
|
|
|
80
86
|
### Organization reports
|
|
81
87
|
|
|
82
88
|
| Scope | GraphQL Enum | Description |
|
|
83
89
|
|-------|-------------|-------------|
|
|
84
|
-
| `organization_reports/create` | `ORGANIZATION_REPORTS_CREATE` | Create
|
|
85
|
-
| `organization_reports/read` | `ORGANIZATION_REPORTS_READ` |
|
|
86
|
-
| `organization_reports/update` | `ORGANIZATION_REPORTS_UPDATE` | Update
|
|
87
|
-
| `organization_reports/delete` | `ORGANIZATION_REPORTS_DELETE` | Delete
|
|
90
|
+
| `organization_reports/create` | `ORGANIZATION_REPORTS_CREATE` | Create a report |
|
|
91
|
+
| `organization_reports/read` | `ORGANIZATION_REPORTS_READ` | Read a report |
|
|
92
|
+
| `organization_reports/update` | `ORGANIZATION_REPORTS_UPDATE` | Update the settings of a report |
|
|
93
|
+
| `organization_reports/delete` | `ORGANIZATION_REPORTS_DELETE` | Delete a report |
|
|
88
94
|
|
|
89
95
|
## Roles
|
|
90
96
|
|
|
91
|
-
|
|
97
|
+
Each member of an organization holds one of two roles:
|
|
92
98
|
|
|
93
99
|
### Owner
|
|
94
100
|
|
|
95
|
-
|
|
101
|
+
An owner has full control inside the organization. These are the default scopes of an
|
|
102
|
+
owner:
|
|
96
103
|
|
|
97
104
|
- All `organization/*` scopes (`read`, `update`, `delete`)
|
|
98
105
|
- All `organization_members/*` scopes
|
|
@@ -104,7 +111,8 @@ Owners have full control within their organization. Their default scopes include
|
|
|
104
111
|
|
|
105
112
|
### Member
|
|
106
113
|
|
|
107
|
-
|
|
114
|
+
A member can reach most things, but cannot delete the organization and cannot control
|
|
115
|
+
another member. These are the default scopes of a member:
|
|
108
116
|
|
|
109
117
|
- `organization/read`, `organization/update`
|
|
110
118
|
- `organization_members/read`
|
|
@@ -114,7 +122,7 @@ Members have broad access but cannot delete the organization or manage other mem
|
|
|
114
122
|
- All `organization_integrations/*` scopes
|
|
115
123
|
- `organization_reports/read`
|
|
116
124
|
|
|
117
|
-
|
|
125
|
+
These are the differences between an owner and a member:
|
|
118
126
|
|
|
119
127
|
| Capability | Owner | Member |
|
|
120
128
|
|-----------|-------|--------|
|
|
@@ -123,24 +131,30 @@ The key differences between owner and member:
|
|
|
123
131
|
| Remove members | Yes | No |
|
|
124
132
|
| Update member roles | Yes | No |
|
|
125
133
|
| Revoke invitations | Yes | No |
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
|
|
|
134
|
+
| Control projects and integrations | Yes | Yes |
|
|
135
|
+
| Control API keys | Yes | Yes |
|
|
136
|
+
| Read reports | Yes | Yes |
|
|
129
137
|
|
|
130
138
|
## How scopes are resolved
|
|
131
139
|
|
|
132
|
-
When an authenticated request reaches the API, the
|
|
140
|
+
When an authenticated request reaches the API, the API resolves the scopes like this:
|
|
133
141
|
|
|
134
|
-
1. **
|
|
135
|
-
|
|
142
|
+
1. **A user with a session** — the API finds the role of that caller in the target
|
|
143
|
+
organization. It then gives the caller the default scopes of that role.
|
|
144
|
+
2. **A request with an API key** — the API uses the scopes that the key received when
|
|
145
|
+
somebody created it. Those scopes are always scopes of the user who created the
|
|
146
|
+
key.
|
|
136
147
|
|
|
137
|
-
|
|
148
|
+
Most queries and mutations point at one organization. For those, the caller must hold
|
|
149
|
+
the scope inside that organization. For a root-level operation such as
|
|
150
|
+
`organizationCreate`, the API resolves the scope at the account level.
|
|
138
151
|
|
|
139
|
-
|
|
152
|
+
When the caller does not hold the scope that an operation needs, the API returns an
|
|
153
|
+
authorization error with the code `FORBIDDEN`. See [Errors](./error-handling.md).
|
|
140
154
|
|
|
141
155
|
## Operations and required scopes
|
|
142
156
|
|
|
143
|
-
|
|
157
|
+
This table gives the scope that each common operation needs:
|
|
144
158
|
|
|
145
159
|
### Queries
|
|
146
160
|
|
|
@@ -192,7 +206,7 @@ Some mutations do not require organization-level scopes because they operate on
|
|
|
192
206
|
| `organizationInvitationAccept` / `organizationInvitationDecline` | Authenticated session (no specific scope) |
|
|
193
207
|
| `mfaFactorEnroll` / `mfaChallengeSend` / `mfaChallengeVerify` / `mfaFactorUnenroll` | Authenticated session (no specific scope) |
|
|
194
208
|
|
|
195
|
-
##
|
|
209
|
+
## Read your scopes
|
|
196
210
|
|
|
197
211
|
### Root-level scopes
|
|
198
212
|
|
|
@@ -259,4 +273,6 @@ Response:
|
|
|
259
273
|
}
|
|
260
274
|
```
|
|
261
275
|
|
|
262
|
-
|
|
276
|
+
Use this to build a UI that changes with the permissions of the caller. An example is
|
|
277
|
+
a **Delete Organization** button that the UI hides when the caller does not hold
|
|
278
|
+
`ORGANIZATION_DELETE`.
|