@onplo/sdk 0.0.0-stage → 0.0.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/LICENSE +202 -0
- package/README.md +24 -2
- package/generated/account.d.ts +10914 -0
- package/generated/account.js +1 -0
- package/generated/ai.d.ts +9848 -0
- package/generated/ai.js +1 -0
- package/generated/compliance.d.ts +18459 -0
- package/generated/compliance.js +1 -0
- package/generated/devices.d.ts +15494 -0
- package/generated/devices.js +1 -0
- package/generated/flows.d.ts +8117 -0
- package/generated/flows.js +1 -0
- package/generated/identity.d.ts +2492 -0
- package/generated/identity.js +1 -0
- package/generated/index.d.ts +36 -0
- package/generated/index.js +13 -0
- package/generated/integrations.d.ts +7970 -0
- package/generated/integrations.js +1 -0
- package/generated/keys.d.ts +8565 -0
- package/generated/keys.js +1 -0
- package/generated/software.d.ts +1466 -0
- package/generated/software.js +1 -0
- package/generated/storage.d.ts +9229 -0
- package/generated/storage.js +1 -0
- package/package.json +25 -4
- package/src/index.d.ts +31 -0
- package/src/index.js +36 -0
|
@@ -0,0 +1,2492 @@
|
|
|
1
|
+
export interface paths {
|
|
2
|
+
"/.well-known/openid-configuration": {
|
|
3
|
+
parameters: {
|
|
4
|
+
query?: never;
|
|
5
|
+
header?: never;
|
|
6
|
+
path?: never;
|
|
7
|
+
cookie?: never;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Read where the sign-in provider is and what it supports
|
|
11
|
+
* @description THE DISCOVERY DOCUMENT (OpenID Connect Discovery 1.0). Every Onplo app — web, desktop, phone,
|
|
12
|
+
* the command line and the agent connector — signs in through identity as an OpenID Connect client
|
|
13
|
+
* (architecture decision record 037), and reads this first: where to send a person to sign in,
|
|
14
|
+
* where to trade the answer for tokens, and where the keys are that check them.
|
|
15
|
+
*
|
|
16
|
+
* IT NAMES ONLY WHAT IS SUPPORTED: the authorization code with PKCE (`S256`), public clients that
|
|
17
|
+
* hold no secret, the `openid` scope, and ID tokens signed ES256. No implicit flow, no password
|
|
18
|
+
* grant and no device code (record 037, rule One).
|
|
19
|
+
*
|
|
20
|
+
* SIGNED OUT, because nobody is signed in yet when it is read, and LIMITED by how often it is
|
|
21
|
+
* called, never by who calls (decision 0732). It may be kept for five minutes.
|
|
22
|
+
*/
|
|
23
|
+
get: operations["readProviderDiscovery"];
|
|
24
|
+
put?: never;
|
|
25
|
+
post?: never;
|
|
26
|
+
delete?: never;
|
|
27
|
+
options?: never;
|
|
28
|
+
head?: never;
|
|
29
|
+
patch?: never;
|
|
30
|
+
trace?: never;
|
|
31
|
+
};
|
|
32
|
+
"/.well-known/jwks.json": {
|
|
33
|
+
parameters: {
|
|
34
|
+
query?: never;
|
|
35
|
+
header?: never;
|
|
36
|
+
path?: never;
|
|
37
|
+
cookie?: never;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Read the public keys that check the provider's tokens
|
|
41
|
+
* @description THE KEY SET (RFC 7517): the public half of every key whose ID tokens may still be in a client's
|
|
42
|
+
* hands. A client checks an ID token's signature with the key its header names by `kid`.
|
|
43
|
+
*
|
|
44
|
+
* THE PRIVATE HALF NEVER LEAVES ONPLO'S KEY SERVICE: identity asks it to sign, and reads only the
|
|
45
|
+
* public half to publish here.
|
|
46
|
+
*
|
|
47
|
+
* ACROSS A ROTATION THERE ARE TWO: the key signing now, and the one before it, kept for at least a
|
|
48
|
+
* day after the change, so a token signed just before it is still checked. A `kid` is the key's own
|
|
49
|
+
* thumbprint (RFC 7638), so one id never names two keys.
|
|
50
|
+
*
|
|
51
|
+
* SIGNED OUT AND LIMITED, as the discovery document is. It may be kept for five minutes; a client
|
|
52
|
+
* that meets a `kid` it does not know reads it again.
|
|
53
|
+
*/
|
|
54
|
+
get: operations["readProviderKeySet"];
|
|
55
|
+
put?: never;
|
|
56
|
+
post?: never;
|
|
57
|
+
delete?: never;
|
|
58
|
+
options?: never;
|
|
59
|
+
head?: never;
|
|
60
|
+
patch?: never;
|
|
61
|
+
trace?: never;
|
|
62
|
+
};
|
|
63
|
+
"/authorize": {
|
|
64
|
+
parameters: {
|
|
65
|
+
query?: never;
|
|
66
|
+
header?: never;
|
|
67
|
+
path?: never;
|
|
68
|
+
cookie?: never;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Send a person from an app to sign in
|
|
72
|
+
* @description THE AUTHORIZATION ENDPOINT (OpenID Connect Core §3.1.2, architecture decision record 037). An
|
|
73
|
+
* app sends the browser here with its request, and Onplo answers one of three ways:
|
|
74
|
+
*
|
|
75
|
+
* - TO THE SIGN-IN SCREEN, carrying the request, when the app, its return address and every
|
|
76
|
+
* field are ones Onplo takes. The screen asks for the passkey, then
|
|
77
|
+
* `grantAuthorizationCode` sends the browser back to the app with its code.
|
|
78
|
+
* - BACK TO THE APP'S REGISTERED ADDRESS WITH AN OAUTH `error` (RFC 6749 §4.1.2.1), and its
|
|
79
|
+
* `state`, when the app and its address are Onplo's but another field is not.
|
|
80
|
+
* - NOWHERE, AS A 400 `not_registered`, when the app or its return address is not one Onplo
|
|
81
|
+
* lists. A code or an error sent to an address nobody registered is how a sign-in is stolen.
|
|
82
|
+
*
|
|
83
|
+
* THE FIELDS ARE READ BY THE RULES OF `AuthorizationRequest`, not by the parameters' own bounds:
|
|
84
|
+
* each is optional here so that a wrong one is answered as OAuth answers it, never as a 422.
|
|
85
|
+
*
|
|
86
|
+
* SIGNED OUT, because nobody is signed in yet, and LIMITED by how often it is called (decision
|
|
87
|
+
* 0732). It writes nothing.
|
|
88
|
+
*/
|
|
89
|
+
get: operations["authorizeSignIn"];
|
|
90
|
+
put?: never;
|
|
91
|
+
post?: never;
|
|
92
|
+
delete?: never;
|
|
93
|
+
options?: never;
|
|
94
|
+
head?: never;
|
|
95
|
+
patch?: never;
|
|
96
|
+
trace?: never;
|
|
97
|
+
};
|
|
98
|
+
"/passkey-proofs": {
|
|
99
|
+
parameters: {
|
|
100
|
+
query?: never;
|
|
101
|
+
header?: never;
|
|
102
|
+
path?: never;
|
|
103
|
+
cookie?: never;
|
|
104
|
+
};
|
|
105
|
+
get?: never;
|
|
106
|
+
put?: never;
|
|
107
|
+
/**
|
|
108
|
+
* Ask for the question a passkey answers
|
|
109
|
+
* @description THE FIRST HALF OF PROVING IT IS YOU. Onplo mints a ceremony and answers
|
|
110
|
+
* `request_options`: hand it to the browser's passkey API untouched, and the browser asks
|
|
111
|
+
* the person for their fingerprint, face or PIN.
|
|
112
|
+
*
|
|
113
|
+
* USER VERIFICATION IS REQUIRED, ALWAYS. A touch with no fingerprint and no PIN proves a
|
|
114
|
+
* device is present, not that the person is.
|
|
115
|
+
*
|
|
116
|
+
* BOUND TO THE SESSION THAT ASKED. The ceremony can be completed only with the same
|
|
117
|
+
* credential, so an answer lifted from one session proves nothing in another.
|
|
118
|
+
*
|
|
119
|
+
* SHORT-LIVED AND SINGLE USE. A person who walks away starts again; nothing has to be
|
|
120
|
+
* cancelled.
|
|
121
|
+
*
|
|
122
|
+
* A `POST` because every call mints a new ceremony. It takes no body: everything it needs is
|
|
123
|
+
* the credential.
|
|
124
|
+
*
|
|
125
|
+
* Not gated: proving it is you is not something a company grants or withholds.
|
|
126
|
+
*/
|
|
127
|
+
post: operations["startPasskeyProof"];
|
|
128
|
+
delete?: never;
|
|
129
|
+
options?: never;
|
|
130
|
+
head?: never;
|
|
131
|
+
patch?: never;
|
|
132
|
+
trace?: never;
|
|
133
|
+
};
|
|
134
|
+
"/passkey-proofs/{passkey_proof_id}/completion": {
|
|
135
|
+
parameters: {
|
|
136
|
+
query?: never;
|
|
137
|
+
header?: never;
|
|
138
|
+
path: {
|
|
139
|
+
passkey_proof_id: components["parameters"]["PasskeyProofId"];
|
|
140
|
+
};
|
|
141
|
+
cookie?: never;
|
|
142
|
+
};
|
|
143
|
+
get?: never;
|
|
144
|
+
put?: never;
|
|
145
|
+
/**
|
|
146
|
+
* Bring the passkey's answer back
|
|
147
|
+
* @description THE SECOND HALF. Send what the browser's passkey API returned, untouched. Onplo checks
|
|
148
|
+
* that it answers the question this ceremony asked, on this site, signed by a passkey or
|
|
149
|
+
* security key this person holds, with the person verified.
|
|
150
|
+
*
|
|
151
|
+
* WHAT CHANGES IS ONE MOMENT. The session's `proved_at` becomes now — the moment every
|
|
152
|
+
* service holds against its own freshness window. The session itself is the same session:
|
|
153
|
+
* same credential, same reach, and whatever was on screen is still there.
|
|
154
|
+
*
|
|
155
|
+
* IT WIDENS NOTHING. A fresh proof is what reaching for more demands; it is never the
|
|
156
|
+
* reaching itself.
|
|
157
|
+
*
|
|
158
|
+
* ONE ANSWER PER CEREMONY. Completed, refused or expired, a ceremony is spent, and its id
|
|
159
|
+
* answers `not_found` from then on — as it does from any other session. The cases are not
|
|
160
|
+
* told apart, so nothing is learned by trying ids.
|
|
161
|
+
*
|
|
162
|
+
* A REFUSED ANSWER SAYS ONLY THAT IT WAS REFUSED — `passkey_not_verified`. A wrong
|
|
163
|
+
* signature, another site, no user verification, a passkey that is not this person's: saying
|
|
164
|
+
* which would teach somebody what to fix. Start a new ceremony.
|
|
165
|
+
*
|
|
166
|
+
* Not gated: proving it is you is not something a company grants or withholds.
|
|
167
|
+
*/
|
|
168
|
+
post: operations["completePasskeyProof"];
|
|
169
|
+
delete?: never;
|
|
170
|
+
options?: never;
|
|
171
|
+
head?: never;
|
|
172
|
+
patch?: never;
|
|
173
|
+
trace?: never;
|
|
174
|
+
};
|
|
175
|
+
"/device-tokens": {
|
|
176
|
+
parameters: {
|
|
177
|
+
query?: never;
|
|
178
|
+
header?: never;
|
|
179
|
+
path?: never;
|
|
180
|
+
cookie?: never;
|
|
181
|
+
};
|
|
182
|
+
get?: never;
|
|
183
|
+
put?: never;
|
|
184
|
+
/**
|
|
185
|
+
* Trade a statement a device signed for a short-lived token
|
|
186
|
+
* @description HOW AN ENROLLED DEVICE GETS A CREDENTIAL. At enrolment a device was issued a certificate;
|
|
187
|
+
* its private half never leaves the device. Here the device proves it holds that half: it
|
|
188
|
+
* signs a short statement and is answered a token, which it then sends as
|
|
189
|
+
* `Authorization: Bearer` on its own calls like any other credential.
|
|
190
|
+
*
|
|
191
|
+
* THE STATEMENT IS A STANDARD ONE (decision 0647): a signed JSON Web Token as RFC 7523
|
|
192
|
+
* describes a client proving itself with its own key. `iss` and `sub` are both the device
|
|
193
|
+
* record's id; `aud` is the full address of this operation; `exp` is when it stops being
|
|
194
|
+
* good; `jti` is a value used once. Its header names the certificate by its SHA-256
|
|
195
|
+
* thumbprint (`x5t#S256`, RFC 7515). The device never sends the certificate itself: Onplo
|
|
196
|
+
* issued it and finds it by that thumbprint.
|
|
197
|
+
*
|
|
198
|
+
* GOOD FOR AT MOST FIVE MINUTES, AND FOR ONE USE. `exp` may be no more than five minutes
|
|
199
|
+
* ahead of Onplo's clock, and a `jti` is refused the second time. So a device signs a new
|
|
200
|
+
* statement at the moment it sends one — after a week asleep as well — and nothing signed
|
|
201
|
+
* earlier is worth keeping.
|
|
202
|
+
*
|
|
203
|
+
* WHAT THE TOKEN IS. It says which device record is calling, in which account environment,
|
|
204
|
+
* and nothing else. It lives at most an hour. It ends AT ONCE when the device's certificate
|
|
205
|
+
* ends — a retired or un-enrolled device is refused on its next call, not when the hour is
|
|
206
|
+
* up. It signs no person in and carries no permission: what a device may call is marked in
|
|
207
|
+
* each contract as an operation a device makes about itself.
|
|
208
|
+
*
|
|
209
|
+
* ONE KIND OF KEY IS CERTIFIED: an elliptic-curve key on the P-256 curve (decision 0963). So a
|
|
210
|
+
* statement is signed ES256, and one whose header names any other `alg` is not verified. A
|
|
211
|
+
* Mac's Secure Enclave and a TPM both make such a key, and it never leaves them.
|
|
212
|
+
*
|
|
213
|
+
* A CERTIFICATE IS VALID FOR 90 DAYS, AND IT IS RENEWED HERE. Every token answers when the
|
|
214
|
+
* certificate that signed its statement stops being valid. When 30 days or fewer are left,
|
|
215
|
+
* the device makes a NEW key pair and sends a certificate request for it beside its next
|
|
216
|
+
* statement; the answer carries the new certificate as well as the token. The old certificate
|
|
217
|
+
* stays in force until the first statement the new key signs is traded, and ends then. A
|
|
218
|
+
* device that lost that answer sends the same request again and is answered the same
|
|
219
|
+
* certificate. A device whose certificate ran out can no longer prove itself here: it is
|
|
220
|
+
* enrolled again.
|
|
221
|
+
*
|
|
222
|
+
* TWO REFUSALS, AND ONLY ONE SAYS WHY. `statement_not_verified` covers everything about WHO
|
|
223
|
+
* signed it — a certificate Onplo does not know, one that has ended, a signature that does
|
|
224
|
+
* not match, another audience, a `jti` already used. They are never told apart, so nothing
|
|
225
|
+
* is learned by trying, and a device cannot learn here that it was un-enrolled.
|
|
226
|
+
* `statement_outside_its_time` is told apart on purpose: a device with a wrong clock can do
|
|
227
|
+
* nothing with "not verified", and every answer's `Date` header carries Onplo's own time to
|
|
228
|
+
* set a statement by.
|
|
229
|
+
*
|
|
230
|
+
* A RENEWAL'S REFUSALS ARE TOLD APART, because the statement is judged first and has already
|
|
231
|
+
* proved the device by then. `certificate_request_unreadable`: no PKCS #10 request can be
|
|
232
|
+
* read from it. `certificate_request_not_signed_by_its_key`: its signature was not made by
|
|
233
|
+
* the key inside it. `key_not_certified`: the key is not a P-256 one. `key_ended`: a
|
|
234
|
+
* certificate for that key was ended, and such a key is never certified again.
|
|
235
|
+
* `key_already_certified`: the key signed this statement, or another device's certificate
|
|
236
|
+
* holds it.
|
|
237
|
+
*
|
|
238
|
+
* NO 401, NO 403 AND NO 503: it never asks who is calling, because the statement is the
|
|
239
|
+
* whole of the answer to that, so it refuses nobody for a credential and the service that
|
|
240
|
+
* would judge one is never asked. An `Authorization` header sent anyway is not read.
|
|
241
|
+
*
|
|
242
|
+
* A `POST` because every call mints a new token.
|
|
243
|
+
*/
|
|
244
|
+
post: operations["tradeDeviceStatement"];
|
|
245
|
+
delete?: never;
|
|
246
|
+
options?: never;
|
|
247
|
+
head?: never;
|
|
248
|
+
patch?: never;
|
|
249
|
+
trace?: never;
|
|
250
|
+
};
|
|
251
|
+
"/environment-switches": {
|
|
252
|
+
parameters: {
|
|
253
|
+
query?: never;
|
|
254
|
+
header?: never;
|
|
255
|
+
path?: never;
|
|
256
|
+
cookie?: never;
|
|
257
|
+
};
|
|
258
|
+
get?: never;
|
|
259
|
+
put?: never;
|
|
260
|
+
/**
|
|
261
|
+
* Open a session in another environment you are a member of
|
|
262
|
+
* @description HOW A SIGNED-IN PERSON STEPS INTO ANOTHER COMPANY. A session acts in one environment, so a
|
|
263
|
+
* switch opens a NEW session in the one named, and answers its token once. The session that
|
|
264
|
+
* asked is not changed and not ended: switching back uses it while it lasts.
|
|
265
|
+
*
|
|
266
|
+
* ONLY A MEMBER, NOW. The person must be a member of that environment at the moment of
|
|
267
|
+
* asking, and not suspended there. An environment that does not exist and one the person is
|
|
268
|
+
* not a member of are refused alike, `not_a_member`, so nothing is learned by trying ids.
|
|
269
|
+
*
|
|
270
|
+
* A PASSKEY TOUCH FIRST, WHEN ONE IS NEEDED — `passkey_proof_needed`. Reaching an environment
|
|
271
|
+
* the sign-in left off needs a touch made in the last five minutes; an environment it chose
|
|
272
|
+
* needs only what the company's entering gate asks. Prove it is you on the session you have,
|
|
273
|
+
* with `startPasskeyProof` and `completePasskeyProof`, and send the switch again. Signing in
|
|
274
|
+
* does not record its chosen environments yet, so today every switch needs the touch.
|
|
275
|
+
*
|
|
276
|
+
* THE NEW SESSION carries the moment of the touch that opened it as its `proved_at`, and it
|
|
277
|
+
* ends no later than the session that asked.
|
|
278
|
+
*
|
|
279
|
+
* `503 authorization_unavailable` also when the company's entering gate could not be read:
|
|
280
|
+
* whether the switch may proceed is unknown, so it is refused, never let through.
|
|
281
|
+
*
|
|
282
|
+
* A `POST` because every call opens a new session.
|
|
283
|
+
*
|
|
284
|
+
* Not gated: stepping into a company you belong to is not something a role grants.
|
|
285
|
+
*/
|
|
286
|
+
post: operations["switchEnvironment"];
|
|
287
|
+
delete?: never;
|
|
288
|
+
options?: never;
|
|
289
|
+
head?: never;
|
|
290
|
+
patch?: never;
|
|
291
|
+
trace?: never;
|
|
292
|
+
};
|
|
293
|
+
"/sign-ins": {
|
|
294
|
+
parameters: {
|
|
295
|
+
query?: never;
|
|
296
|
+
header?: never;
|
|
297
|
+
path?: never;
|
|
298
|
+
cookie?: never;
|
|
299
|
+
};
|
|
300
|
+
get?: never;
|
|
301
|
+
put?: never;
|
|
302
|
+
/**
|
|
303
|
+
* Ask for the question a passkey answers to sign in
|
|
304
|
+
* @description THE FIRST OF THREE CALLS THAT SIGN A PERSON IN. Onplo mints a sign-in and answers
|
|
305
|
+
* `request_options`: hand it to the browser's passkey API untouched, and the device shows the
|
|
306
|
+
* Onplo accounts it holds a passkey for. The person picks one and is verified by fingerprint,
|
|
307
|
+
* face or PIN.
|
|
308
|
+
*
|
|
309
|
+
* NOBODY IS NAMED, AND NO KEY IS LISTED. The call takes no body, so it cannot be asked about
|
|
310
|
+
* a username, and `allowCredentials` is always empty: every sign-in is put the same question,
|
|
311
|
+
* whoever is asking and whether or not an account exists (decision 0529). Nothing is learned
|
|
312
|
+
* by trying. A passkey and a security key alike are made to be found this way when they are
|
|
313
|
+
* registered (`startPasskeyRegistration`).
|
|
314
|
+
*
|
|
315
|
+
* A PERSON WHO TYPED A USERNAME sends it with the answer, and an answer from another
|
|
316
|
+
* person's passkey is refused exactly as a wrong passkey is.
|
|
317
|
+
*
|
|
318
|
+
* SHORT-LIVED AND SINGLE USE. A person who walks away starts again; nothing has to be
|
|
319
|
+
* cancelled.
|
|
320
|
+
*
|
|
321
|
+
* A `POST` because every call mints a new sign-in.
|
|
322
|
+
*/
|
|
323
|
+
post: operations["startSignIn"];
|
|
324
|
+
delete?: never;
|
|
325
|
+
options?: never;
|
|
326
|
+
head?: never;
|
|
327
|
+
patch?: never;
|
|
328
|
+
trace?: never;
|
|
329
|
+
};
|
|
330
|
+
"/sign-ins/{sign_in_id}/completion": {
|
|
331
|
+
parameters: {
|
|
332
|
+
query?: never;
|
|
333
|
+
header?: never;
|
|
334
|
+
path: {
|
|
335
|
+
sign_in_id: components["parameters"]["SignInId"];
|
|
336
|
+
};
|
|
337
|
+
cookie?: never;
|
|
338
|
+
};
|
|
339
|
+
get?: never;
|
|
340
|
+
put?: never;
|
|
341
|
+
/**
|
|
342
|
+
* Bring the passkey's answer back, and see where you may go
|
|
343
|
+
* @description THE SECOND CALL. Send what the browser's passkey API returned, untouched. Onplo checks
|
|
344
|
+
* that it answers the question this sign-in asked, on this site, signed by a passkey or
|
|
345
|
+
* security key Onplo holds, with the person verified. Which person it is, is read from the
|
|
346
|
+
* answer's `userHandle`.
|
|
347
|
+
*
|
|
348
|
+
* WHAT IT ANSWERS IS A CHOICE, NOT A SESSION. The person has proved who they are and has not
|
|
349
|
+
* chosen where they go (Account → Sign in, step 4): the answer lists the environments they may
|
|
350
|
+
* choose (decision 0562) and a `sign_in_token`, good once and for minutes, that opens the
|
|
351
|
+
* session they choose (`openSignedInSession`). Nothing is signed in until then.
|
|
352
|
+
*
|
|
353
|
+
* WITH THE DEVICE'S OWN TOKEN, WHEN THE CLIENT HAS ONE. An enrolled device shows the token it
|
|
354
|
+
* traded for (`tradeDeviceStatement`) beside the answer, and the session this sign-in opens
|
|
355
|
+
* keeps that device (decision 0886): the passkey says who, the device says where. A token that
|
|
356
|
+
* is not a live device's is refused `device_token_not_verified`; send the answer again in a new
|
|
357
|
+
* sign-in without it, or with a fresh one.
|
|
358
|
+
*
|
|
359
|
+
* A REFUSED ANSWER SAYS ONLY THAT IT WAS REFUSED — `passkey_not_verified`. A wrong signature,
|
|
360
|
+
* another site, no user verification, an answer without a `userHandle`, a passkey Onplo does
|
|
361
|
+
* not hold, and a username that is not the passkey's are never told apart. The person sees
|
|
362
|
+
* "That did not work", whichever it was.
|
|
363
|
+
*
|
|
364
|
+
* ONE ANSWER PER SIGN-IN. Completed, refused or expired, a sign-in is spent, and its id
|
|
365
|
+
* answers `not_found` from then on. The cases are not told apart.
|
|
366
|
+
*
|
|
367
|
+
* `503` when the list of environments could not be read: nothing is answered, and the person
|
|
368
|
+
* starts again.
|
|
369
|
+
*/
|
|
370
|
+
post: operations["completeSignIn"];
|
|
371
|
+
delete?: never;
|
|
372
|
+
options?: never;
|
|
373
|
+
head?: never;
|
|
374
|
+
patch?: never;
|
|
375
|
+
trace?: never;
|
|
376
|
+
};
|
|
377
|
+
"/sign-ins/{sign_in_id}/sessions": {
|
|
378
|
+
parameters: {
|
|
379
|
+
query?: never;
|
|
380
|
+
header?: never;
|
|
381
|
+
path: {
|
|
382
|
+
sign_in_id: components["parameters"]["SignInId"];
|
|
383
|
+
};
|
|
384
|
+
cookie?: never;
|
|
385
|
+
};
|
|
386
|
+
get?: never;
|
|
387
|
+
put?: never;
|
|
388
|
+
/**
|
|
389
|
+
* Open the session you chose
|
|
390
|
+
* @description THE THIRD CALL. Send the `sign_in_token` the completion answered, the environments the
|
|
391
|
+
* person chose, and the one they land in. Onplo opens ONE session, in that environment, and
|
|
392
|
+
* answers its token once.
|
|
393
|
+
*
|
|
394
|
+
* ONE SESSION, IN ONE ENVIRONMENT (decision 0798, rule 3). The other environments chosen are
|
|
395
|
+
* recorded on it: switching into one of them later (`switchEnvironment`) asks only the
|
|
396
|
+
* company's entering gate, while one left off asks a passkey touch first (decision 0873). So
|
|
397
|
+
* "Full access" is every choice sent here, and a session is still opened in only one.
|
|
398
|
+
*
|
|
399
|
+
* WHERE TO LAND is the client's to propose, from the sign-in page's rule: the Personal
|
|
400
|
+
* environment, or the most recently used Business one when Personal is off. It must be one of
|
|
401
|
+
* the environments chosen.
|
|
402
|
+
*
|
|
403
|
+
* THE SIGN-IN TOKEN IS GOOD ONCE. Used, expired, or not this sign-in's, it answers
|
|
404
|
+
* `not_found`, and the cases are not told apart.
|
|
405
|
+
*
|
|
406
|
+
* THE SESSION carries the moment of this sign-in's passkey touch as its `proved_at`, and the
|
|
407
|
+
* device shown at completion, if one was.
|
|
408
|
+
*
|
|
409
|
+
* A `POST` because it opens a session.
|
|
410
|
+
*/
|
|
411
|
+
post: operations["openSignedInSession"];
|
|
412
|
+
delete?: never;
|
|
413
|
+
options?: never;
|
|
414
|
+
head?: never;
|
|
415
|
+
patch?: never;
|
|
416
|
+
trace?: never;
|
|
417
|
+
};
|
|
418
|
+
"/sign-ins/{sign_in_id}/authorization-codes": {
|
|
419
|
+
parameters: {
|
|
420
|
+
query?: never;
|
|
421
|
+
header?: never;
|
|
422
|
+
path: {
|
|
423
|
+
sign_in_id: components["parameters"]["SignInId"];
|
|
424
|
+
};
|
|
425
|
+
cookie?: never;
|
|
426
|
+
};
|
|
427
|
+
get?: never;
|
|
428
|
+
put?: never;
|
|
429
|
+
/**
|
|
430
|
+
* Send the person back to the app they came from, with its one code
|
|
431
|
+
* @description THE THIRD CALL, FOR AN APP SIGNING IN THROUGH SINGLE SIGN-ON (architecture decision record
|
|
432
|
+
* 037). It takes the place `openSignedInSession` has when the sign-in screen signs itself in:
|
|
433
|
+
* where that opens a session and hands its token to the screen, this keeps a one-time code for
|
|
434
|
+
* the app the person was sent from, and answers the address to send the browser to, back to
|
|
435
|
+
* that app with the code.
|
|
436
|
+
*
|
|
437
|
+
* SEND what `openSignedInSession` takes, the `sign_in_token`, the environments chosen and the
|
|
438
|
+
* one to land in, and beside them the app's request exactly as it arrived at the
|
|
439
|
+
* authorization endpoint. Onplo reads the request again by the same rules, because the screen
|
|
440
|
+
* carried it and nothing it carries is trusted.
|
|
441
|
+
*
|
|
442
|
+
* THE CODE is good once, for one minute, and only for the app it names, at the exact return
|
|
443
|
+
* address it names, with the PKCE verifier that matches its challenge. The app trades it for
|
|
444
|
+
* the session at the token endpoint. Only its hash is kept.
|
|
445
|
+
*
|
|
446
|
+
* THE SIGN-IN TOKEN IS GOOD ONCE. Used, expired, or not this sign-in's, it answers
|
|
447
|
+
* `not_found`, and the cases are not told apart. One sign-in token hands out one code.
|
|
448
|
+
*
|
|
449
|
+
* A `POST` because it keeps a code.
|
|
450
|
+
*/
|
|
451
|
+
post: operations["grantAuthorizationCode"];
|
|
452
|
+
delete?: never;
|
|
453
|
+
options?: never;
|
|
454
|
+
head?: never;
|
|
455
|
+
patch?: never;
|
|
456
|
+
trace?: never;
|
|
457
|
+
};
|
|
458
|
+
"/passkey-registrations": {
|
|
459
|
+
parameters: {
|
|
460
|
+
query?: never;
|
|
461
|
+
header?: never;
|
|
462
|
+
path?: never;
|
|
463
|
+
cookie?: never;
|
|
464
|
+
};
|
|
465
|
+
get?: never;
|
|
466
|
+
put?: never;
|
|
467
|
+
/**
|
|
468
|
+
* Ask for the question a new passkey answers
|
|
469
|
+
* @description THE FIRST HALF OF ADDING A PASSKEY OR A SECURITY KEY, for a person already signed in
|
|
470
|
+
* (Account → Settings → Security → Sign-in methods). Onplo mints a registration and answers
|
|
471
|
+
* `creation_options`: hand it to the browser's passkey API untouched, and the device makes a
|
|
472
|
+
* new key for this person on `onplo.com`.
|
|
473
|
+
*
|
|
474
|
+
* A PASSKEY TOUCH FIRST: ONE MADE IN THE LAST FIVE MINUTES — `passkey_proof_needed`. A new way
|
|
475
|
+
* in is the most sensitive thing a session can add, so the person proves it is them on the
|
|
476
|
+
* session they have (`startPasskeyProof`, `completePasskeyProof`) and asks again. Right after
|
|
477
|
+
* signing in, that proof is already fresh.
|
|
478
|
+
*
|
|
479
|
+
* EVERY KEY IS MADE TO BE FOUND WITHOUT A USERNAME (`residentKey: required`), so signing in
|
|
480
|
+
* never has to list anyone's keys (`startSignIn`). The keys this person already holds are
|
|
481
|
+
* listed in `excludeCredentials`, so the same key is not added twice.
|
|
482
|
+
*
|
|
483
|
+
* BOUND TO THE SESSION THAT ASKED, SHORT-LIVED AND SINGLE USE, as a proof is.
|
|
484
|
+
*
|
|
485
|
+
* A `POST` because every call mints a new registration. It takes no body: everything it needs
|
|
486
|
+
* is the credential.
|
|
487
|
+
*
|
|
488
|
+
* GATED BY `account:sign-in-method.create`, the catalogue's act of adding a passkey or a security
|
|
489
|
+
* key (ring 1, a personal environment's): a key or an agent never holds it.
|
|
490
|
+
*/
|
|
491
|
+
post: operations["startPasskeyRegistration"];
|
|
492
|
+
delete?: never;
|
|
493
|
+
options?: never;
|
|
494
|
+
head?: never;
|
|
495
|
+
patch?: never;
|
|
496
|
+
trace?: never;
|
|
497
|
+
};
|
|
498
|
+
"/passkey-registrations/{passkey_registration_id}/completion": {
|
|
499
|
+
parameters: {
|
|
500
|
+
query?: never;
|
|
501
|
+
header?: never;
|
|
502
|
+
path: {
|
|
503
|
+
passkey_registration_id: components["parameters"]["PasskeyRegistrationId"];
|
|
504
|
+
};
|
|
505
|
+
cookie?: never;
|
|
506
|
+
};
|
|
507
|
+
get?: never;
|
|
508
|
+
put?: never;
|
|
509
|
+
/**
|
|
510
|
+
* Bring the new key back, and keep it
|
|
511
|
+
* @description THE SECOND HALF. Send what the browser's passkey API returned, untouched, and the name the
|
|
512
|
+
* person gives the key. Onplo checks that it answers the question this registration asked, on
|
|
513
|
+
* this site, from a key that verified the person and can be found without a username, and
|
|
514
|
+
* keeps it as one of the person's sign-in methods.
|
|
515
|
+
*
|
|
516
|
+
* WHAT IS KEPT is the key's public half and how to reach it; its private half never leaves the
|
|
517
|
+
* device. The key is listed in Account → Settings → Security → Sign-in methods from then on,
|
|
518
|
+
* where it can be renamed, made Primary or removed.
|
|
519
|
+
*
|
|
520
|
+
* NO ATTESTATION IS ASKED FOR (`attestation: none`). Onplo does not judge which maker built a
|
|
521
|
+
* key, only that the person holds it and was verified by it.
|
|
522
|
+
*
|
|
523
|
+
* ONE ANSWER PER REGISTRATION. Completed, refused or expired, it is spent, and its id answers
|
|
524
|
+
* `not_found` from then on — as it does from any other session.
|
|
525
|
+
*
|
|
526
|
+
* A REFUSED KEY SAYS ONLY THAT IT WAS REFUSED — `passkey_not_verified`, as a proof's refusal
|
|
527
|
+
* does. `already_registered` is told apart: the person already holds this very key, and a
|
|
528
|
+
* client says so rather than "try again".
|
|
529
|
+
*
|
|
530
|
+
* A `POST` because it adds a sign-in method, which has its own id.
|
|
531
|
+
*
|
|
532
|
+
* GATED BY `account:sign-in-method.create`, the catalogue's act of adding a passkey or a security
|
|
533
|
+
* key (ring 1, a personal environment's): a key or an agent never holds it.
|
|
534
|
+
*/
|
|
535
|
+
post: operations["completePasskeyRegistration"];
|
|
536
|
+
delete?: never;
|
|
537
|
+
options?: never;
|
|
538
|
+
head?: never;
|
|
539
|
+
patch?: never;
|
|
540
|
+
trace?: never;
|
|
541
|
+
};
|
|
542
|
+
"/username-checks": {
|
|
543
|
+
parameters: {
|
|
544
|
+
query?: never;
|
|
545
|
+
header?: never;
|
|
546
|
+
path?: never;
|
|
547
|
+
cookie?: never;
|
|
548
|
+
};
|
|
549
|
+
get?: never;
|
|
550
|
+
put?: never;
|
|
551
|
+
/**
|
|
552
|
+
* Ask whether a username may be chosen
|
|
553
|
+
* @description THE CHECK AS YOU TYPE, on the first screen of signing up (Account → Sign up, step 1). Send the
|
|
554
|
+
* username being typed; Onplo answers whether it may be chosen now.
|
|
555
|
+
*
|
|
556
|
+
* ONE ANSWER FOR EVERY NAME THAT MAY NOT BE CHOSEN: somebody holds it, or somebody gave it up
|
|
557
|
+
* less than 90 days ago, or it is reserved. Which of them is never said, because it says
|
|
558
|
+
* something about a person the one signing up has never met (Account's `RegisterPerson`).
|
|
559
|
+
*
|
|
560
|
+
* WHY THIS DOES NOT UNDO SIGN-IN'S RULE. Signing in never says whether a username exists
|
|
561
|
+
* (decision 0529). Signing up must, at the moment a name is chosen, and says only "may be chosen"
|
|
562
|
+
* or "may not", from the same list `RegisterPerson` judges. It is limited per address by the
|
|
563
|
+
* gate, as every signed-out call is.
|
|
564
|
+
*
|
|
565
|
+
* ADVICE, NEVER A HOLD. Nothing is reserved by asking: the name is judged again when the sign-up
|
|
566
|
+
* finishes, and another person may have taken it in between.
|
|
567
|
+
*
|
|
568
|
+
* A `POST` so the name travels in the body and never in a URL a log keeps.
|
|
569
|
+
*
|
|
570
|
+
* `503` when Account, which knows the list, could not be asked: nothing was judged, and the check
|
|
571
|
+
* may be tried again.
|
|
572
|
+
*/
|
|
573
|
+
post: operations["checkUsername"];
|
|
574
|
+
delete?: never;
|
|
575
|
+
options?: never;
|
|
576
|
+
head?: never;
|
|
577
|
+
patch?: never;
|
|
578
|
+
trace?: never;
|
|
579
|
+
};
|
|
580
|
+
"/sign-ups": {
|
|
581
|
+
parameters: {
|
|
582
|
+
query?: never;
|
|
583
|
+
header?: never;
|
|
584
|
+
path?: never;
|
|
585
|
+
cookie?: never;
|
|
586
|
+
};
|
|
587
|
+
get?: never;
|
|
588
|
+
put?: never;
|
|
589
|
+
/**
|
|
590
|
+
* Start signing up, and get the question the first passkey answers
|
|
591
|
+
* @description THE FIRST OF TWO CALLS THAT MAKE AN ONPLO ACCOUNT (Account → Sign up). Send the username and
|
|
592
|
+
* the facts Account records about the person; Onplo mints a sign-up and answers
|
|
593
|
+
* `creation_options`: hand it to the browser's passkey API untouched, and the device makes the
|
|
594
|
+
* person's first passkey, or a security key does.
|
|
595
|
+
*
|
|
596
|
+
* THE USERNAME IS JUDGED HERE, as `checkUsername` judges it, and again when the sign-up finishes.
|
|
597
|
+
* `username_not_available` here means pick another.
|
|
598
|
+
*
|
|
599
|
+
* THE EMAIL ADDRESS IS ASKED, NOT REQUIRED, AND IS NEVER A WAY IN (decisions 0198 and 0935). When
|
|
600
|
+
* sent it is recorded as the person's own and mailed its confirmation link; it may be left out.
|
|
601
|
+
* Nothing signs in by it.
|
|
602
|
+
*
|
|
603
|
+
* AN INVITED GUEST SIGNS UP THE SAME WAY. An invitation is accepted afterwards, from the
|
|
604
|
+
* person's own Companies → Requests, by somebody who holds the invited address confirmed
|
|
605
|
+
* (Account's rule, ONPLO-1694). A sign-up carries no invitation, so a forwarded mail lets nobody
|
|
606
|
+
* in.
|
|
607
|
+
*
|
|
608
|
+
* SHORT-LIVED AND SINGLE USE, as a sign-in is. Nothing is recorded anywhere until the sign-up
|
|
609
|
+
* finishes: a person who walks away leaves no account behind.
|
|
610
|
+
*
|
|
611
|
+
* `503` when Account, which judges the username, could not be asked: no sign-up was minted, and
|
|
612
|
+
* the call may be tried again.
|
|
613
|
+
*/
|
|
614
|
+
post: operations["startSignUp"];
|
|
615
|
+
delete?: never;
|
|
616
|
+
options?: never;
|
|
617
|
+
head?: never;
|
|
618
|
+
patch?: never;
|
|
619
|
+
trace?: never;
|
|
620
|
+
};
|
|
621
|
+
"/sign-ups/{sign_up_id}/completion": {
|
|
622
|
+
parameters: {
|
|
623
|
+
query?: never;
|
|
624
|
+
header?: never;
|
|
625
|
+
path: {
|
|
626
|
+
sign_up_id: components["parameters"]["SignUpId"];
|
|
627
|
+
};
|
|
628
|
+
cookie?: never;
|
|
629
|
+
};
|
|
630
|
+
get?: never;
|
|
631
|
+
put?: never;
|
|
632
|
+
/**
|
|
633
|
+
* Bring the first passkey back, and get the recovery codes and the first session
|
|
634
|
+
* @description THE SECOND CALL. Send what the browser's passkey API returned, untouched, and the name the
|
|
635
|
+
* person gives the key. Onplo checks it as `completePasskeyRegistration` checks a new key, and
|
|
636
|
+
* then, in one act: keeps the key, has Account record the person, their personal environment
|
|
637
|
+
* and its one membership (`RegisterPerson`), mints the person's recovery codes, and opens their
|
|
638
|
+
* first session there.
|
|
639
|
+
*
|
|
640
|
+
* THE RECOVERY CODES ARE SHOWN ONCE, HERE, AND NEVER AGAIN. They are the only way back for a
|
|
641
|
+
* person who loses every passkey (Account → Sign up, step 3). Onplo keeps none of them in the
|
|
642
|
+
* clear, so nobody can show them a second time. They are not yet counted as a way in: the
|
|
643
|
+
* person says they kept them, on Settings → Security (decision 0614).
|
|
644
|
+
*
|
|
645
|
+
* THE SESSION LANDS IN THE PERSONAL ENVIRONMENT, the only one the person has (step 5). Its
|
|
646
|
+
* `proved_at` is the moment of this passkey touch.
|
|
647
|
+
*
|
|
648
|
+
* ONE ANSWER PER SIGN-UP. Completed, refused or expired, a sign-up is spent, and its id answers
|
|
649
|
+
* `not_found` from then on.
|
|
650
|
+
*
|
|
651
|
+
* `username_not_available` when somebody took the name since the sign-up started: nothing was
|
|
652
|
+
* recorded, and the person starts again with another.
|
|
653
|
+
*
|
|
654
|
+
* `503` when Account could not be asked to record the person: the sign-up is not spent, no codes
|
|
655
|
+
* were minted, and the same answer may be sent again until the sign-up expires.
|
|
656
|
+
*/
|
|
657
|
+
post: operations["completeSignUp"];
|
|
658
|
+
delete?: never;
|
|
659
|
+
options?: never;
|
|
660
|
+
head?: never;
|
|
661
|
+
patch?: never;
|
|
662
|
+
trace?: never;
|
|
663
|
+
};
|
|
664
|
+
"/recoveries": {
|
|
665
|
+
parameters: {
|
|
666
|
+
query?: never;
|
|
667
|
+
header?: never;
|
|
668
|
+
path?: never;
|
|
669
|
+
cookie?: never;
|
|
670
|
+
};
|
|
671
|
+
get?: never;
|
|
672
|
+
put?: never;
|
|
673
|
+
/**
|
|
674
|
+
* Use a recovery code, and get the question a new passkey answers
|
|
675
|
+
* @description THE EMERGENCY DOOR, for a person who lost every passkey (Account → Sign in → Choose another
|
|
676
|
+
* sign-in method → Recovery code). Send the username and one recovery code. Onplo spends the code
|
|
677
|
+
* and answers `creation_options` for a new passkey: using a code requires registering a new
|
|
678
|
+
* passkey, which becomes the Primary one (Account → Settings → Security).
|
|
679
|
+
*
|
|
680
|
+
* A REFUSED CODE SAYS ONLY THAT IT WAS REFUSED — `recovery_not_verified`. An unknown username, a
|
|
681
|
+
* wrong code and a code already used are never told apart, so trying says nothing about whether
|
|
682
|
+
* an account exists (decision 0529).
|
|
683
|
+
*
|
|
684
|
+
* A CODE IS SPENT WHEN IT IS ACCEPTED HERE, whether or not the new passkey is then made. A person
|
|
685
|
+
* who walks away uses another code next time. The person's other codes stay good.
|
|
686
|
+
*
|
|
687
|
+
* USING A CODE RAISES A SECURITY ALERT to the person, so somebody who used a stolen code is seen
|
|
688
|
+
* (Account, "Recovery codes & sessions").
|
|
689
|
+
*
|
|
690
|
+
* SHORT-LIVED AND SINGLE USE, as a sign-in is.
|
|
691
|
+
*/
|
|
692
|
+
post: operations["startRecovery"];
|
|
693
|
+
delete?: never;
|
|
694
|
+
options?: never;
|
|
695
|
+
head?: never;
|
|
696
|
+
patch?: never;
|
|
697
|
+
trace?: never;
|
|
698
|
+
};
|
|
699
|
+
"/recoveries/{recovery_id}/completion": {
|
|
700
|
+
parameters: {
|
|
701
|
+
query?: never;
|
|
702
|
+
header?: never;
|
|
703
|
+
path: {
|
|
704
|
+
recovery_id: components["parameters"]["RecoveryId"];
|
|
705
|
+
};
|
|
706
|
+
cookie?: never;
|
|
707
|
+
};
|
|
708
|
+
get?: never;
|
|
709
|
+
put?: never;
|
|
710
|
+
/**
|
|
711
|
+
* Bring the new passkey back, and see where you may go
|
|
712
|
+
* @description THE SECOND CALL. Send what the browser's passkey API returned, untouched, and the name the
|
|
713
|
+
* person gives the key. Onplo checks it as `completePasskeyRegistration` checks a new key, keeps
|
|
714
|
+
* it as the person's Primary passkey, and answers as `completeSignIn` does: the environments the
|
|
715
|
+
* person may choose and a `sign_in_token` that opens one session. A RECOVERY IS A SIGN-IN THAT
|
|
716
|
+
* BEGAN WITH A CODE: open the session with `openSignedInSession`, naming this recovery's id as
|
|
717
|
+
* its `sign_in_id`.
|
|
718
|
+
*
|
|
719
|
+
* ONE ANSWER PER RECOVERY. Completed, refused or expired, a recovery is spent, and its id answers
|
|
720
|
+
* `not_found` from then on.
|
|
721
|
+
*
|
|
722
|
+
* `503` when the list of environments could not be read: the key is kept, and the person signs in
|
|
723
|
+
* with it.
|
|
724
|
+
*/
|
|
725
|
+
post: operations["completeRecovery"];
|
|
726
|
+
delete?: never;
|
|
727
|
+
options?: never;
|
|
728
|
+
head?: never;
|
|
729
|
+
patch?: never;
|
|
730
|
+
trace?: never;
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
export type webhooks = Record<string, never>;
|
|
734
|
+
export interface components {
|
|
735
|
+
schemas: {
|
|
736
|
+
/**
|
|
737
|
+
* Format: uuid
|
|
738
|
+
* @description A UUID version 7 (RFC 9562) — sortable by creation, and never a counter.
|
|
739
|
+
* @example 019250e1-8f3c-7c21-9a4d-3a2f7b6c1d90
|
|
740
|
+
*/
|
|
741
|
+
Id: string;
|
|
742
|
+
/**
|
|
743
|
+
* @description ONE CEREMONY: the question to put to a passkey, and until when an answer is taken. Single
|
|
744
|
+
* use, and only the session that asked can complete it.
|
|
745
|
+
*/
|
|
746
|
+
PasskeyProof: {
|
|
747
|
+
/** @description What the completion names. */
|
|
748
|
+
id: components["schemas"]["Id"];
|
|
749
|
+
request_options: components["schemas"]["PasskeyRequestOptions"];
|
|
750
|
+
/** @description When the ceremony dies. Seconds to minutes; after it, start again. */
|
|
751
|
+
expires_at: components["schemas"]["Timestamp"];
|
|
752
|
+
};
|
|
753
|
+
/**
|
|
754
|
+
* @description WHAT THE BROWSER HANDS THE PASSKEY — the JSON form of the standard's request options, in the
|
|
755
|
+
* standard's own field names (see the note at the top of this document). Pass it to the
|
|
756
|
+
* browser's passkey API untouched.
|
|
757
|
+
*/
|
|
758
|
+
PasskeyRequestOptions: {
|
|
759
|
+
/** @description Random bytes minted for this ceremony. The passkey signs them, so an old answer cannot be replayed. */
|
|
760
|
+
challenge: string;
|
|
761
|
+
/** @description A hint, in milliseconds, for how long the browser waits for the person. `expires_at` is what binds. */
|
|
762
|
+
timeout?: number;
|
|
763
|
+
/**
|
|
764
|
+
* @description The site the passkey belongs to, always `onplo.com` (decision 0728): the registrable
|
|
765
|
+
* domain and never the host the product is served from, so a passkey made once answers on every
|
|
766
|
+
* Onplo site and none outside them. It never changes, because a new one strands every passkey
|
|
767
|
+
* made under the old. A passkey made for another site cannot answer.
|
|
768
|
+
*/
|
|
769
|
+
rpId: string;
|
|
770
|
+
/**
|
|
771
|
+
* @description The passkeys and security keys this person holds, so the browser offers theirs and no
|
|
772
|
+
* one else's.
|
|
773
|
+
*/
|
|
774
|
+
allowCredentials: {
|
|
775
|
+
id: string;
|
|
776
|
+
/** @enum {string} */
|
|
777
|
+
type: "public-key";
|
|
778
|
+
/** @description How that key was last reached — a hint the browser uses to look in the right place. */
|
|
779
|
+
transports?: string[];
|
|
780
|
+
}[];
|
|
781
|
+
/**
|
|
782
|
+
* @description Always `required`. The person is verified, not merely present.
|
|
783
|
+
* @enum {string}
|
|
784
|
+
*/
|
|
785
|
+
userVerification: "required";
|
|
786
|
+
};
|
|
787
|
+
PasskeyProofCompletion: {
|
|
788
|
+
answer: components["schemas"]["PasskeyAnswer"];
|
|
789
|
+
};
|
|
790
|
+
/**
|
|
791
|
+
* @description WHAT THE BROWSER'S PASSKEY API RETURNED — the JSON form of the standard's authentication
|
|
792
|
+
* response, in the standard's own field names. Send it untouched.
|
|
793
|
+
*/
|
|
794
|
+
PasskeyAnswer: {
|
|
795
|
+
/** @description Which passkey or security key answered. */
|
|
796
|
+
id: string;
|
|
797
|
+
/** @description The same, as the standard repeats it. */
|
|
798
|
+
rawId: string;
|
|
799
|
+
/** @enum {string} */
|
|
800
|
+
type: "public-key";
|
|
801
|
+
/**
|
|
802
|
+
* @description Whether the key is part of this device or was reached from another.
|
|
803
|
+
* @enum {string}
|
|
804
|
+
*/
|
|
805
|
+
authenticatorAttachment?: "platform" | "cross-platform";
|
|
806
|
+
response: {
|
|
807
|
+
/**
|
|
808
|
+
* @description What the browser says it asked — the challenge and the page it asked from. The page's
|
|
809
|
+
* origin must be one identity lists, `https://app.onplo.com` at launch, or the answer is
|
|
810
|
+
* refused, whatever the passkey signed: any page under `onplo.com` may ask a passkey, and the
|
|
811
|
+
* list is what keeps a page that is not ours from completing a sign-in (decision 0728).
|
|
812
|
+
*/
|
|
813
|
+
clientDataJSON: string;
|
|
814
|
+
/** @description What the key says about itself — the site it is for, and that the person was verified. */
|
|
815
|
+
authenticatorData: string;
|
|
816
|
+
signature: string;
|
|
817
|
+
/** @description Whose passkey this is, as the key recorded it. Left out by a key that does not keep one. */
|
|
818
|
+
userHandle?: string;
|
|
819
|
+
};
|
|
820
|
+
/**
|
|
821
|
+
* @description Always present in the standard's form, and always empty here: this API asks for no
|
|
822
|
+
* extension, so an answer carrying one is not an answer to its question.
|
|
823
|
+
*/
|
|
824
|
+
clientExtensionResults: Record<string, never>;
|
|
825
|
+
};
|
|
826
|
+
/** @description What a completed proof leaves behind. */
|
|
827
|
+
SessionProof: {
|
|
828
|
+
/**
|
|
829
|
+
* @description When this session last proved itself — now. The same moment every service holds
|
|
830
|
+
* against its own freshness window.
|
|
831
|
+
*/
|
|
832
|
+
proved_at: components["schemas"]["Timestamp"];
|
|
833
|
+
};
|
|
834
|
+
/**
|
|
835
|
+
* @description WHAT A DEVICE SENDS AS ITS CREDENTIAL, and until when. Opaque: a device stores it, sends
|
|
836
|
+
* it, and never reads it.
|
|
837
|
+
*/
|
|
838
|
+
DeviceToken: {
|
|
839
|
+
/**
|
|
840
|
+
* @description The credential. Sent as `Authorization: Bearer` on the device's own calls. Never a
|
|
841
|
+
* token a client can decode: what it means is asked of Onplo on every call.
|
|
842
|
+
*/
|
|
843
|
+
token: string;
|
|
844
|
+
/**
|
|
845
|
+
* @description When the token stops being good by itself — at most an hour from now. It may stop
|
|
846
|
+
* sooner: it ends with the device's certificate, at once.
|
|
847
|
+
*/
|
|
848
|
+
expires_at: components["schemas"]["Timestamp"];
|
|
849
|
+
/**
|
|
850
|
+
* @description When the certificate that signed this statement stops being valid by itself, 90 days
|
|
851
|
+
* after it was issued. With 30 days or fewer left, the device sends a renewal.
|
|
852
|
+
*/
|
|
853
|
+
certificate_expires_at: components["schemas"]["Timestamp"];
|
|
854
|
+
/**
|
|
855
|
+
* @description Only on an answer to a renewal: the certificate for the new key. It comes into force
|
|
856
|
+
* when the first statement the new key signs is traded.
|
|
857
|
+
*/
|
|
858
|
+
renewed_certificate?: components["schemas"]["RenewedDeviceCertificate"];
|
|
859
|
+
};
|
|
860
|
+
/**
|
|
861
|
+
* @description A DEVICE'S NEXT CERTIFICATE, and what signed it. Public, every part of it: a certificate
|
|
862
|
+
* authority's key never leaves a managed KMS (architecture decision record 030).
|
|
863
|
+
*/
|
|
864
|
+
RenewedDeviceCertificate: {
|
|
865
|
+
/**
|
|
866
|
+
* @description The certificate, X.509 in DER, written base64url with no padding. It names the device
|
|
867
|
+
* record and its environment, as the one it follows did.
|
|
868
|
+
*/
|
|
869
|
+
certificate: string;
|
|
870
|
+
/**
|
|
871
|
+
* @description What signed it, the certificate's own issuer first — each X.509 in DER, written
|
|
872
|
+
* base64url with no padding.
|
|
873
|
+
*/
|
|
874
|
+
authority_certificates: string[];
|
|
875
|
+
/** @description When the new certificate stops being valid by itself, 90 days after it was issued. */
|
|
876
|
+
expires_at: components["schemas"]["Timestamp"];
|
|
877
|
+
};
|
|
878
|
+
/**
|
|
879
|
+
* @description THE SESSION A SWITCH OPENED. Opaque, like every token here: a client stores it, sends it,
|
|
880
|
+
* and never reads it.
|
|
881
|
+
*/
|
|
882
|
+
SwitchedSession: {
|
|
883
|
+
/**
|
|
884
|
+
* @description The new session's credential, shown this once. Sent as `Authorization: Bearer` on every
|
|
885
|
+
* call made in the environment switched into.
|
|
886
|
+
*/
|
|
887
|
+
token: string;
|
|
888
|
+
/** @description The account environment this session acts in — the one the switch named. */
|
|
889
|
+
environment_id: components["schemas"]["Id"];
|
|
890
|
+
/**
|
|
891
|
+
* @description When this session stops being good by itself: never later than the session that asked
|
|
892
|
+
* for it.
|
|
893
|
+
*/
|
|
894
|
+
expires_at: components["schemas"]["Timestamp"];
|
|
895
|
+
/**
|
|
896
|
+
* @description The moment of the passkey touch that opened this session — the one the asking session
|
|
897
|
+
* carried.
|
|
898
|
+
*/
|
|
899
|
+
proved_at: components["schemas"]["Timestamp"];
|
|
900
|
+
};
|
|
901
|
+
/** @description ONE SIGN-IN: the question to put to a passkey, and until when an answer is taken. Single use. */
|
|
902
|
+
SignIn: {
|
|
903
|
+
/** @description What the completion and the session's opening name. */
|
|
904
|
+
id: components["schemas"]["Id"];
|
|
905
|
+
/**
|
|
906
|
+
* @description With `allowCredentials` always empty: the person is not known yet, and the device offers
|
|
907
|
+
* every Onplo key it holds.
|
|
908
|
+
*/
|
|
909
|
+
request_options: components["schemas"]["PasskeyRequestOptions"];
|
|
910
|
+
/** @description When the sign-in dies. Seconds to minutes; after it, start again. */
|
|
911
|
+
expires_at: components["schemas"]["Timestamp"];
|
|
912
|
+
};
|
|
913
|
+
SignInCompletion: {
|
|
914
|
+
answer: components["schemas"]["PasskeyAnswer"];
|
|
915
|
+
/**
|
|
916
|
+
* @description The username the person typed, when they typed one — Account's `Username`, lower case
|
|
917
|
+
* (decision 0561). The answer must come from that person's key, or it is refused as a
|
|
918
|
+
* wrong passkey is. Left out when the person picked their account on the device.
|
|
919
|
+
*/
|
|
920
|
+
username?: string;
|
|
921
|
+
/**
|
|
922
|
+
* @description The token this device traded for (`DeviceToken.token`), when the client runs on an
|
|
923
|
+
* enrolled device. It proves which device the person is on, never who they are (decisions
|
|
924
|
+
* 0644 and 0886).
|
|
925
|
+
*/
|
|
926
|
+
device_token?: string;
|
|
927
|
+
};
|
|
928
|
+
/**
|
|
929
|
+
* @description WHERE A PERSON WHO HAS JUST PROVED THEMSELVES MAY GO, and the token that opens one session.
|
|
930
|
+
* The list is the person's own (decision 0562): which environments they belong to, each one's
|
|
931
|
+
* kind and name, and their state there — never anything inside one.
|
|
932
|
+
*/
|
|
933
|
+
SignInChoices: {
|
|
934
|
+
/**
|
|
935
|
+
* @description Good once, and until `expires_at`, for opening this sign-in's session
|
|
936
|
+
* (`openSignedInSession`). It is not a session and opens nothing else.
|
|
937
|
+
*/
|
|
938
|
+
sign_in_token: string;
|
|
939
|
+
/** @description When the sign-in token dies. Minutes; after it, sign in again. */
|
|
940
|
+
expires_at: components["schemas"]["Timestamp"];
|
|
941
|
+
/** @description The moment of the passkey touch — the `proved_at` the session will carry. */
|
|
942
|
+
proved_at: components["schemas"]["Timestamp"];
|
|
943
|
+
/**
|
|
944
|
+
* @description EVERY ENVIRONMENT THE PERSON MAY CHOOSE, WHOLE — never a page, because the chooser shows
|
|
945
|
+
* them all on one screen with one "Full access" toggle. Personal first, then Business, then
|
|
946
|
+
* the Onplo team, and oldest first within a kind. A membership the person left is never
|
|
947
|
+
* here; a suspended one is, so the chooser can say access is paused.
|
|
948
|
+
*/
|
|
949
|
+
choices: components["schemas"]["SignInChoice"][];
|
|
950
|
+
};
|
|
951
|
+
SignInChoice: {
|
|
952
|
+
/** @description The account environment. */
|
|
953
|
+
environment_id: components["schemas"]["Id"];
|
|
954
|
+
/**
|
|
955
|
+
* @description Which kind of environment it is.
|
|
956
|
+
* @enum {string}
|
|
957
|
+
*/
|
|
958
|
+
kind: "personal" | "business" | "onplo";
|
|
959
|
+
/**
|
|
960
|
+
* @description A company's name. Absent exactly when `kind` is `personal`: the client names a personal
|
|
961
|
+
* environment from its kind, in the reader's language.
|
|
962
|
+
*/
|
|
963
|
+
name?: string;
|
|
964
|
+
/**
|
|
965
|
+
* @description The person's state there. A suspended membership can be seen and not landed in.
|
|
966
|
+
* @enum {string}
|
|
967
|
+
*/
|
|
968
|
+
membership_state: "active" | "suspended";
|
|
969
|
+
};
|
|
970
|
+
SignedInSessionOpening: {
|
|
971
|
+
/** @description The token the completion answered. */
|
|
972
|
+
sign_in_token: string;
|
|
973
|
+
/**
|
|
974
|
+
* @description THE ENVIRONMENTS THE PERSON CHOSE for this sign-in, each one of the completion's
|
|
975
|
+
* choices, each named once. "Full access" sends them all. Switching into one of these later asks no passkey
|
|
976
|
+
* touch; one left out does.
|
|
977
|
+
*/
|
|
978
|
+
environment_ids: components["schemas"]["Id"][];
|
|
979
|
+
/** @description The one of them the session acts in. */
|
|
980
|
+
land_in: components["schemas"]["Id"];
|
|
981
|
+
};
|
|
982
|
+
AuthorizationCodeGrant: {
|
|
983
|
+
/** @description The token the completion answered. */
|
|
984
|
+
sign_in_token: string;
|
|
985
|
+
/** @description The environments the person chose, each one of the completion's choices, each named once. */
|
|
986
|
+
environment_ids: components["schemas"]["Id"][];
|
|
987
|
+
/** @description The one of them the app's session will act in. */
|
|
988
|
+
land_in: components["schemas"]["Id"];
|
|
989
|
+
authorization_request: components["schemas"]["AuthorizationRequest"];
|
|
990
|
+
};
|
|
991
|
+
/**
|
|
992
|
+
* @description THE APP'S REQUEST, field for field as it arrived at the authorization endpoint (RFC 6749
|
|
993
|
+
* §4.1.1, RFC 7636 §4.3, OpenID Connect Core §3.1.2.1).
|
|
994
|
+
*/
|
|
995
|
+
AuthorizationRequest: {
|
|
996
|
+
/** @description The app, by the id Onplo lists it under. */
|
|
997
|
+
client_id: string;
|
|
998
|
+
/** @description Where the app is sent back to, exactly as it registered it. */
|
|
999
|
+
redirect_uri: string;
|
|
1000
|
+
/**
|
|
1001
|
+
* @description Always `code`, the authorization code.
|
|
1002
|
+
* @enum {string}
|
|
1003
|
+
*/
|
|
1004
|
+
response_type: "code";
|
|
1005
|
+
/** @description The scopes asked, space-separated. `openid` is always one of them. */
|
|
1006
|
+
scope: string;
|
|
1007
|
+
/** @description The app's own value, sent back to it beside the code. */
|
|
1008
|
+
state: string;
|
|
1009
|
+
/** @description The PKCE challenge, the SHA-256 of the app's verifier in base64url. */
|
|
1010
|
+
code_challenge: string;
|
|
1011
|
+
/**
|
|
1012
|
+
* @description Always `S256`.
|
|
1013
|
+
* @enum {string}
|
|
1014
|
+
*/
|
|
1015
|
+
code_challenge_method: "S256";
|
|
1016
|
+
/** @description The app's value the ID token echoes, when it sent one. */
|
|
1017
|
+
nonce?: string;
|
|
1018
|
+
};
|
|
1019
|
+
AuthorizationCodeGranted: {
|
|
1020
|
+
/**
|
|
1021
|
+
* Format: uri
|
|
1022
|
+
* @description The app's return address with `code` and `state` added. The screen sends the browser
|
|
1023
|
+
* there at once; the code in it is good for one minute.
|
|
1024
|
+
*/
|
|
1025
|
+
redirect_to: string;
|
|
1026
|
+
};
|
|
1027
|
+
/**
|
|
1028
|
+
* @description THE SESSION A SIGN-IN OPENED. Opaque, like every token here: a client stores it, sends it,
|
|
1029
|
+
* and never reads it.
|
|
1030
|
+
*/
|
|
1031
|
+
SignedInSession: {
|
|
1032
|
+
/**
|
|
1033
|
+
* @description The session's credential, shown this once. Sent as `Authorization: Bearer` on every call
|
|
1034
|
+
* made in the environment it acts in.
|
|
1035
|
+
*/
|
|
1036
|
+
token: string;
|
|
1037
|
+
/** @description The account environment this session acts in — `land_in`. */
|
|
1038
|
+
environment_id: components["schemas"]["Id"];
|
|
1039
|
+
/** @description When this session stops being good by itself. */
|
|
1040
|
+
expires_at: components["schemas"]["Timestamp"];
|
|
1041
|
+
/** @description The moment of the passkey touch that signed the person in. */
|
|
1042
|
+
proved_at: components["schemas"]["Timestamp"];
|
|
1043
|
+
};
|
|
1044
|
+
/**
|
|
1045
|
+
* @description ONE REGISTRATION: the question a new key answers, and until when an answer is taken. Single
|
|
1046
|
+
* use, and only the session that asked can complete it.
|
|
1047
|
+
*/
|
|
1048
|
+
PasskeyRegistration: {
|
|
1049
|
+
/** @description What the completion names. */
|
|
1050
|
+
id: components["schemas"]["Id"];
|
|
1051
|
+
creation_options: components["schemas"]["PasskeyCreationOptions"];
|
|
1052
|
+
/** @description When the registration dies. Seconds to minutes; after it, start again. */
|
|
1053
|
+
expires_at: components["schemas"]["Timestamp"];
|
|
1054
|
+
};
|
|
1055
|
+
/**
|
|
1056
|
+
* @description WHAT THE BROWSER HANDS THE DEVICE TO MAKE A NEW KEY — the JSON form of the standard's
|
|
1057
|
+
* creation options, in the standard's own field names (see the note at the top of this
|
|
1058
|
+
* document). Pass it to the browser's passkey API untouched.
|
|
1059
|
+
*/
|
|
1060
|
+
PasskeyCreationOptions: {
|
|
1061
|
+
rp: {
|
|
1062
|
+
/** @description Always `onplo.com` (decision 0728), as `PasskeyRequestOptions.rpId` is. */
|
|
1063
|
+
id: string;
|
|
1064
|
+
/** @description What the device shows the key as being for — `Onplo`. */
|
|
1065
|
+
name: string;
|
|
1066
|
+
};
|
|
1067
|
+
user: {
|
|
1068
|
+
/**
|
|
1069
|
+
* @description The person, as the key records them and hands back as `userHandle` at every sign-in.
|
|
1070
|
+
* Opaque bytes that name nobody outside Onplo.
|
|
1071
|
+
*/
|
|
1072
|
+
id: string;
|
|
1073
|
+
/** @description The person's username, so the device can tell their keys apart. */
|
|
1074
|
+
name: string;
|
|
1075
|
+
/** @description The person's name, as the device shows it. */
|
|
1076
|
+
displayName: string;
|
|
1077
|
+
};
|
|
1078
|
+
/** @description Random bytes minted for this registration. The new key signs them. */
|
|
1079
|
+
challenge: string;
|
|
1080
|
+
/** @description The signature kinds Onplo accepts, most preferred first. */
|
|
1081
|
+
pubKeyCredParams: {
|
|
1082
|
+
/** @enum {string} */
|
|
1083
|
+
type: "public-key";
|
|
1084
|
+
/** @description A COSE algorithm number — `-8` EdDSA, `-7` ES256, `-257` RS256. */
|
|
1085
|
+
alg: number;
|
|
1086
|
+
}[];
|
|
1087
|
+
/** @description A hint, in milliseconds, for how long the browser waits for the person. `expires_at` is what binds. */
|
|
1088
|
+
timeout?: number;
|
|
1089
|
+
/** @description The keys this person already holds, so the device does not add one twice. */
|
|
1090
|
+
excludeCredentials: {
|
|
1091
|
+
id: string;
|
|
1092
|
+
/** @enum {string} */
|
|
1093
|
+
type: "public-key";
|
|
1094
|
+
transports?: string[];
|
|
1095
|
+
}[];
|
|
1096
|
+
authenticatorSelection: {
|
|
1097
|
+
/**
|
|
1098
|
+
* @description Always `required`: the key keeps who it is for, so signing in finds it without a
|
|
1099
|
+
* username and never lists anyone's keys.
|
|
1100
|
+
* @enum {string}
|
|
1101
|
+
*/
|
|
1102
|
+
residentKey: "required";
|
|
1103
|
+
/**
|
|
1104
|
+
* @description Always `required`. The person is verified, not merely present.
|
|
1105
|
+
* @enum {string}
|
|
1106
|
+
*/
|
|
1107
|
+
userVerification: "required";
|
|
1108
|
+
};
|
|
1109
|
+
/**
|
|
1110
|
+
* @description Always `none`. Onplo does not judge which maker built a key.
|
|
1111
|
+
* @enum {string}
|
|
1112
|
+
*/
|
|
1113
|
+
attestation: "none";
|
|
1114
|
+
};
|
|
1115
|
+
PasskeyRegistrationCompletion: {
|
|
1116
|
+
attestation: components["schemas"]["PasskeyAttestation"];
|
|
1117
|
+
/**
|
|
1118
|
+
* @description What the person calls this key in their list of sign-in methods — Account's
|
|
1119
|
+
* `SignInMethod.name`, renamed there later.
|
|
1120
|
+
*/
|
|
1121
|
+
name: string;
|
|
1122
|
+
};
|
|
1123
|
+
/**
|
|
1124
|
+
* @description WHAT THE BROWSER'S PASSKEY API RETURNED WHEN IT MADE THE KEY — the JSON form of the
|
|
1125
|
+
* standard's registration response, in the standard's own field names. Send it untouched.
|
|
1126
|
+
*/
|
|
1127
|
+
PasskeyAttestation: {
|
|
1128
|
+
/** @description The new key's id. */
|
|
1129
|
+
id: string;
|
|
1130
|
+
/** @description The same, as the standard repeats it. */
|
|
1131
|
+
rawId: string;
|
|
1132
|
+
/** @enum {string} */
|
|
1133
|
+
type: "public-key";
|
|
1134
|
+
/**
|
|
1135
|
+
* @description Whether the key is part of this device or was reached from another.
|
|
1136
|
+
* @enum {string}
|
|
1137
|
+
*/
|
|
1138
|
+
authenticatorAttachment?: "platform" | "cross-platform";
|
|
1139
|
+
response: {
|
|
1140
|
+
/**
|
|
1141
|
+
* @description What the browser says it asked — the challenge and the page it asked from, which must
|
|
1142
|
+
* be one identity lists, as for a sign-in (decision 0728).
|
|
1143
|
+
*/
|
|
1144
|
+
clientDataJSON: string;
|
|
1145
|
+
/** @description The new key's public half and what the key says about itself. */
|
|
1146
|
+
attestationObject: string;
|
|
1147
|
+
/** @description How the key can be reached, kept so the browser looks in the right place. */
|
|
1148
|
+
transports?: string[];
|
|
1149
|
+
};
|
|
1150
|
+
/** @description Always empty, because this API asks for no extension. */
|
|
1151
|
+
clientExtensionResults: Record<string, never>;
|
|
1152
|
+
};
|
|
1153
|
+
/** @description THE KEY JUST KEPT, by the id Account's list of sign-in methods names it with. */
|
|
1154
|
+
AddedSignInMethod: {
|
|
1155
|
+
/** @description The sign-in method's id — `SignInMethod.id` in Account's list. */
|
|
1156
|
+
id: components["schemas"]["Id"];
|
|
1157
|
+
/** @description The name it was given. */
|
|
1158
|
+
name: string;
|
|
1159
|
+
/** @description When it was kept. */
|
|
1160
|
+
added_at: components["schemas"]["Timestamp"];
|
|
1161
|
+
};
|
|
1162
|
+
/**
|
|
1163
|
+
* @description A person's one identifier, lower case — Account's `Username` (decision 0561). The client lowers
|
|
1164
|
+
* what the person types before sending it.
|
|
1165
|
+
*/
|
|
1166
|
+
Username: string;
|
|
1167
|
+
UsernameCheck: {
|
|
1168
|
+
username: components["schemas"]["Username"];
|
|
1169
|
+
};
|
|
1170
|
+
UsernameAvailability: {
|
|
1171
|
+
/**
|
|
1172
|
+
* @description Whether the name may be chosen now. False for a name somebody holds, gave up less than 90
|
|
1173
|
+
* days ago, or that is reserved — never which. Advice, never a hold.
|
|
1174
|
+
*/
|
|
1175
|
+
available: boolean;
|
|
1176
|
+
};
|
|
1177
|
+
/**
|
|
1178
|
+
* @description WHAT ACCOUNT RECORDS ABOUT A NEW PERSON (`RegisterPerson`), asked on the sign-up screens and
|
|
1179
|
+
* held by identity until the sign-up finishes.
|
|
1180
|
+
*
|
|
1181
|
+
* A FIRST NAME, AND A LAST NAME IF THEY HAVE ONE (Account → Sign in, "How signing up works",
|
|
1182
|
+
* step 1; ONPLO-4080). There is no middle name, and where one name divides is never guessed.
|
|
1183
|
+
*/
|
|
1184
|
+
SignUpStart: {
|
|
1185
|
+
username: components["schemas"]["Username"];
|
|
1186
|
+
/**
|
|
1187
|
+
* @description The person's first name, as typed, by the rule Account's `ProfileUpdate` holds: something a
|
|
1188
|
+
* person can see, on one line.
|
|
1189
|
+
*/
|
|
1190
|
+
first_name: string;
|
|
1191
|
+
/** @description The person's last name, as typed, by the same rule. Left out by a person who has one name. */
|
|
1192
|
+
last_name?: string;
|
|
1193
|
+
/**
|
|
1194
|
+
* Format: email
|
|
1195
|
+
* @description The person's own address, OR LEFT OUT: it is asked, and is not required to get in (step 4,
|
|
1196
|
+
* decision 0935). When sent it is recorded as theirs and mailed its confirmation link, and it is
|
|
1197
|
+
* never a way in (decision 0198). Left out, no address is written and no mail is sent.
|
|
1198
|
+
*/
|
|
1199
|
+
email_address?: string;
|
|
1200
|
+
/**
|
|
1201
|
+
* @description The language Onplo speaks to them in, a BCP 47 tag, from the browser and confirmed once. The same rule as Account's `Preferences.language`.
|
|
1202
|
+
* @example nl-BE
|
|
1203
|
+
*/
|
|
1204
|
+
language: string;
|
|
1205
|
+
/** @description The zone times are shown in for them, an IANA name, from the device and confirmed once. */
|
|
1206
|
+
time_zone: string;
|
|
1207
|
+
/**
|
|
1208
|
+
* @description The country they are in, ISO 3166-1 alpha-2, which their working calendar counts public
|
|
1209
|
+
* holidays by. Left out when the client does not know it.
|
|
1210
|
+
*/
|
|
1211
|
+
country?: string;
|
|
1212
|
+
};
|
|
1213
|
+
/**
|
|
1214
|
+
* @description ONE SIGN-UP: the question the first passkey answers, and until when an answer is taken. Single
|
|
1215
|
+
* use.
|
|
1216
|
+
*/
|
|
1217
|
+
SignUp: {
|
|
1218
|
+
/** @description What the completion names. */
|
|
1219
|
+
id: components["schemas"]["Id"];
|
|
1220
|
+
/** @description With `excludeCredentials` always empty, since the person holds no key yet. */
|
|
1221
|
+
creation_options: components["schemas"]["PasskeyCreationOptions"];
|
|
1222
|
+
/** @description When the sign-up dies. Minutes; after it, start again. */
|
|
1223
|
+
expires_at: components["schemas"]["Timestamp"];
|
|
1224
|
+
};
|
|
1225
|
+
SignUpCompletion: {
|
|
1226
|
+
attestation: components["schemas"]["PasskeyAttestation"];
|
|
1227
|
+
/** @description What the person calls their first key in their list of sign-in methods. */
|
|
1228
|
+
name: string;
|
|
1229
|
+
};
|
|
1230
|
+
/**
|
|
1231
|
+
* @description AN ACCOUNT MADE: the recovery codes, shown this once, and the first session, in the person's
|
|
1232
|
+
* personal environment.
|
|
1233
|
+
*/
|
|
1234
|
+
SignedUp: {
|
|
1235
|
+
/**
|
|
1236
|
+
* @description TEN ONE-TIME CODES, each good once, the only way back for a person who loses every passkey.
|
|
1237
|
+
* Shown here and never again: Onplo keeps none of them in the clear.
|
|
1238
|
+
*/
|
|
1239
|
+
recovery_codes: string[];
|
|
1240
|
+
session: components["schemas"]["SignedInSession"];
|
|
1241
|
+
};
|
|
1242
|
+
RecoveryStart: {
|
|
1243
|
+
username: components["schemas"]["Username"];
|
|
1244
|
+
/**
|
|
1245
|
+
* @description One of the person's recovery codes, as it was shown, lower case.
|
|
1246
|
+
* @example abcde-12345
|
|
1247
|
+
*/
|
|
1248
|
+
recovery_code: string;
|
|
1249
|
+
};
|
|
1250
|
+
/**
|
|
1251
|
+
* @description ONE RECOVERY: the question the new passkey answers, and until when an answer is taken. Single
|
|
1252
|
+
* use. Its id is the `sign_in_id` that opens the session afterwards.
|
|
1253
|
+
*/
|
|
1254
|
+
Recovery: {
|
|
1255
|
+
/** @description What the completion, and then `openSignedInSession`, name. */
|
|
1256
|
+
id: components["schemas"]["Id"];
|
|
1257
|
+
creation_options: components["schemas"]["PasskeyCreationOptions"];
|
|
1258
|
+
/** @description When the recovery dies. Minutes; after it, use another code. */
|
|
1259
|
+
expires_at: components["schemas"]["Timestamp"];
|
|
1260
|
+
};
|
|
1261
|
+
RecoveryCompletion: {
|
|
1262
|
+
attestation: components["schemas"]["PasskeyAttestation"];
|
|
1263
|
+
/** @description What the person calls the new key. It becomes their Primary passkey. */
|
|
1264
|
+
name: string;
|
|
1265
|
+
};
|
|
1266
|
+
/**
|
|
1267
|
+
* Format: date-time
|
|
1268
|
+
* @description RFC 3339, always UTC, always with the offset written out.
|
|
1269
|
+
* @example 2026-09-13T06:06:00Z
|
|
1270
|
+
*/
|
|
1271
|
+
Timestamp: string;
|
|
1272
|
+
/**
|
|
1273
|
+
* @description RFC 9457. Served as `application/problem+json`, on every failure, from every operation —
|
|
1274
|
+
* one shape to handle rather than one per endpoint. CLOSED, like every other object here:
|
|
1275
|
+
* the server validates its own answers against this schema, and an open object is the one
|
|
1276
|
+
* shape that check cannot see through.
|
|
1277
|
+
*/
|
|
1278
|
+
Problem: {
|
|
1279
|
+
/**
|
|
1280
|
+
* Format: uri
|
|
1281
|
+
* @description A stable URI naming the kind of problem. Dereferenceable; documentation lives there.
|
|
1282
|
+
* @example https://onplo.com/problems/passkey_not_verified
|
|
1283
|
+
*/
|
|
1284
|
+
type: string;
|
|
1285
|
+
/** @example The passkey did not verify */
|
|
1286
|
+
title: string;
|
|
1287
|
+
status: number;
|
|
1288
|
+
/** @description What went wrong THIS time, in a sentence a person could be shown. */
|
|
1289
|
+
detail?: string;
|
|
1290
|
+
/**
|
|
1291
|
+
* Format: uri-reference
|
|
1292
|
+
* @description The request path this happened on.
|
|
1293
|
+
*/
|
|
1294
|
+
instance?: string;
|
|
1295
|
+
/**
|
|
1296
|
+
* @description The machine name, stable across wording changes. `type` is the URI a human opens; this
|
|
1297
|
+
* is what a client branches on.
|
|
1298
|
+
* @example passkey_not_verified
|
|
1299
|
+
*/
|
|
1300
|
+
code: string;
|
|
1301
|
+
/**
|
|
1302
|
+
* Format: uuid
|
|
1303
|
+
* @description Quote it in a support request and the exact call can be found. It is also on the
|
|
1304
|
+
* `Onplo-Request-Id` response header of every response, failed or not.
|
|
1305
|
+
*/
|
|
1306
|
+
request_id: string;
|
|
1307
|
+
/** @description One entry per field that is wrong. REQUIRED on a 422. */
|
|
1308
|
+
errors?: {
|
|
1309
|
+
/**
|
|
1310
|
+
* @description A JSON Pointer (RFC 6901) at the wrong value, rooted at the REQUEST: `/body/...`
|
|
1311
|
+
* for a body field, `/path/...` for a path segment.
|
|
1312
|
+
* @example /body/answer/response/signature
|
|
1313
|
+
*/
|
|
1314
|
+
pointer: string;
|
|
1315
|
+
code: string;
|
|
1316
|
+
detail: string;
|
|
1317
|
+
}[];
|
|
1318
|
+
};
|
|
1319
|
+
/**
|
|
1320
|
+
* @description The provider's metadata, under the names OpenID Connect Discovery 1.0 gives them, so any
|
|
1321
|
+
* standard client reads it unchanged. Every list holds only what identity supports.
|
|
1322
|
+
*/
|
|
1323
|
+
ProviderDiscovery: {
|
|
1324
|
+
/**
|
|
1325
|
+
* Format: uri
|
|
1326
|
+
* @description The provider's address. Every ID token's `iss` is exactly this.
|
|
1327
|
+
*/
|
|
1328
|
+
issuer: string;
|
|
1329
|
+
/**
|
|
1330
|
+
* Format: uri
|
|
1331
|
+
* @description Where a person is sent to sign in.
|
|
1332
|
+
*/
|
|
1333
|
+
authorization_endpoint: string;
|
|
1334
|
+
/**
|
|
1335
|
+
* Format: uri
|
|
1336
|
+
* @description Where the answer is traded for tokens.
|
|
1337
|
+
*/
|
|
1338
|
+
token_endpoint: string;
|
|
1339
|
+
/**
|
|
1340
|
+
* Format: uri
|
|
1341
|
+
* @description Where the key set is, `readProviderKeySet`.
|
|
1342
|
+
*/
|
|
1343
|
+
jwks_uri: string;
|
|
1344
|
+
scopes_supported: "openid"[];
|
|
1345
|
+
response_types_supported: "code"[];
|
|
1346
|
+
response_modes_supported: "query"[];
|
|
1347
|
+
grant_types_supported: ("authorization_code" | "refresh_token")[];
|
|
1348
|
+
subject_types_supported: "public"[];
|
|
1349
|
+
id_token_signing_alg_values_supported: "ES256"[];
|
|
1350
|
+
/** @description `none`: every Onplo app is a public client and holds no secret. */
|
|
1351
|
+
token_endpoint_auth_methods_supported: "none"[];
|
|
1352
|
+
code_challenge_methods_supported: "S256"[];
|
|
1353
|
+
claims_supported: ("iss" | "sub" | "aud" | "exp" | "iat" | "auth_time" | "amr")[];
|
|
1354
|
+
};
|
|
1355
|
+
/** @description A JSON Web Key Set (RFC 7517). */
|
|
1356
|
+
ProviderKeySet: {
|
|
1357
|
+
keys: components["schemas"]["ProviderKey"][];
|
|
1358
|
+
};
|
|
1359
|
+
/**
|
|
1360
|
+
* @description One public key, an elliptic-curve key on P-256 as RFC 7518 writes it. The private half is never
|
|
1361
|
+
* anywhere this API reaches.
|
|
1362
|
+
*/
|
|
1363
|
+
ProviderKey: {
|
|
1364
|
+
/**
|
|
1365
|
+
* @description The key type.
|
|
1366
|
+
* @enum {string}
|
|
1367
|
+
*/
|
|
1368
|
+
kty: "EC";
|
|
1369
|
+
/**
|
|
1370
|
+
* @description The curve.
|
|
1371
|
+
* @enum {string}
|
|
1372
|
+
*/
|
|
1373
|
+
crv: "P-256";
|
|
1374
|
+
/** @description The point's x coordinate, 32 bytes in base64url. */
|
|
1375
|
+
x: string;
|
|
1376
|
+
/** @description The point's y coordinate, 32 bytes in base64url. */
|
|
1377
|
+
y: string;
|
|
1378
|
+
/** @description The key's id, its RFC 7638 thumbprint. An ID token's header names its key by it. */
|
|
1379
|
+
kid: string;
|
|
1380
|
+
/**
|
|
1381
|
+
* @description The key signs; it encrypts nothing.
|
|
1382
|
+
* @enum {string}
|
|
1383
|
+
*/
|
|
1384
|
+
use: "sig";
|
|
1385
|
+
/**
|
|
1386
|
+
* @description The one algorithm it signs with.
|
|
1387
|
+
* @enum {string}
|
|
1388
|
+
*/
|
|
1389
|
+
alg: "ES256";
|
|
1390
|
+
};
|
|
1391
|
+
};
|
|
1392
|
+
responses: {
|
|
1393
|
+
/**
|
|
1394
|
+
* @description The request could not be read, so nothing in it was looked at — `malformed_request`. Its body
|
|
1395
|
+
* is not valid JSON, or its address carries a broken `%`-escape. No field is named, because
|
|
1396
|
+
* none was read. Declared on every operation, the ones that take no body included: a body is
|
|
1397
|
+
* read before the server knows which operation it was sent to.
|
|
1398
|
+
*/
|
|
1399
|
+
BadRequest: {
|
|
1400
|
+
headers: {
|
|
1401
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1402
|
+
[name: string]: unknown;
|
|
1403
|
+
};
|
|
1404
|
+
content: {
|
|
1405
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1406
|
+
/** @enum {unknown} */
|
|
1407
|
+
code?: "malformed_request";
|
|
1408
|
+
};
|
|
1409
|
+
};
|
|
1410
|
+
};
|
|
1411
|
+
/**
|
|
1412
|
+
* @description There is no usable credential on this call — it is missing, malformed, unknown, expired, or
|
|
1413
|
+
* it has been REVOKED. A revoked credential fails HERE and not with 403, because it is no
|
|
1414
|
+
* longer a credential.
|
|
1415
|
+
*/
|
|
1416
|
+
Unauthorized: {
|
|
1417
|
+
headers: {
|
|
1418
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1419
|
+
"WWW-Authenticate": components["headers"]["WwwAuthenticate"];
|
|
1420
|
+
[name: string]: unknown;
|
|
1421
|
+
};
|
|
1422
|
+
content: {
|
|
1423
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1424
|
+
/** @enum {unknown} */
|
|
1425
|
+
code?: "credential_missing" | "credential_malformed" | "credential_unknown" | "credential_expired" | "credential_revoked";
|
|
1426
|
+
};
|
|
1427
|
+
};
|
|
1428
|
+
};
|
|
1429
|
+
/**
|
|
1430
|
+
* @description The credential is good and this call is refused anyway. `permission_missing`: the
|
|
1431
|
+
* credential does not carry the permission this operation needs. `ring_requires_person`: a
|
|
1432
|
+
* ring-1 act attempted by a raw key, refused regardless of scopes. `outside_session_scope`:
|
|
1433
|
+
* allowed to this subject and not within the scope this session declared at sign-in.
|
|
1434
|
+
*
|
|
1435
|
+
* ONE COMPONENT ON EVERY OPERATION, the ungated ones included, because the three reasons are
|
|
1436
|
+
* the same on every contract and a client writes one branch for them.
|
|
1437
|
+
*/
|
|
1438
|
+
Forbidden: {
|
|
1439
|
+
headers: {
|
|
1440
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1441
|
+
[name: string]: unknown;
|
|
1442
|
+
};
|
|
1443
|
+
content: {
|
|
1444
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1445
|
+
/** @enum {unknown} */
|
|
1446
|
+
code?: "permission_missing" | "ring_requires_person" | "outside_session_scope";
|
|
1447
|
+
};
|
|
1448
|
+
};
|
|
1449
|
+
};
|
|
1450
|
+
/**
|
|
1451
|
+
* @description No such ceremony, or not one this session started. The two are never told apart, and
|
|
1452
|
+
* neither is one that expired or was already answered: saying which would let somebody learn
|
|
1453
|
+
* about a ceremony by trying its id.
|
|
1454
|
+
*/
|
|
1455
|
+
NotFound: {
|
|
1456
|
+
headers: {
|
|
1457
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1458
|
+
"Cache-Control": components["headers"]["CacheControl"];
|
|
1459
|
+
[name: string]: unknown;
|
|
1460
|
+
};
|
|
1461
|
+
content: {
|
|
1462
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1463
|
+
/** @enum {unknown} */
|
|
1464
|
+
code?: "not_found";
|
|
1465
|
+
};
|
|
1466
|
+
};
|
|
1467
|
+
};
|
|
1468
|
+
/**
|
|
1469
|
+
* @description The request body is larger than this API reads — `request_too_large`. `detail` names the
|
|
1470
|
+
* limit in bytes. Declared on every operation, for the reason `BadRequest` gives.
|
|
1471
|
+
*/
|
|
1472
|
+
ContentTooLarge: {
|
|
1473
|
+
headers: {
|
|
1474
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1475
|
+
[name: string]: unknown;
|
|
1476
|
+
};
|
|
1477
|
+
content: {
|
|
1478
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1479
|
+
/** @enum {unknown} */
|
|
1480
|
+
code?: "request_too_large";
|
|
1481
|
+
};
|
|
1482
|
+
};
|
|
1483
|
+
};
|
|
1484
|
+
/**
|
|
1485
|
+
* @description The request body is in a form this API does not read — `unsupported_media_type`. This API
|
|
1486
|
+
* reads JSON, sent uncompressed as `application/json`, and nothing else.
|
|
1487
|
+
*/
|
|
1488
|
+
UnsupportedMediaType: {
|
|
1489
|
+
headers: {
|
|
1490
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1491
|
+
[name: string]: unknown;
|
|
1492
|
+
};
|
|
1493
|
+
content: {
|
|
1494
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1495
|
+
/** @enum {unknown} */
|
|
1496
|
+
code?: "unsupported_media_type";
|
|
1497
|
+
};
|
|
1498
|
+
};
|
|
1499
|
+
};
|
|
1500
|
+
/**
|
|
1501
|
+
* @description The request parsed and something in it is wrong. `errors` says what, one entry per field,
|
|
1502
|
+
* each with a JSON Pointer at it. ONE `code`, because the detail is in `errors`. This is
|
|
1503
|
+
* about the SHAPE of what was sent; an answer of the right shape that does not verify is the
|
|
1504
|
+
* 409 on that operation.
|
|
1505
|
+
*/
|
|
1506
|
+
Unprocessable: {
|
|
1507
|
+
headers: {
|
|
1508
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1509
|
+
[name: string]: unknown;
|
|
1510
|
+
};
|
|
1511
|
+
content: {
|
|
1512
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1513
|
+
/** @enum {unknown} */
|
|
1514
|
+
code?: "unprocessable_request";
|
|
1515
|
+
};
|
|
1516
|
+
};
|
|
1517
|
+
};
|
|
1518
|
+
/**
|
|
1519
|
+
* @description This door was called too often in the last minute, from this address or from everyone
|
|
1520
|
+
* together — `too_many_requests`. Nothing was read and no token was issued. `Retry-After`
|
|
1521
|
+
* says how many whole seconds to wait; the same call is then answered as usual.
|
|
1522
|
+
*
|
|
1523
|
+
* Only a door that answers with no credential is limited this way, because nobody is charged
|
|
1524
|
+
* for the call (decision 0732). How many calls a minute it takes is not part of this contract.
|
|
1525
|
+
*/
|
|
1526
|
+
TooManyCalls: {
|
|
1527
|
+
headers: {
|
|
1528
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1529
|
+
"Retry-After": components["headers"]["RetryAfter"];
|
|
1530
|
+
[name: string]: unknown;
|
|
1531
|
+
};
|
|
1532
|
+
content: {
|
|
1533
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1534
|
+
/** @enum {unknown} */
|
|
1535
|
+
code?: "too_many_requests";
|
|
1536
|
+
};
|
|
1537
|
+
};
|
|
1538
|
+
};
|
|
1539
|
+
/**
|
|
1540
|
+
* @description Something failed that this contract cannot describe — including an answer this API produced
|
|
1541
|
+
* and then refused to send, because the contract does not describe that answer either
|
|
1542
|
+
* (`response_not_in_contract`). Response validation stays on in production (decision 0551).
|
|
1543
|
+
* `request_id` is what finds the call.
|
|
1544
|
+
*/
|
|
1545
|
+
ServerError: {
|
|
1546
|
+
headers: {
|
|
1547
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1548
|
+
[name: string]: unknown;
|
|
1549
|
+
};
|
|
1550
|
+
content: {
|
|
1551
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1552
|
+
/** @enum {unknown} */
|
|
1553
|
+
code?: "internal_error" | "response_not_in_contract";
|
|
1554
|
+
};
|
|
1555
|
+
};
|
|
1556
|
+
};
|
|
1557
|
+
/**
|
|
1558
|
+
* @description The authorization service could not be asked, so whether this call may proceed is UNKNOWN —
|
|
1559
|
+
* `authorization_unavailable`. Never a 403, which would claim a refusal when all that is
|
|
1560
|
+
* known is that we could not ask.
|
|
1561
|
+
*/
|
|
1562
|
+
ServiceUnavailable: {
|
|
1563
|
+
headers: {
|
|
1564
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1565
|
+
[name: string]: unknown;
|
|
1566
|
+
};
|
|
1567
|
+
content: {
|
|
1568
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1569
|
+
/** @enum {unknown} */
|
|
1570
|
+
code?: "authorization_unavailable";
|
|
1571
|
+
};
|
|
1572
|
+
};
|
|
1573
|
+
};
|
|
1574
|
+
/**
|
|
1575
|
+
* @description **Onplo has not built this operation yet** — `not_implemented` (decision 0580). It is
|
|
1576
|
+
* declared here because the contract is written before the code; it is not a 404, because the
|
|
1577
|
+
* address is right, and not a 503, because there is nothing to retry. Treat the operation as
|
|
1578
|
+
* absent for now. Nothing about your credential or your request caused this.
|
|
1579
|
+
*/
|
|
1580
|
+
NotImplemented: {
|
|
1581
|
+
headers: {
|
|
1582
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1583
|
+
"Cache-Control": components["headers"]["CacheControl"];
|
|
1584
|
+
[name: string]: unknown;
|
|
1585
|
+
};
|
|
1586
|
+
content: {
|
|
1587
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1588
|
+
/** @enum {unknown} */
|
|
1589
|
+
code?: "not_implemented";
|
|
1590
|
+
};
|
|
1591
|
+
};
|
|
1592
|
+
};
|
|
1593
|
+
};
|
|
1594
|
+
parameters: {
|
|
1595
|
+
PasskeyProofId: components["schemas"]["Id"];
|
|
1596
|
+
SignInId: components["schemas"]["Id"];
|
|
1597
|
+
PasskeyRegistrationId: components["schemas"]["Id"];
|
|
1598
|
+
SignUpId: components["schemas"]["Id"];
|
|
1599
|
+
RecoveryId: components["schemas"]["Id"];
|
|
1600
|
+
};
|
|
1601
|
+
requestBodies: never;
|
|
1602
|
+
headers: {
|
|
1603
|
+
/**
|
|
1604
|
+
* @description The id of this call. Minted by the server as a UUID version 7 and **never taken from a
|
|
1605
|
+
* request header** (decision 0553). It rides EVERY response, and it is the same value as the
|
|
1606
|
+
* problem document's `request_id` when there is one. Quote it in a support request and the
|
|
1607
|
+
* exact call can be found.
|
|
1608
|
+
*/
|
|
1609
|
+
OnploRequestId: string;
|
|
1610
|
+
/**
|
|
1611
|
+
* @description The challenge RFC 9110 §11.6.1 and RFC 6750 §3 require on a 401 under a bearer scheme
|
|
1612
|
+
* (decision 0569). `Bearer realm="onplo"` alone when no credential was sent; otherwise
|
|
1613
|
+
* `Bearer realm="onplo", error="invalid_token"`. It never carries `error_description` and never
|
|
1614
|
+
* `scope`. A 403 carries no challenge at all.
|
|
1615
|
+
*/
|
|
1616
|
+
WwwAuthenticate: string;
|
|
1617
|
+
/**
|
|
1618
|
+
* @description `no-store`, in two places. On the statuses RFC 9110 §15.1 makes cacheable by default — a
|
|
1619
|
+
* 404 and a 501 (decision 0580): a cached "not built yet" would outlive the day the operation
|
|
1620
|
+
* is built. And on every answer that carries a credential — `tradeDeviceStatement`'s,
|
|
1621
|
+
* `switchEnvironment`'s, `completeSignIn`'s, `openSignedInSession`'s, `completeSignUp`'s and
|
|
1622
|
+
* `completeRecovery`'s — each marked `x-carries-secret` so the server sends it.
|
|
1623
|
+
*/
|
|
1624
|
+
CacheControl: "no-store";
|
|
1625
|
+
/**
|
|
1626
|
+
* @description Whole seconds until a limited caller may call this door again (decision 0732). It rides a
|
|
1627
|
+
* 429 and no other status.
|
|
1628
|
+
*/
|
|
1629
|
+
RetryAfter: number;
|
|
1630
|
+
/**
|
|
1631
|
+
* @description Where the browser is sent (decision 1027): identity's sign-in screen, or the app's registered
|
|
1632
|
+
* return address with an OAuth `error`. It rides a redirect and no other answer.
|
|
1633
|
+
*/
|
|
1634
|
+
Location: string;
|
|
1635
|
+
};
|
|
1636
|
+
pathItems: never;
|
|
1637
|
+
}
|
|
1638
|
+
export type $defs = Record<string, never>;
|
|
1639
|
+
export interface operations {
|
|
1640
|
+
readProviderDiscovery: {
|
|
1641
|
+
parameters: {
|
|
1642
|
+
query?: never;
|
|
1643
|
+
header?: never;
|
|
1644
|
+
path?: never;
|
|
1645
|
+
cookie?: never;
|
|
1646
|
+
};
|
|
1647
|
+
requestBody?: never;
|
|
1648
|
+
responses: {
|
|
1649
|
+
/** @description The discovery document. */
|
|
1650
|
+
200: {
|
|
1651
|
+
headers: {
|
|
1652
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1653
|
+
[name: string]: unknown;
|
|
1654
|
+
};
|
|
1655
|
+
content: {
|
|
1656
|
+
"application/json": components["schemas"]["ProviderDiscovery"];
|
|
1657
|
+
};
|
|
1658
|
+
};
|
|
1659
|
+
400: components["responses"]["BadRequest"];
|
|
1660
|
+
413: components["responses"]["ContentTooLarge"];
|
|
1661
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
1662
|
+
429: components["responses"]["TooManyCalls"];
|
|
1663
|
+
500: components["responses"]["ServerError"];
|
|
1664
|
+
501: components["responses"]["NotImplemented"];
|
|
1665
|
+
};
|
|
1666
|
+
};
|
|
1667
|
+
readProviderKeySet: {
|
|
1668
|
+
parameters: {
|
|
1669
|
+
query?: never;
|
|
1670
|
+
header?: never;
|
|
1671
|
+
path?: never;
|
|
1672
|
+
cookie?: never;
|
|
1673
|
+
};
|
|
1674
|
+
requestBody?: never;
|
|
1675
|
+
responses: {
|
|
1676
|
+
/** @description The key set. */
|
|
1677
|
+
200: {
|
|
1678
|
+
headers: {
|
|
1679
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1680
|
+
[name: string]: unknown;
|
|
1681
|
+
};
|
|
1682
|
+
content: {
|
|
1683
|
+
"application/json": components["schemas"]["ProviderKeySet"];
|
|
1684
|
+
};
|
|
1685
|
+
};
|
|
1686
|
+
400: components["responses"]["BadRequest"];
|
|
1687
|
+
413: components["responses"]["ContentTooLarge"];
|
|
1688
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
1689
|
+
429: components["responses"]["TooManyCalls"];
|
|
1690
|
+
500: components["responses"]["ServerError"];
|
|
1691
|
+
501: components["responses"]["NotImplemented"];
|
|
1692
|
+
};
|
|
1693
|
+
};
|
|
1694
|
+
authorizeSignIn: {
|
|
1695
|
+
parameters: {
|
|
1696
|
+
query?: {
|
|
1697
|
+
/** @description The app, by the id Onplo lists it under. */
|
|
1698
|
+
client_id?: string;
|
|
1699
|
+
/** @description Where the app is sent back to, exactly as it registered it. */
|
|
1700
|
+
redirect_uri?: string;
|
|
1701
|
+
/** @description Always `code`. */
|
|
1702
|
+
response_type?: string;
|
|
1703
|
+
/** @description The scopes asked, space-separated. `openid` is always one of them. */
|
|
1704
|
+
scope?: string;
|
|
1705
|
+
/** @description The app's own value, sent back to it. */
|
|
1706
|
+
state?: string;
|
|
1707
|
+
/** @description The PKCE challenge, the SHA-256 of the app's verifier in base64url. */
|
|
1708
|
+
code_challenge?: string;
|
|
1709
|
+
/** @description Always `S256`. */
|
|
1710
|
+
code_challenge_method?: string;
|
|
1711
|
+
/** @description The app's value the ID token echoes. */
|
|
1712
|
+
nonce?: string;
|
|
1713
|
+
};
|
|
1714
|
+
header?: never;
|
|
1715
|
+
path?: never;
|
|
1716
|
+
cookie?: never;
|
|
1717
|
+
};
|
|
1718
|
+
requestBody?: never;
|
|
1719
|
+
responses: {
|
|
1720
|
+
/** @description The browser is sent to the sign-in screen, or back to the app with an error. */
|
|
1721
|
+
302: {
|
|
1722
|
+
headers: {
|
|
1723
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1724
|
+
Location: components["headers"]["Location"];
|
|
1725
|
+
[name: string]: unknown;
|
|
1726
|
+
};
|
|
1727
|
+
content?: never;
|
|
1728
|
+
};
|
|
1729
|
+
/**
|
|
1730
|
+
* @description Nothing is redirected. `not_registered`: the app, or its return address, is not one Onplo
|
|
1731
|
+
* lists. `malformed_request`: the address could not be read.
|
|
1732
|
+
*/
|
|
1733
|
+
400: {
|
|
1734
|
+
headers: {
|
|
1735
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1736
|
+
[name: string]: unknown;
|
|
1737
|
+
};
|
|
1738
|
+
content: {
|
|
1739
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1740
|
+
/** @enum {unknown} */
|
|
1741
|
+
code?: "malformed_request" | "not_registered";
|
|
1742
|
+
};
|
|
1743
|
+
};
|
|
1744
|
+
};
|
|
1745
|
+
413: components["responses"]["ContentTooLarge"];
|
|
1746
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
1747
|
+
422: components["responses"]["Unprocessable"];
|
|
1748
|
+
429: components["responses"]["TooManyCalls"];
|
|
1749
|
+
500: components["responses"]["ServerError"];
|
|
1750
|
+
};
|
|
1751
|
+
};
|
|
1752
|
+
startPasskeyProof: {
|
|
1753
|
+
parameters: {
|
|
1754
|
+
query?: never;
|
|
1755
|
+
header?: never;
|
|
1756
|
+
path?: never;
|
|
1757
|
+
cookie?: never;
|
|
1758
|
+
};
|
|
1759
|
+
requestBody?: never;
|
|
1760
|
+
responses: {
|
|
1761
|
+
/** @description The ceremony, and the question to put to the passkey. */
|
|
1762
|
+
201: {
|
|
1763
|
+
headers: {
|
|
1764
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1765
|
+
[name: string]: unknown;
|
|
1766
|
+
};
|
|
1767
|
+
content: {
|
|
1768
|
+
"application/json": components["schemas"]["PasskeyProof"];
|
|
1769
|
+
};
|
|
1770
|
+
};
|
|
1771
|
+
400: components["responses"]["BadRequest"];
|
|
1772
|
+
401: components["responses"]["Unauthorized"];
|
|
1773
|
+
403: components["responses"]["Forbidden"];
|
|
1774
|
+
/**
|
|
1775
|
+
* @description Refused: the credential is not a person's signed-in session (`not_a_person_session`).
|
|
1776
|
+
* A key, a grant and an AI agent have no passkey to ask.
|
|
1777
|
+
*/
|
|
1778
|
+
409: {
|
|
1779
|
+
headers: {
|
|
1780
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1781
|
+
[name: string]: unknown;
|
|
1782
|
+
};
|
|
1783
|
+
content: {
|
|
1784
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1785
|
+
/** @enum {unknown} */
|
|
1786
|
+
code?: "not_a_person_session";
|
|
1787
|
+
};
|
|
1788
|
+
};
|
|
1789
|
+
};
|
|
1790
|
+
413: components["responses"]["ContentTooLarge"];
|
|
1791
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
1792
|
+
500: components["responses"]["ServerError"];
|
|
1793
|
+
503: components["responses"]["ServiceUnavailable"];
|
|
1794
|
+
};
|
|
1795
|
+
};
|
|
1796
|
+
completePasskeyProof: {
|
|
1797
|
+
parameters: {
|
|
1798
|
+
query?: never;
|
|
1799
|
+
header?: never;
|
|
1800
|
+
path: {
|
|
1801
|
+
passkey_proof_id: components["parameters"]["PasskeyProofId"];
|
|
1802
|
+
};
|
|
1803
|
+
cookie?: never;
|
|
1804
|
+
};
|
|
1805
|
+
requestBody: {
|
|
1806
|
+
content: {
|
|
1807
|
+
"application/json": components["schemas"]["PasskeyProofCompletion"];
|
|
1808
|
+
};
|
|
1809
|
+
};
|
|
1810
|
+
responses: {
|
|
1811
|
+
/** @description Proved. The moment this session now carries. */
|
|
1812
|
+
200: {
|
|
1813
|
+
headers: {
|
|
1814
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1815
|
+
[name: string]: unknown;
|
|
1816
|
+
};
|
|
1817
|
+
content: {
|
|
1818
|
+
"application/json": components["schemas"]["SessionProof"];
|
|
1819
|
+
};
|
|
1820
|
+
};
|
|
1821
|
+
400: components["responses"]["BadRequest"];
|
|
1822
|
+
401: components["responses"]["Unauthorized"];
|
|
1823
|
+
403: components["responses"]["Forbidden"];
|
|
1824
|
+
404: components["responses"]["NotFound"];
|
|
1825
|
+
/**
|
|
1826
|
+
* @description Refused: the passkey's answer did not verify (`passkey_not_verified`). The ceremony is
|
|
1827
|
+
* spent.
|
|
1828
|
+
*/
|
|
1829
|
+
409: {
|
|
1830
|
+
headers: {
|
|
1831
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1832
|
+
[name: string]: unknown;
|
|
1833
|
+
};
|
|
1834
|
+
content: {
|
|
1835
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1836
|
+
/** @enum {unknown} */
|
|
1837
|
+
code?: "passkey_not_verified";
|
|
1838
|
+
};
|
|
1839
|
+
};
|
|
1840
|
+
};
|
|
1841
|
+
413: components["responses"]["ContentTooLarge"];
|
|
1842
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
1843
|
+
422: components["responses"]["Unprocessable"];
|
|
1844
|
+
500: components["responses"]["ServerError"];
|
|
1845
|
+
503: components["responses"]["ServiceUnavailable"];
|
|
1846
|
+
};
|
|
1847
|
+
};
|
|
1848
|
+
tradeDeviceStatement: {
|
|
1849
|
+
parameters: {
|
|
1850
|
+
query?: never;
|
|
1851
|
+
header?: never;
|
|
1852
|
+
path?: never;
|
|
1853
|
+
cookie?: never;
|
|
1854
|
+
};
|
|
1855
|
+
requestBody: {
|
|
1856
|
+
content: {
|
|
1857
|
+
"application/json": {
|
|
1858
|
+
/**
|
|
1859
|
+
* @description The signed statement, in the compact form: three base64url parts joined by
|
|
1860
|
+
* dots. Bounded, because an unbounded string in a body makes the body limit
|
|
1861
|
+
* unprovable. The example shows the SHAPE and is no statement at all: its three
|
|
1862
|
+
* parts are the words header, claims and signature.
|
|
1863
|
+
* @example aGVhZGVy.Y2xhaW1z.c2lnbmF0dXJl
|
|
1864
|
+
*/
|
|
1865
|
+
statement: string;
|
|
1866
|
+
/**
|
|
1867
|
+
* @description A RENEWAL, sent only when the device wants its next certificate: a PKCS #10
|
|
1868
|
+
* certificate request (RFC 2986) for a NEW P-256 key, signed by that key, in DER
|
|
1869
|
+
* and written base64url with no padding. One for P-256 is a few hundred bytes;
|
|
1870
|
+
* the ceiling leaves room for the names it carries.
|
|
1871
|
+
*/
|
|
1872
|
+
certificate_request?: string;
|
|
1873
|
+
};
|
|
1874
|
+
};
|
|
1875
|
+
};
|
|
1876
|
+
responses: {
|
|
1877
|
+
/**
|
|
1878
|
+
* @description The token, and when it stops being good, and when the certificate behind it does. With
|
|
1879
|
+
* a renewal, the new certificate too. Sent with `no-store`.
|
|
1880
|
+
*/
|
|
1881
|
+
201: {
|
|
1882
|
+
headers: {
|
|
1883
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1884
|
+
"Cache-Control": components["headers"]["CacheControl"];
|
|
1885
|
+
[name: string]: unknown;
|
|
1886
|
+
};
|
|
1887
|
+
content: {
|
|
1888
|
+
"application/json": components["schemas"]["DeviceToken"];
|
|
1889
|
+
};
|
|
1890
|
+
};
|
|
1891
|
+
400: components["responses"]["BadRequest"];
|
|
1892
|
+
/**
|
|
1893
|
+
* @description Refused. `statement_not_verified`: the statement does not prove a device Onplo will
|
|
1894
|
+
* answer — which check failed is never said. `statement_outside_its_time`: its `exp` is
|
|
1895
|
+
* past, or more than five minutes ahead; set the clock by this answer's `Date` header
|
|
1896
|
+
* and sign a new one. The five others refuse a renewal's certificate request, and the
|
|
1897
|
+
* operation's description says each. No token is issued, and no certificate, either way.
|
|
1898
|
+
*/
|
|
1899
|
+
409: {
|
|
1900
|
+
headers: {
|
|
1901
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1902
|
+
[name: string]: unknown;
|
|
1903
|
+
};
|
|
1904
|
+
content: {
|
|
1905
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1906
|
+
/** @enum {unknown} */
|
|
1907
|
+
code?: "statement_not_verified" | "statement_outside_its_time" | "certificate_request_unreadable" | "certificate_request_not_signed_by_its_key" | "key_not_certified" | "key_ended" | "key_already_certified";
|
|
1908
|
+
};
|
|
1909
|
+
};
|
|
1910
|
+
};
|
|
1911
|
+
413: components["responses"]["ContentTooLarge"];
|
|
1912
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
1913
|
+
422: components["responses"]["Unprocessable"];
|
|
1914
|
+
429: components["responses"]["TooManyCalls"];
|
|
1915
|
+
500: components["responses"]["ServerError"];
|
|
1916
|
+
501: components["responses"]["NotImplemented"];
|
|
1917
|
+
};
|
|
1918
|
+
};
|
|
1919
|
+
switchEnvironment: {
|
|
1920
|
+
parameters: {
|
|
1921
|
+
query?: never;
|
|
1922
|
+
header?: never;
|
|
1923
|
+
path?: never;
|
|
1924
|
+
cookie?: never;
|
|
1925
|
+
};
|
|
1926
|
+
requestBody: {
|
|
1927
|
+
content: {
|
|
1928
|
+
"application/json": {
|
|
1929
|
+
/** @description The account environment to open a session in. */
|
|
1930
|
+
environment_id: components["schemas"]["Id"];
|
|
1931
|
+
};
|
|
1932
|
+
};
|
|
1933
|
+
};
|
|
1934
|
+
responses: {
|
|
1935
|
+
/** @description The new session's token, where it acts, and until when. Sent with `no-store`. */
|
|
1936
|
+
201: {
|
|
1937
|
+
headers: {
|
|
1938
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1939
|
+
"Cache-Control": components["headers"]["CacheControl"];
|
|
1940
|
+
[name: string]: unknown;
|
|
1941
|
+
};
|
|
1942
|
+
content: {
|
|
1943
|
+
"application/json": components["schemas"]["SwitchedSession"];
|
|
1944
|
+
};
|
|
1945
|
+
};
|
|
1946
|
+
400: components["responses"]["BadRequest"];
|
|
1947
|
+
401: components["responses"]["Unauthorized"];
|
|
1948
|
+
403: components["responses"]["Forbidden"];
|
|
1949
|
+
/**
|
|
1950
|
+
* @description Refused, and no session is opened. `not_a_person_session`: the credential is not a
|
|
1951
|
+
* person's signed-in session. `not_a_member`: the person is not a member of that
|
|
1952
|
+
* environment now, or it does not exist. `membership_suspended`: they are a member and
|
|
1953
|
+
* suspended there. `passkey_proof_needed`: prove it is you on this session, then send the
|
|
1954
|
+
* switch again. `already_in_that_environment`: the session that asked already acts there.
|
|
1955
|
+
*/
|
|
1956
|
+
409: {
|
|
1957
|
+
headers: {
|
|
1958
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1959
|
+
[name: string]: unknown;
|
|
1960
|
+
};
|
|
1961
|
+
content: {
|
|
1962
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
1963
|
+
/** @enum {unknown} */
|
|
1964
|
+
code?: "not_a_person_session" | "not_a_member" | "membership_suspended" | "passkey_proof_needed" | "already_in_that_environment";
|
|
1965
|
+
};
|
|
1966
|
+
};
|
|
1967
|
+
};
|
|
1968
|
+
413: components["responses"]["ContentTooLarge"];
|
|
1969
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
1970
|
+
422: components["responses"]["Unprocessable"];
|
|
1971
|
+
500: components["responses"]["ServerError"];
|
|
1972
|
+
503: components["responses"]["ServiceUnavailable"];
|
|
1973
|
+
};
|
|
1974
|
+
};
|
|
1975
|
+
startSignIn: {
|
|
1976
|
+
parameters: {
|
|
1977
|
+
query?: never;
|
|
1978
|
+
header?: never;
|
|
1979
|
+
path?: never;
|
|
1980
|
+
cookie?: never;
|
|
1981
|
+
};
|
|
1982
|
+
requestBody?: never;
|
|
1983
|
+
responses: {
|
|
1984
|
+
/** @description The sign-in, and the question to put to the passkey. */
|
|
1985
|
+
201: {
|
|
1986
|
+
headers: {
|
|
1987
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
1988
|
+
[name: string]: unknown;
|
|
1989
|
+
};
|
|
1990
|
+
content: {
|
|
1991
|
+
"application/json": components["schemas"]["SignIn"];
|
|
1992
|
+
};
|
|
1993
|
+
};
|
|
1994
|
+
400: components["responses"]["BadRequest"];
|
|
1995
|
+
413: components["responses"]["ContentTooLarge"];
|
|
1996
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
1997
|
+
429: components["responses"]["TooManyCalls"];
|
|
1998
|
+
500: components["responses"]["ServerError"];
|
|
1999
|
+
};
|
|
2000
|
+
};
|
|
2001
|
+
completeSignIn: {
|
|
2002
|
+
parameters: {
|
|
2003
|
+
query?: never;
|
|
2004
|
+
header?: never;
|
|
2005
|
+
path: {
|
|
2006
|
+
sign_in_id: components["parameters"]["SignInId"];
|
|
2007
|
+
};
|
|
2008
|
+
cookie?: never;
|
|
2009
|
+
};
|
|
2010
|
+
requestBody: {
|
|
2011
|
+
content: {
|
|
2012
|
+
"application/json": components["schemas"]["SignInCompletion"];
|
|
2013
|
+
};
|
|
2014
|
+
};
|
|
2015
|
+
responses: {
|
|
2016
|
+
/** @description Proved. Where the person may go, and the token that opens one session. Sent with `no-store`. */
|
|
2017
|
+
200: {
|
|
2018
|
+
headers: {
|
|
2019
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2020
|
+
"Cache-Control": components["headers"]["CacheControl"];
|
|
2021
|
+
[name: string]: unknown;
|
|
2022
|
+
};
|
|
2023
|
+
content: {
|
|
2024
|
+
"application/json": components["schemas"]["SignInChoices"];
|
|
2025
|
+
};
|
|
2026
|
+
};
|
|
2027
|
+
400: components["responses"]["BadRequest"];
|
|
2028
|
+
404: components["responses"]["NotFound"];
|
|
2029
|
+
/**
|
|
2030
|
+
* @description Refused, and the sign-in is spent. `passkey_not_verified`: the answer did not prove a
|
|
2031
|
+
* person Onplo will sign in, and which check failed is never said.
|
|
2032
|
+
* `device_token_not_verified`: the device token shown beside it is not a live device's.
|
|
2033
|
+
*/
|
|
2034
|
+
409: {
|
|
2035
|
+
headers: {
|
|
2036
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2037
|
+
[name: string]: unknown;
|
|
2038
|
+
};
|
|
2039
|
+
content: {
|
|
2040
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
2041
|
+
/** @enum {unknown} */
|
|
2042
|
+
code?: "passkey_not_verified" | "device_token_not_verified";
|
|
2043
|
+
};
|
|
2044
|
+
};
|
|
2045
|
+
};
|
|
2046
|
+
413: components["responses"]["ContentTooLarge"];
|
|
2047
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
2048
|
+
422: components["responses"]["Unprocessable"];
|
|
2049
|
+
429: components["responses"]["TooManyCalls"];
|
|
2050
|
+
500: components["responses"]["ServerError"];
|
|
2051
|
+
503: components["responses"]["ServiceUnavailable"];
|
|
2052
|
+
};
|
|
2053
|
+
};
|
|
2054
|
+
openSignedInSession: {
|
|
2055
|
+
parameters: {
|
|
2056
|
+
query?: never;
|
|
2057
|
+
header?: never;
|
|
2058
|
+
path: {
|
|
2059
|
+
sign_in_id: components["parameters"]["SignInId"];
|
|
2060
|
+
};
|
|
2061
|
+
cookie?: never;
|
|
2062
|
+
};
|
|
2063
|
+
requestBody: {
|
|
2064
|
+
content: {
|
|
2065
|
+
"application/json": components["schemas"]["SignedInSessionOpening"];
|
|
2066
|
+
};
|
|
2067
|
+
};
|
|
2068
|
+
responses: {
|
|
2069
|
+
/** @description The session's token, where it acts, and until when. Sent with `no-store`. */
|
|
2070
|
+
201: {
|
|
2071
|
+
headers: {
|
|
2072
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2073
|
+
"Cache-Control": components["headers"]["CacheControl"];
|
|
2074
|
+
[name: string]: unknown;
|
|
2075
|
+
};
|
|
2076
|
+
content: {
|
|
2077
|
+
"application/json": components["schemas"]["SignedInSession"];
|
|
2078
|
+
};
|
|
2079
|
+
};
|
|
2080
|
+
400: components["responses"]["BadRequest"];
|
|
2081
|
+
404: components["responses"]["NotFound"];
|
|
2082
|
+
/**
|
|
2083
|
+
* @description Refused, and no session is opened; the sign-in token is still good until it expires.
|
|
2084
|
+
* `not_a_choice`: an environment sent is not one the completion listed, or the one to land
|
|
2085
|
+
* in is not among those chosen. `membership_suspended`: the person is suspended in the
|
|
2086
|
+
* environment they would land in; choose another.
|
|
2087
|
+
*/
|
|
2088
|
+
409: {
|
|
2089
|
+
headers: {
|
|
2090
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2091
|
+
[name: string]: unknown;
|
|
2092
|
+
};
|
|
2093
|
+
content: {
|
|
2094
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
2095
|
+
/** @enum {unknown} */
|
|
2096
|
+
code?: "not_a_choice" | "membership_suspended";
|
|
2097
|
+
};
|
|
2098
|
+
};
|
|
2099
|
+
};
|
|
2100
|
+
413: components["responses"]["ContentTooLarge"];
|
|
2101
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
2102
|
+
422: components["responses"]["Unprocessable"];
|
|
2103
|
+
429: components["responses"]["TooManyCalls"];
|
|
2104
|
+
500: components["responses"]["ServerError"];
|
|
2105
|
+
};
|
|
2106
|
+
};
|
|
2107
|
+
grantAuthorizationCode: {
|
|
2108
|
+
parameters: {
|
|
2109
|
+
query?: never;
|
|
2110
|
+
header?: never;
|
|
2111
|
+
path: {
|
|
2112
|
+
sign_in_id: components["parameters"]["SignInId"];
|
|
2113
|
+
};
|
|
2114
|
+
cookie?: never;
|
|
2115
|
+
};
|
|
2116
|
+
requestBody: {
|
|
2117
|
+
content: {
|
|
2118
|
+
"application/json": components["schemas"]["AuthorizationCodeGrant"];
|
|
2119
|
+
};
|
|
2120
|
+
};
|
|
2121
|
+
responses: {
|
|
2122
|
+
/** @description Where to send the browser, back to the app with its code. Sent with `no-store`. */
|
|
2123
|
+
201: {
|
|
2124
|
+
headers: {
|
|
2125
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2126
|
+
"Cache-Control": components["headers"]["CacheControl"];
|
|
2127
|
+
[name: string]: unknown;
|
|
2128
|
+
};
|
|
2129
|
+
content: {
|
|
2130
|
+
"application/json": components["schemas"]["AuthorizationCodeGranted"];
|
|
2131
|
+
};
|
|
2132
|
+
};
|
|
2133
|
+
400: components["responses"]["BadRequest"];
|
|
2134
|
+
404: components["responses"]["NotFound"];
|
|
2135
|
+
/**
|
|
2136
|
+
* @description Refused, and no code is kept; the sign-in token is still good until it expires.
|
|
2137
|
+
* `not_a_choice` and `membership_suspended` are what `openSignedInSession` answers.
|
|
2138
|
+
* `not_registered`: the app, or its return address, is not one Onplo lists. The browser is
|
|
2139
|
+
* never sent there. `authorization_request_refused`: the request is not one the
|
|
2140
|
+
* authorization endpoint takes.
|
|
2141
|
+
*/
|
|
2142
|
+
409: {
|
|
2143
|
+
headers: {
|
|
2144
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2145
|
+
[name: string]: unknown;
|
|
2146
|
+
};
|
|
2147
|
+
content: {
|
|
2148
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
2149
|
+
/** @enum {unknown} */
|
|
2150
|
+
code?: "not_a_choice" | "membership_suspended" | "not_registered" | "authorization_request_refused";
|
|
2151
|
+
};
|
|
2152
|
+
};
|
|
2153
|
+
};
|
|
2154
|
+
413: components["responses"]["ContentTooLarge"];
|
|
2155
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
2156
|
+
422: components["responses"]["Unprocessable"];
|
|
2157
|
+
429: components["responses"]["TooManyCalls"];
|
|
2158
|
+
500: components["responses"]["ServerError"];
|
|
2159
|
+
};
|
|
2160
|
+
};
|
|
2161
|
+
startPasskeyRegistration: {
|
|
2162
|
+
parameters: {
|
|
2163
|
+
query?: never;
|
|
2164
|
+
header?: never;
|
|
2165
|
+
path?: never;
|
|
2166
|
+
cookie?: never;
|
|
2167
|
+
};
|
|
2168
|
+
requestBody?: never;
|
|
2169
|
+
responses: {
|
|
2170
|
+
/** @description The registration, and the question to put to the new key. */
|
|
2171
|
+
201: {
|
|
2172
|
+
headers: {
|
|
2173
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2174
|
+
[name: string]: unknown;
|
|
2175
|
+
};
|
|
2176
|
+
content: {
|
|
2177
|
+
"application/json": components["schemas"]["PasskeyRegistration"];
|
|
2178
|
+
};
|
|
2179
|
+
};
|
|
2180
|
+
400: components["responses"]["BadRequest"];
|
|
2181
|
+
401: components["responses"]["Unauthorized"];
|
|
2182
|
+
403: components["responses"]["Forbidden"];
|
|
2183
|
+
/**
|
|
2184
|
+
* @description Refused. `not_a_person_session`: the credential is not a person's signed-in session.
|
|
2185
|
+
* `passkey_proof_needed`: prove it is you on this session, then ask again.
|
|
2186
|
+
*/
|
|
2187
|
+
409: {
|
|
2188
|
+
headers: {
|
|
2189
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2190
|
+
[name: string]: unknown;
|
|
2191
|
+
};
|
|
2192
|
+
content: {
|
|
2193
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
2194
|
+
/** @enum {unknown} */
|
|
2195
|
+
code?: "not_a_person_session" | "passkey_proof_needed";
|
|
2196
|
+
};
|
|
2197
|
+
};
|
|
2198
|
+
};
|
|
2199
|
+
413: components["responses"]["ContentTooLarge"];
|
|
2200
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
2201
|
+
500: components["responses"]["ServerError"];
|
|
2202
|
+
503: components["responses"]["ServiceUnavailable"];
|
|
2203
|
+
};
|
|
2204
|
+
};
|
|
2205
|
+
completePasskeyRegistration: {
|
|
2206
|
+
parameters: {
|
|
2207
|
+
query?: never;
|
|
2208
|
+
header?: never;
|
|
2209
|
+
path: {
|
|
2210
|
+
passkey_registration_id: components["parameters"]["PasskeyRegistrationId"];
|
|
2211
|
+
};
|
|
2212
|
+
cookie?: never;
|
|
2213
|
+
};
|
|
2214
|
+
requestBody: {
|
|
2215
|
+
content: {
|
|
2216
|
+
"application/json": components["schemas"]["PasskeyRegistrationCompletion"];
|
|
2217
|
+
};
|
|
2218
|
+
};
|
|
2219
|
+
responses: {
|
|
2220
|
+
/** @description Kept. The new sign-in method, as Account lists it. */
|
|
2221
|
+
201: {
|
|
2222
|
+
headers: {
|
|
2223
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2224
|
+
[name: string]: unknown;
|
|
2225
|
+
};
|
|
2226
|
+
content: {
|
|
2227
|
+
"application/json": components["schemas"]["AddedSignInMethod"];
|
|
2228
|
+
};
|
|
2229
|
+
};
|
|
2230
|
+
400: components["responses"]["BadRequest"];
|
|
2231
|
+
401: components["responses"]["Unauthorized"];
|
|
2232
|
+
403: components["responses"]["Forbidden"];
|
|
2233
|
+
404: components["responses"]["NotFound"];
|
|
2234
|
+
/**
|
|
2235
|
+
* @description Refused, and nothing is kept. `passkey_not_verified`: the new key did not prove what it
|
|
2236
|
+
* must, and which check failed is never said. `already_registered`: this person already
|
|
2237
|
+
* holds this key.
|
|
2238
|
+
*/
|
|
2239
|
+
409: {
|
|
2240
|
+
headers: {
|
|
2241
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2242
|
+
[name: string]: unknown;
|
|
2243
|
+
};
|
|
2244
|
+
content: {
|
|
2245
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
2246
|
+
/** @enum {unknown} */
|
|
2247
|
+
code?: "passkey_not_verified" | "already_registered";
|
|
2248
|
+
};
|
|
2249
|
+
};
|
|
2250
|
+
};
|
|
2251
|
+
413: components["responses"]["ContentTooLarge"];
|
|
2252
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
2253
|
+
422: components["responses"]["Unprocessable"];
|
|
2254
|
+
500: components["responses"]["ServerError"];
|
|
2255
|
+
503: components["responses"]["ServiceUnavailable"];
|
|
2256
|
+
};
|
|
2257
|
+
};
|
|
2258
|
+
checkUsername: {
|
|
2259
|
+
parameters: {
|
|
2260
|
+
query?: never;
|
|
2261
|
+
header?: never;
|
|
2262
|
+
path?: never;
|
|
2263
|
+
cookie?: never;
|
|
2264
|
+
};
|
|
2265
|
+
requestBody: {
|
|
2266
|
+
content: {
|
|
2267
|
+
"application/json": components["schemas"]["UsernameCheck"];
|
|
2268
|
+
};
|
|
2269
|
+
};
|
|
2270
|
+
responses: {
|
|
2271
|
+
/** @description Whether the name may be chosen now. */
|
|
2272
|
+
200: {
|
|
2273
|
+
headers: {
|
|
2274
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2275
|
+
[name: string]: unknown;
|
|
2276
|
+
};
|
|
2277
|
+
content: {
|
|
2278
|
+
"application/json": components["schemas"]["UsernameAvailability"];
|
|
2279
|
+
};
|
|
2280
|
+
};
|
|
2281
|
+
400: components["responses"]["BadRequest"];
|
|
2282
|
+
413: components["responses"]["ContentTooLarge"];
|
|
2283
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
2284
|
+
422: components["responses"]["Unprocessable"];
|
|
2285
|
+
429: components["responses"]["TooManyCalls"];
|
|
2286
|
+
500: components["responses"]["ServerError"];
|
|
2287
|
+
503: components["responses"]["ServiceUnavailable"];
|
|
2288
|
+
};
|
|
2289
|
+
};
|
|
2290
|
+
startSignUp: {
|
|
2291
|
+
parameters: {
|
|
2292
|
+
query?: never;
|
|
2293
|
+
header?: never;
|
|
2294
|
+
path?: never;
|
|
2295
|
+
cookie?: never;
|
|
2296
|
+
};
|
|
2297
|
+
requestBody: {
|
|
2298
|
+
content: {
|
|
2299
|
+
"application/json": components["schemas"]["SignUpStart"];
|
|
2300
|
+
};
|
|
2301
|
+
};
|
|
2302
|
+
responses: {
|
|
2303
|
+
/** @description The sign-up, and the question to put to the first passkey. */
|
|
2304
|
+
201: {
|
|
2305
|
+
headers: {
|
|
2306
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2307
|
+
[name: string]: unknown;
|
|
2308
|
+
};
|
|
2309
|
+
content: {
|
|
2310
|
+
"application/json": components["schemas"]["SignUp"];
|
|
2311
|
+
};
|
|
2312
|
+
};
|
|
2313
|
+
400: components["responses"]["BadRequest"];
|
|
2314
|
+
/**
|
|
2315
|
+
* @description Refused. `username_not_available`: somebody holds the name, gave it up recently, or it is
|
|
2316
|
+
* reserved — never which.
|
|
2317
|
+
*/
|
|
2318
|
+
409: {
|
|
2319
|
+
headers: {
|
|
2320
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2321
|
+
[name: string]: unknown;
|
|
2322
|
+
};
|
|
2323
|
+
content: {
|
|
2324
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
2325
|
+
/** @enum {unknown} */
|
|
2326
|
+
code?: "username_not_available";
|
|
2327
|
+
};
|
|
2328
|
+
};
|
|
2329
|
+
};
|
|
2330
|
+
413: components["responses"]["ContentTooLarge"];
|
|
2331
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
2332
|
+
422: components["responses"]["Unprocessable"];
|
|
2333
|
+
429: components["responses"]["TooManyCalls"];
|
|
2334
|
+
500: components["responses"]["ServerError"];
|
|
2335
|
+
503: components["responses"]["ServiceUnavailable"];
|
|
2336
|
+
};
|
|
2337
|
+
};
|
|
2338
|
+
completeSignUp: {
|
|
2339
|
+
parameters: {
|
|
2340
|
+
query?: never;
|
|
2341
|
+
header?: never;
|
|
2342
|
+
path: {
|
|
2343
|
+
sign_up_id: components["parameters"]["SignUpId"];
|
|
2344
|
+
};
|
|
2345
|
+
cookie?: never;
|
|
2346
|
+
};
|
|
2347
|
+
requestBody: {
|
|
2348
|
+
content: {
|
|
2349
|
+
"application/json": components["schemas"]["SignUpCompletion"];
|
|
2350
|
+
};
|
|
2351
|
+
};
|
|
2352
|
+
responses: {
|
|
2353
|
+
/** @description Signed up. The recovery codes, shown this once, and the first session. Sent with `no-store`. */
|
|
2354
|
+
201: {
|
|
2355
|
+
headers: {
|
|
2356
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2357
|
+
"Cache-Control": components["headers"]["CacheControl"];
|
|
2358
|
+
[name: string]: unknown;
|
|
2359
|
+
};
|
|
2360
|
+
content: {
|
|
2361
|
+
"application/json": components["schemas"]["SignedUp"];
|
|
2362
|
+
};
|
|
2363
|
+
};
|
|
2364
|
+
400: components["responses"]["BadRequest"];
|
|
2365
|
+
404: components["responses"]["NotFound"];
|
|
2366
|
+
/**
|
|
2367
|
+
* @description Refused, and the sign-up is spent. `passkey_not_verified`: the answer did not prove a new
|
|
2368
|
+
* key Onplo will keep, and which check failed is never said. `username_not_available`:
|
|
2369
|
+
* somebody took the name since the sign-up started.
|
|
2370
|
+
*/
|
|
2371
|
+
409: {
|
|
2372
|
+
headers: {
|
|
2373
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2374
|
+
[name: string]: unknown;
|
|
2375
|
+
};
|
|
2376
|
+
content: {
|
|
2377
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
2378
|
+
/** @enum {unknown} */
|
|
2379
|
+
code?: "passkey_not_verified" | "username_not_available";
|
|
2380
|
+
};
|
|
2381
|
+
};
|
|
2382
|
+
};
|
|
2383
|
+
413: components["responses"]["ContentTooLarge"];
|
|
2384
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
2385
|
+
422: components["responses"]["Unprocessable"];
|
|
2386
|
+
429: components["responses"]["TooManyCalls"];
|
|
2387
|
+
500: components["responses"]["ServerError"];
|
|
2388
|
+
503: components["responses"]["ServiceUnavailable"];
|
|
2389
|
+
};
|
|
2390
|
+
};
|
|
2391
|
+
startRecovery: {
|
|
2392
|
+
parameters: {
|
|
2393
|
+
query?: never;
|
|
2394
|
+
header?: never;
|
|
2395
|
+
path?: never;
|
|
2396
|
+
cookie?: never;
|
|
2397
|
+
};
|
|
2398
|
+
requestBody: {
|
|
2399
|
+
content: {
|
|
2400
|
+
"application/json": components["schemas"]["RecoveryStart"];
|
|
2401
|
+
};
|
|
2402
|
+
};
|
|
2403
|
+
responses: {
|
|
2404
|
+
/** @description The recovery, and the question to put to the new passkey. */
|
|
2405
|
+
201: {
|
|
2406
|
+
headers: {
|
|
2407
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2408
|
+
[name: string]: unknown;
|
|
2409
|
+
};
|
|
2410
|
+
content: {
|
|
2411
|
+
"application/json": components["schemas"]["Recovery"];
|
|
2412
|
+
};
|
|
2413
|
+
};
|
|
2414
|
+
400: components["responses"]["BadRequest"];
|
|
2415
|
+
/**
|
|
2416
|
+
* @description Refused. `recovery_not_verified`: the username and code did not prove a person, and why is
|
|
2417
|
+
* never said.
|
|
2418
|
+
*/
|
|
2419
|
+
409: {
|
|
2420
|
+
headers: {
|
|
2421
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2422
|
+
[name: string]: unknown;
|
|
2423
|
+
};
|
|
2424
|
+
content: {
|
|
2425
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
2426
|
+
/** @enum {unknown} */
|
|
2427
|
+
code?: "recovery_not_verified";
|
|
2428
|
+
};
|
|
2429
|
+
};
|
|
2430
|
+
};
|
|
2431
|
+
413: components["responses"]["ContentTooLarge"];
|
|
2432
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
2433
|
+
422: components["responses"]["Unprocessable"];
|
|
2434
|
+
429: components["responses"]["TooManyCalls"];
|
|
2435
|
+
500: components["responses"]["ServerError"];
|
|
2436
|
+
501: components["responses"]["NotImplemented"];
|
|
2437
|
+
};
|
|
2438
|
+
};
|
|
2439
|
+
completeRecovery: {
|
|
2440
|
+
parameters: {
|
|
2441
|
+
query?: never;
|
|
2442
|
+
header?: never;
|
|
2443
|
+
path: {
|
|
2444
|
+
recovery_id: components["parameters"]["RecoveryId"];
|
|
2445
|
+
};
|
|
2446
|
+
cookie?: never;
|
|
2447
|
+
};
|
|
2448
|
+
requestBody: {
|
|
2449
|
+
content: {
|
|
2450
|
+
"application/json": components["schemas"]["RecoveryCompletion"];
|
|
2451
|
+
};
|
|
2452
|
+
};
|
|
2453
|
+
responses: {
|
|
2454
|
+
/** @description Back in. Where the person may go, and the token that opens one session. Sent with `no-store`. */
|
|
2455
|
+
200: {
|
|
2456
|
+
headers: {
|
|
2457
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2458
|
+
"Cache-Control": components["headers"]["CacheControl"];
|
|
2459
|
+
[name: string]: unknown;
|
|
2460
|
+
};
|
|
2461
|
+
content: {
|
|
2462
|
+
"application/json": components["schemas"]["SignInChoices"];
|
|
2463
|
+
};
|
|
2464
|
+
};
|
|
2465
|
+
400: components["responses"]["BadRequest"];
|
|
2466
|
+
404: components["responses"]["NotFound"];
|
|
2467
|
+
/**
|
|
2468
|
+
* @description Refused, and the recovery is spent. `passkey_not_verified`: the answer did not prove a new
|
|
2469
|
+
* key Onplo will keep. `already_registered`: that key is kept already.
|
|
2470
|
+
*/
|
|
2471
|
+
409: {
|
|
2472
|
+
headers: {
|
|
2473
|
+
"Onplo-Request-Id": components["headers"]["OnploRequestId"];
|
|
2474
|
+
[name: string]: unknown;
|
|
2475
|
+
};
|
|
2476
|
+
content: {
|
|
2477
|
+
"application/problem+json": components["schemas"]["Problem"] & {
|
|
2478
|
+
/** @enum {unknown} */
|
|
2479
|
+
code?: "passkey_not_verified" | "already_registered";
|
|
2480
|
+
};
|
|
2481
|
+
};
|
|
2482
|
+
};
|
|
2483
|
+
413: components["responses"]["ContentTooLarge"];
|
|
2484
|
+
415: components["responses"]["UnsupportedMediaType"];
|
|
2485
|
+
422: components["responses"]["Unprocessable"];
|
|
2486
|
+
429: components["responses"]["TooManyCalls"];
|
|
2487
|
+
500: components["responses"]["ServerError"];
|
|
2488
|
+
501: components["responses"]["NotImplemented"];
|
|
2489
|
+
503: components["responses"]["ServiceUnavailable"];
|
|
2490
|
+
};
|
|
2491
|
+
};
|
|
2492
|
+
}
|