@technomoron/api-server-base 2.0.0-beta.2 → 2.0.0-beta.21

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.
Files changed (115) hide show
  1. package/README.txt +81 -28
  2. package/dist/cjs/api-module.cjs +9 -0
  3. package/dist/cjs/api-module.d.ts +7 -4
  4. package/dist/cjs/api-server-base.cjs +607 -99
  5. package/dist/cjs/api-server-base.d.ts +80 -23
  6. package/dist/cjs/auth-api/auth-module.d.ts +23 -3
  7. package/dist/cjs/auth-api/auth-module.js +320 -124
  8. package/dist/cjs/auth-api/compat-auth-storage.d.ts +7 -5
  9. package/dist/cjs/auth-api/compat-auth-storage.js +15 -3
  10. package/dist/cjs/auth-api/mem-auth-store.d.ts +5 -3
  11. package/dist/cjs/auth-api/mem-auth-store.js +14 -28
  12. package/dist/cjs/auth-api/module.d.ts +1 -1
  13. package/dist/cjs/auth-api/sql-auth-store.d.ts +16 -4
  14. package/dist/cjs/auth-api/sql-auth-store.js +43 -30
  15. package/dist/cjs/auth-api/storage.d.ts +6 -4
  16. package/dist/cjs/auth-api/storage.js +15 -5
  17. package/dist/cjs/auth-api/types.d.ts +7 -2
  18. package/dist/cjs/auth-api/user-id.d.ts +5 -0
  19. package/dist/cjs/auth-api/user-id.js +38 -0
  20. package/dist/cjs/auth-cookie-options.d.ts +11 -0
  21. package/dist/cjs/auth-cookie-options.js +66 -0
  22. package/dist/cjs/index.cjs +4 -14
  23. package/dist/cjs/index.d.ts +4 -9
  24. package/dist/cjs/oauth/memory.d.ts +6 -0
  25. package/dist/cjs/oauth/memory.js +44 -11
  26. package/dist/cjs/oauth/models.d.ts +7 -2
  27. package/dist/cjs/oauth/models.js +10 -21
  28. package/dist/cjs/oauth/sequelize.d.ts +10 -48
  29. package/dist/cjs/oauth/sequelize.js +44 -99
  30. package/dist/cjs/oauth/types.d.ts +1 -0
  31. package/dist/cjs/passkey/base.d.ts +2 -0
  32. package/dist/cjs/passkey/config.d.ts +2 -0
  33. package/dist/cjs/passkey/config.js +26 -0
  34. package/dist/cjs/passkey/memory.d.ts +8 -0
  35. package/dist/cjs/passkey/memory.js +57 -16
  36. package/dist/cjs/passkey/models.d.ts +13 -4
  37. package/dist/cjs/passkey/models.js +41 -14
  38. package/dist/cjs/passkey/sequelize.d.ts +13 -25
  39. package/dist/cjs/passkey/sequelize.js +68 -153
  40. package/dist/cjs/passkey/service.d.ts +6 -2
  41. package/dist/cjs/passkey/service.js +205 -27
  42. package/dist/cjs/passkey/types.d.ts +18 -9
  43. package/dist/cjs/sequelize-utils.d.ts +8 -0
  44. package/dist/cjs/sequelize-utils.js +57 -0
  45. package/dist/cjs/token/base.d.ts +2 -1
  46. package/dist/cjs/token/base.js +3 -1
  47. package/dist/cjs/token/memory.d.ts +10 -0
  48. package/dist/cjs/token/memory.js +122 -32
  49. package/dist/cjs/token/sequelize.d.ts +4 -4
  50. package/dist/cjs/token/sequelize.js +67 -85
  51. package/dist/cjs/token/types.d.ts +8 -1
  52. package/dist/cjs/user/base.d.ts +1 -0
  53. package/dist/cjs/user/base.js +11 -4
  54. package/dist/cjs/user/memory.d.ts +2 -0
  55. package/dist/cjs/user/memory.js +9 -10
  56. package/dist/cjs/user/sequelize.d.ts +7 -2
  57. package/dist/cjs/user/sequelize.js +19 -32
  58. package/dist/esm/api-module.d.ts +7 -4
  59. package/dist/esm/api-module.js +9 -0
  60. package/dist/esm/api-server-base.d.ts +80 -23
  61. package/dist/esm/api-server-base.js +608 -100
  62. package/dist/esm/auth-api/auth-module.d.ts +23 -3
  63. package/dist/esm/auth-api/auth-module.js +321 -125
  64. package/dist/esm/auth-api/compat-auth-storage.d.ts +7 -5
  65. package/dist/esm/auth-api/compat-auth-storage.js +13 -1
  66. package/dist/esm/auth-api/mem-auth-store.d.ts +5 -3
  67. package/dist/esm/auth-api/mem-auth-store.js +14 -28
  68. package/dist/esm/auth-api/module.d.ts +1 -1
  69. package/dist/esm/auth-api/sql-auth-store.d.ts +16 -4
  70. package/dist/esm/auth-api/sql-auth-store.js +43 -30
  71. package/dist/esm/auth-api/storage.d.ts +6 -4
  72. package/dist/esm/auth-api/storage.js +13 -3
  73. package/dist/esm/auth-api/types.d.ts +7 -2
  74. package/dist/esm/auth-api/user-id.d.ts +5 -0
  75. package/dist/esm/auth-api/user-id.js +32 -0
  76. package/dist/esm/auth-cookie-options.d.ts +11 -0
  77. package/dist/esm/auth-cookie-options.js +63 -0
  78. package/dist/esm/index.d.ts +4 -9
  79. package/dist/esm/index.js +2 -7
  80. package/dist/esm/oauth/memory.d.ts +6 -0
  81. package/dist/esm/oauth/memory.js +44 -11
  82. package/dist/esm/oauth/models.d.ts +7 -2
  83. package/dist/esm/oauth/models.js +6 -19
  84. package/dist/esm/oauth/sequelize.d.ts +10 -48
  85. package/dist/esm/oauth/sequelize.js +32 -87
  86. package/dist/esm/oauth/types.d.ts +1 -0
  87. package/dist/esm/passkey/base.d.ts +2 -0
  88. package/dist/esm/passkey/config.d.ts +2 -0
  89. package/dist/esm/passkey/config.js +23 -0
  90. package/dist/esm/passkey/memory.d.ts +8 -0
  91. package/dist/esm/passkey/memory.js +57 -16
  92. package/dist/esm/passkey/models.d.ts +13 -4
  93. package/dist/esm/passkey/models.js +39 -12
  94. package/dist/esm/passkey/sequelize.d.ts +13 -25
  95. package/dist/esm/passkey/sequelize.js +69 -154
  96. package/dist/esm/passkey/service.d.ts +6 -2
  97. package/dist/esm/passkey/service.js +173 -28
  98. package/dist/esm/passkey/types.d.ts +18 -9
  99. package/dist/esm/sequelize-utils.d.ts +8 -0
  100. package/dist/esm/sequelize-utils.js +48 -0
  101. package/dist/esm/token/base.d.ts +2 -1
  102. package/dist/esm/token/base.js +3 -1
  103. package/dist/esm/token/memory.d.ts +10 -0
  104. package/dist/esm/token/memory.js +122 -32
  105. package/dist/esm/token/sequelize.d.ts +4 -4
  106. package/dist/esm/token/sequelize.js +67 -85
  107. package/dist/esm/token/types.d.ts +8 -1
  108. package/dist/esm/user/base.d.ts +1 -0
  109. package/dist/esm/user/base.js +11 -4
  110. package/dist/esm/user/memory.d.ts +2 -0
  111. package/dist/esm/user/memory.js +9 -10
  112. package/dist/esm/user/sequelize.d.ts +7 -2
  113. package/dist/esm/user/sequelize.js +19 -32
  114. package/docs/swagger/openapi.json +1876 -0
  115. package/package.json +84 -34
@@ -0,0 +1,1876 @@
1
+ {
2
+ "openapi": "3.1.0",
3
+ "info": {
4
+ "title": "API Server Base",
5
+ "version": "2.0.0-beta.19",
6
+ "description": "OpenAPI reference for ApiServer base endpoints and optional modules. Auth, passkey, and oauth modules are optional and require the corresponding module to be enabled in the ApiServer config. Base endpoints are always available."
7
+ },
8
+ "servers": [
9
+ {
10
+ "url": "http://localhost:3101",
11
+ "description": "Default local development server"
12
+ }
13
+ ],
14
+ "tags": [
15
+ {
16
+ "name": "base",
17
+ "description": "Base endpoints always available in ApiServer."
18
+ },
19
+ {
20
+ "name": "auth",
21
+ "description": "Optional auth module endpoints. Requires the auth module to be enabled in the ApiServer config."
22
+ },
23
+ {
24
+ "name": "passkey",
25
+ "description": "Optional passkey module endpoints. Requires passkey support to be enabled in the ApiServer auth config."
26
+ },
27
+ {
28
+ "name": "oauth",
29
+ "description": "Optional OAuth module endpoints. Requires OAuth support to be enabled in the ApiServer auth config."
30
+ }
31
+ ],
32
+ "paths": {
33
+ "/api/v1/ping": {
34
+ "get": {
35
+ "tags": ["base"],
36
+ "summary": "Health check",
37
+ "description": "Auth: none. Returns ApiResponse<PingResponseData> with server health and version metadata.",
38
+ "security": [],
39
+ "responses": {
40
+ "200": {
41
+ "description": "Server is reachable.",
42
+ "content": {
43
+ "application/json": {
44
+ "schema": {
45
+ "allOf": [
46
+ { "$ref": "#/components/schemas/ApiResponse" },
47
+ {
48
+ "type": "object",
49
+ "properties": {
50
+ "data": { "$ref": "#/components/schemas/PingResponseData" }
51
+ },
52
+ "required": ["data"]
53
+ }
54
+ ]
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ },
62
+ "/api/auth/v1/login": {
63
+ "post": {
64
+ "tags": ["auth"],
65
+ "summary": "Login with credentials",
66
+ "description": "Auth: none. Issues access and refresh tokens for valid credentials.",
67
+ "security": [],
68
+ "requestBody": {
69
+ "required": true,
70
+ "content": {
71
+ "application/json": {
72
+ "schema": { "$ref": "#/components/schemas/LoginRequest" }
73
+ }
74
+ }
75
+ },
76
+ "responses": {
77
+ "200": {
78
+ "description": "Login succeeded.",
79
+ "content": {
80
+ "application/json": {
81
+ "schema": {
82
+ "allOf": [
83
+ { "$ref": "#/components/schemas/ApiResponse" },
84
+ {
85
+ "type": "object",
86
+ "properties": {
87
+ "data": { "$ref": "#/components/schemas/AuthTokensResponseData" }
88
+ },
89
+ "required": ["data"]
90
+ }
91
+ ]
92
+ }
93
+ }
94
+ }
95
+ },
96
+ "400": {
97
+ "description": "Missing or invalid credentials.",
98
+ "content": {
99
+ "application/json": {
100
+ "schema": {
101
+ "allOf": [
102
+ { "$ref": "#/components/schemas/ApiResponse" },
103
+ {
104
+ "type": "object",
105
+ "properties": {
106
+ "data": { "type": "null" }
107
+ },
108
+ "required": ["data"]
109
+ }
110
+ ]
111
+ }
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }
117
+ },
118
+ "/api/auth/v1/refresh": {
119
+ "post": {
120
+ "tags": ["auth"],
121
+ "summary": "Refresh access and refresh tokens",
122
+ "description": "Auth: required. Reissues tokens using a refresh token supplied in the body or refresh cookie.",
123
+ "security": [{ "refreshTokenCookie": [] }],
124
+ "requestBody": {
125
+ "required": false,
126
+ "content": {
127
+ "application/json": {
128
+ "schema": { "$ref": "#/components/schemas/RefreshRequest" }
129
+ }
130
+ }
131
+ },
132
+ "responses": {
133
+ "200": {
134
+ "description": "Refresh succeeded.",
135
+ "content": {
136
+ "application/json": {
137
+ "schema": {
138
+ "allOf": [
139
+ { "$ref": "#/components/schemas/ApiResponse" },
140
+ {
141
+ "type": "object",
142
+ "properties": {
143
+ "data": { "$ref": "#/components/schemas/AuthTokensResponseData" }
144
+ },
145
+ "required": ["data"]
146
+ }
147
+ ]
148
+ }
149
+ }
150
+ }
151
+ },
152
+ "401": {
153
+ "description": "Missing or invalid refresh token.",
154
+ "content": {
155
+ "application/json": {
156
+ "schema": {
157
+ "allOf": [
158
+ { "$ref": "#/components/schemas/ApiResponse" },
159
+ {
160
+ "type": "object",
161
+ "properties": {
162
+ "data": { "type": "null" }
163
+ },
164
+ "required": ["data"]
165
+ }
166
+ ]
167
+ }
168
+ }
169
+ }
170
+ },
171
+ "403": {
172
+ "description": "Refresh token expired.",
173
+ "content": {
174
+ "application/json": {
175
+ "schema": {
176
+ "allOf": [
177
+ { "$ref": "#/components/schemas/ApiResponse" },
178
+ {
179
+ "type": "object",
180
+ "properties": {
181
+ "data": { "type": "null" }
182
+ },
183
+ "required": ["data"]
184
+ }
185
+ ]
186
+ }
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+ },
193
+ "/api/auth/v1/logout": {
194
+ "post": {
195
+ "tags": ["auth"],
196
+ "summary": "Logout and revoke the refresh token",
197
+ "description": "Auth: required. Revokes the refresh token supplied in the body or refresh cookie and clears auth cookies.",
198
+ "security": [{ "refreshTokenCookie": [] }],
199
+ "requestBody": {
200
+ "required": false,
201
+ "content": {
202
+ "application/json": {
203
+ "schema": { "$ref": "#/components/schemas/LogoutRequest" }
204
+ }
205
+ }
206
+ },
207
+ "responses": {
208
+ "200": {
209
+ "description": "Logout succeeded.",
210
+ "content": {
211
+ "application/json": {
212
+ "schema": {
213
+ "allOf": [
214
+ { "$ref": "#/components/schemas/ApiResponse" },
215
+ {
216
+ "type": "object",
217
+ "properties": {
218
+ "data": { "$ref": "#/components/schemas/LogoutResponseData" }
219
+ },
220
+ "required": ["data"]
221
+ }
222
+ ]
223
+ }
224
+ }
225
+ }
226
+ },
227
+ "401": {
228
+ "description": "Not logged in.",
229
+ "content": {
230
+ "application/json": {
231
+ "schema": {
232
+ "allOf": [
233
+ { "$ref": "#/components/schemas/ApiResponse" },
234
+ {
235
+ "type": "object",
236
+ "properties": {
237
+ "data": { "type": "null" }
238
+ },
239
+ "required": ["data"]
240
+ }
241
+ ]
242
+ }
243
+ }
244
+ }
245
+ }
246
+ }
247
+ }
248
+ },
249
+ "/api/auth/v1/whoami": {
250
+ "post": {
251
+ "tags": ["auth"],
252
+ "summary": "Resolve the current identity",
253
+ "description": "Auth: required. Resolves the effective user from the refresh token and optionally refreshes the access token.",
254
+ "security": [{ "refreshTokenCookie": [] }],
255
+ "requestBody": {
256
+ "required": false,
257
+ "content": {
258
+ "application/json": {
259
+ "schema": { "$ref": "#/components/schemas/WhoAmIRequest" }
260
+ }
261
+ }
262
+ },
263
+ "responses": {
264
+ "200": {
265
+ "description": "Identity resolved.",
266
+ "content": {
267
+ "application/json": {
268
+ "schema": {
269
+ "allOf": [
270
+ { "$ref": "#/components/schemas/ApiResponse" },
271
+ {
272
+ "type": "object",
273
+ "properties": {
274
+ "data": { "$ref": "#/components/schemas/WhoAmIResponseData" }
275
+ },
276
+ "required": ["data"]
277
+ }
278
+ ]
279
+ }
280
+ }
281
+ }
282
+ },
283
+ "401": {
284
+ "description": "Missing or invalid refresh token.",
285
+ "content": {
286
+ "application/json": {
287
+ "schema": {
288
+ "allOf": [
289
+ { "$ref": "#/components/schemas/ApiResponse" },
290
+ {
291
+ "type": "object",
292
+ "properties": {
293
+ "data": { "type": "null" }
294
+ },
295
+ "required": ["data"]
296
+ }
297
+ ]
298
+ }
299
+ }
300
+ }
301
+ },
302
+ "403": {
303
+ "description": "Refresh token expired or user not found.",
304
+ "content": {
305
+ "application/json": {
306
+ "schema": {
307
+ "allOf": [
308
+ { "$ref": "#/components/schemas/ApiResponse" },
309
+ {
310
+ "type": "object",
311
+ "properties": {
312
+ "data": { "type": "null" }
313
+ },
314
+ "required": ["data"]
315
+ }
316
+ ]
317
+ }
318
+ }
319
+ }
320
+ }
321
+ }
322
+ }
323
+ },
324
+ "/api/auth/v1/impersonations": {
325
+ "post": {
326
+ "tags": ["auth"],
327
+ "summary": "Start impersonating a user",
328
+ "description": "Auth: strict. Issues tokens for a target user when impersonation is permitted.",
329
+ "security": [{ "accessTokenBearer": [] }, { "accessTokenCookie": [] }, { "apiKeyBearer": [] }],
330
+ "requestBody": {
331
+ "required": true,
332
+ "content": {
333
+ "application/json": {
334
+ "schema": { "$ref": "#/components/schemas/ImpersonateRequest" }
335
+ }
336
+ }
337
+ },
338
+ "responses": {
339
+ "200": {
340
+ "description": "Impersonation tokens issued.",
341
+ "content": {
342
+ "application/json": {
343
+ "schema": {
344
+ "allOf": [
345
+ { "$ref": "#/components/schemas/ApiResponse" },
346
+ {
347
+ "type": "object",
348
+ "properties": {
349
+ "data": { "$ref": "#/components/schemas/AuthTokensResponseData" }
350
+ },
351
+ "required": ["data"]
352
+ }
353
+ ]
354
+ }
355
+ }
356
+ }
357
+ },
358
+ "400": {
359
+ "description": "Missing userId or login.",
360
+ "content": {
361
+ "application/json": {
362
+ "schema": {
363
+ "allOf": [
364
+ { "$ref": "#/components/schemas/ApiResponse" },
365
+ {
366
+ "type": "object",
367
+ "properties": {
368
+ "data": { "type": "null" }
369
+ },
370
+ "required": ["data"]
371
+ }
372
+ ]
373
+ }
374
+ }
375
+ }
376
+ },
377
+ "401": {
378
+ "description": "Authentication required.",
379
+ "content": {
380
+ "application/json": {
381
+ "schema": {
382
+ "allOf": [
383
+ { "$ref": "#/components/schemas/ApiResponse" },
384
+ {
385
+ "type": "object",
386
+ "properties": {
387
+ "data": { "type": "null" }
388
+ },
389
+ "required": ["data"]
390
+ }
391
+ ]
392
+ }
393
+ }
394
+ }
395
+ },
396
+ "403": {
397
+ "description": "Impersonation not permitted or user not found.",
398
+ "content": {
399
+ "application/json": {
400
+ "schema": {
401
+ "allOf": [
402
+ { "$ref": "#/components/schemas/ApiResponse" },
403
+ {
404
+ "type": "object",
405
+ "properties": {
406
+ "data": { "type": "null" }
407
+ },
408
+ "required": ["data"]
409
+ }
410
+ ]
411
+ }
412
+ }
413
+ }
414
+ }
415
+ }
416
+ },
417
+ "delete": {
418
+ "tags": ["auth"],
419
+ "summary": "Stop impersonating",
420
+ "description": "Auth: strict. Reissues tokens for the real user to end impersonation.",
421
+ "security": [{ "accessTokenBearer": [] }, { "accessTokenCookie": [] }, { "apiKeyBearer": [] }],
422
+ "requestBody": {
423
+ "required": false,
424
+ "content": {
425
+ "application/json": {
426
+ "schema": { "$ref": "#/components/schemas/ImpersonationEndRequest" }
427
+ }
428
+ }
429
+ },
430
+ "responses": {
431
+ "200": {
432
+ "description": "Impersonation ended; admin tokens returned.",
433
+ "content": {
434
+ "application/json": {
435
+ "schema": {
436
+ "allOf": [
437
+ { "$ref": "#/components/schemas/ApiResponse" },
438
+ {
439
+ "type": "object",
440
+ "properties": {
441
+ "data": { "$ref": "#/components/schemas/AuthTokensResponseData" }
442
+ },
443
+ "required": ["data"]
444
+ }
445
+ ]
446
+ }
447
+ }
448
+ }
449
+ },
450
+ "401": {
451
+ "description": "Authentication required.",
452
+ "content": {
453
+ "application/json": {
454
+ "schema": {
455
+ "allOf": [
456
+ { "$ref": "#/components/schemas/ApiResponse" },
457
+ {
458
+ "type": "object",
459
+ "properties": {
460
+ "data": { "type": "null" }
461
+ },
462
+ "required": ["data"]
463
+ }
464
+ ]
465
+ }
466
+ }
467
+ }
468
+ },
469
+ "403": {
470
+ "description": "Authenticated user not found.",
471
+ "content": {
472
+ "application/json": {
473
+ "schema": {
474
+ "allOf": [
475
+ { "$ref": "#/components/schemas/ApiResponse" },
476
+ {
477
+ "type": "object",
478
+ "properties": {
479
+ "data": { "type": "null" }
480
+ },
481
+ "required": ["data"]
482
+ }
483
+ ]
484
+ }
485
+ }
486
+ }
487
+ }
488
+ }
489
+ }
490
+ },
491
+ "/api/auth/v1/passkeys/challenge": {
492
+ "post": {
493
+ "tags": ["passkey"],
494
+ "summary": "Create a passkey challenge",
495
+ "description": "Auth: none. Creates a passkey challenge for register or authenticate flows.",
496
+ "security": [],
497
+ "requestBody": {
498
+ "required": true,
499
+ "content": {
500
+ "application/json": {
501
+ "schema": { "$ref": "#/components/schemas/PasskeyChallengeRequest" }
502
+ }
503
+ }
504
+ },
505
+ "responses": {
506
+ "200": {
507
+ "description": "Challenge created.",
508
+ "content": {
509
+ "application/json": {
510
+ "schema": {
511
+ "allOf": [
512
+ { "$ref": "#/components/schemas/ApiResponse" },
513
+ {
514
+ "type": "object",
515
+ "properties": {
516
+ "data": { "$ref": "#/components/schemas/PasskeyChallenge" }
517
+ },
518
+ "required": ["data"]
519
+ }
520
+ ]
521
+ }
522
+ }
523
+ }
524
+ },
525
+ "400": {
526
+ "description": "Malformed request.",
527
+ "content": {
528
+ "application/json": {
529
+ "schema": {
530
+ "allOf": [
531
+ { "$ref": "#/components/schemas/ApiResponse" },
532
+ {
533
+ "type": "object",
534
+ "properties": {
535
+ "data": { "type": "null" }
536
+ },
537
+ "required": ["data"]
538
+ }
539
+ ]
540
+ }
541
+ }
542
+ }
543
+ },
544
+ "501": {
545
+ "description": "Passkey support not configured.",
546
+ "content": {
547
+ "application/json": {
548
+ "schema": {
549
+ "allOf": [
550
+ { "$ref": "#/components/schemas/ApiResponse" },
551
+ {
552
+ "type": "object",
553
+ "properties": {
554
+ "data": { "type": "null" }
555
+ },
556
+ "required": ["data"]
557
+ }
558
+ ]
559
+ }
560
+ }
561
+ }
562
+ }
563
+ }
564
+ }
565
+ },
566
+ "/api/auth/v1/passkeys/verify": {
567
+ "post": {
568
+ "tags": ["passkey"],
569
+ "summary": "Verify a passkey response",
570
+ "description": "Auth: none. Verifies a passkey response and issues tokens on success.",
571
+ "security": [],
572
+ "requestBody": {
573
+ "required": true,
574
+ "content": {
575
+ "application/json": {
576
+ "schema": { "$ref": "#/components/schemas/PasskeyVerifyRequest" }
577
+ }
578
+ }
579
+ },
580
+ "responses": {
581
+ "200": {
582
+ "description": "Passkey verified; tokens issued.",
583
+ "content": {
584
+ "application/json": {
585
+ "schema": {
586
+ "allOf": [
587
+ { "$ref": "#/components/schemas/ApiResponse" },
588
+ {
589
+ "type": "object",
590
+ "properties": {
591
+ "data": { "$ref": "#/components/schemas/AuthTokensResponseData" }
592
+ },
593
+ "required": ["data"]
594
+ }
595
+ ]
596
+ }
597
+ }
598
+ }
599
+ },
600
+ "400": {
601
+ "description": "Malformed request.",
602
+ "content": {
603
+ "application/json": {
604
+ "schema": {
605
+ "allOf": [
606
+ { "$ref": "#/components/schemas/ApiResponse" },
607
+ {
608
+ "type": "object",
609
+ "properties": {
610
+ "data": { "type": "null" }
611
+ },
612
+ "required": ["data"]
613
+ }
614
+ ]
615
+ }
616
+ }
617
+ }
618
+ },
619
+ "401": {
620
+ "description": "Passkey verification failed.",
621
+ "content": {
622
+ "application/json": {
623
+ "schema": {
624
+ "allOf": [
625
+ { "$ref": "#/components/schemas/ApiResponse" },
626
+ {
627
+ "type": "object",
628
+ "properties": {
629
+ "data": { "type": "null" }
630
+ },
631
+ "required": ["data"]
632
+ }
633
+ ]
634
+ }
635
+ }
636
+ }
637
+ },
638
+ "403": {
639
+ "description": "User not found for passkey verification.",
640
+ "content": {
641
+ "application/json": {
642
+ "schema": {
643
+ "allOf": [
644
+ { "$ref": "#/components/schemas/ApiResponse" },
645
+ {
646
+ "type": "object",
647
+ "properties": {
648
+ "data": { "type": "null" }
649
+ },
650
+ "required": ["data"]
651
+ }
652
+ ]
653
+ }
654
+ }
655
+ }
656
+ },
657
+ "501": {
658
+ "description": "Passkey support not configured.",
659
+ "content": {
660
+ "application/json": {
661
+ "schema": {
662
+ "allOf": [
663
+ { "$ref": "#/components/schemas/ApiResponse" },
664
+ {
665
+ "type": "object",
666
+ "properties": {
667
+ "data": { "type": "null" }
668
+ },
669
+ "required": ["data"]
670
+ }
671
+ ]
672
+ }
673
+ }
674
+ }
675
+ }
676
+ }
677
+ }
678
+ },
679
+ "/api/auth/v1/passkeys": {
680
+ "get": {
681
+ "tags": ["passkey"],
682
+ "summary": "List passkey credentials",
683
+ "description": "Auth: strict. Returns passkey credentials for the authenticated user.",
684
+ "security": [{ "accessTokenBearer": [] }, { "accessTokenCookie": [] }, { "apiKeyBearer": [] }],
685
+ "responses": {
686
+ "200": {
687
+ "description": "Credentials for the current user.",
688
+ "content": {
689
+ "application/json": {
690
+ "schema": {
691
+ "allOf": [
692
+ { "$ref": "#/components/schemas/ApiResponse" },
693
+ {
694
+ "type": "object",
695
+ "properties": {
696
+ "data": { "$ref": "#/components/schemas/PasskeyListResponseData" }
697
+ },
698
+ "required": ["data"]
699
+ }
700
+ ]
701
+ }
702
+ }
703
+ }
704
+ },
705
+ "401": {
706
+ "description": "Authentication required.",
707
+ "content": {
708
+ "application/json": {
709
+ "schema": {
710
+ "allOf": [
711
+ { "$ref": "#/components/schemas/ApiResponse" },
712
+ {
713
+ "type": "object",
714
+ "properties": {
715
+ "data": { "type": "null" }
716
+ },
717
+ "required": ["data"]
718
+ }
719
+ ]
720
+ }
721
+ }
722
+ }
723
+ },
724
+ "403": {
725
+ "description": "Authenticated user not found.",
726
+ "content": {
727
+ "application/json": {
728
+ "schema": {
729
+ "allOf": [
730
+ { "$ref": "#/components/schemas/ApiResponse" },
731
+ {
732
+ "type": "object",
733
+ "properties": {
734
+ "data": { "type": "null" }
735
+ },
736
+ "required": ["data"]
737
+ }
738
+ ]
739
+ }
740
+ }
741
+ }
742
+ },
743
+ "501": {
744
+ "description": "Passkey management not configured.",
745
+ "content": {
746
+ "application/json": {
747
+ "schema": {
748
+ "allOf": [
749
+ { "$ref": "#/components/schemas/ApiResponse" },
750
+ {
751
+ "type": "object",
752
+ "properties": {
753
+ "data": { "type": "null" }
754
+ },
755
+ "required": ["data"]
756
+ }
757
+ ]
758
+ }
759
+ }
760
+ }
761
+ }
762
+ }
763
+ }
764
+ },
765
+ "/api/auth/v1/passkeys/{credentialId}": {
766
+ "delete": {
767
+ "tags": ["passkey"],
768
+ "summary": "Delete a passkey credential",
769
+ "description": "Auth: strict. Deletes the passkey credential identified by the path parameter.",
770
+ "security": [{ "accessTokenBearer": [] }, { "accessTokenCookie": [] }, { "apiKeyBearer": [] }],
771
+ "parameters": [
772
+ {
773
+ "name": "credentialId",
774
+ "in": "path",
775
+ "required": true,
776
+ "description": "Credential id (base64url).",
777
+ "schema": { "type": "string" }
778
+ }
779
+ ],
780
+ "responses": {
781
+ "200": {
782
+ "description": "Credential deleted.",
783
+ "content": {
784
+ "application/json": {
785
+ "schema": {
786
+ "allOf": [
787
+ { "$ref": "#/components/schemas/ApiResponse" },
788
+ {
789
+ "type": "object",
790
+ "properties": {
791
+ "data": { "$ref": "#/components/schemas/PasskeyDeleteResponseData" }
792
+ },
793
+ "required": ["data"]
794
+ }
795
+ ]
796
+ }
797
+ }
798
+ }
799
+ },
800
+ "400": {
801
+ "description": "Missing or invalid credentialId.",
802
+ "content": {
803
+ "application/json": {
804
+ "schema": {
805
+ "allOf": [
806
+ { "$ref": "#/components/schemas/ApiResponse" },
807
+ {
808
+ "type": "object",
809
+ "properties": {
810
+ "data": { "type": "null" }
811
+ },
812
+ "required": ["data"]
813
+ }
814
+ ]
815
+ }
816
+ }
817
+ }
818
+ },
819
+ "401": {
820
+ "description": "Authentication required.",
821
+ "content": {
822
+ "application/json": {
823
+ "schema": {
824
+ "allOf": [
825
+ { "$ref": "#/components/schemas/ApiResponse" },
826
+ {
827
+ "type": "object",
828
+ "properties": {
829
+ "data": { "type": "null" }
830
+ },
831
+ "required": ["data"]
832
+ }
833
+ ]
834
+ }
835
+ }
836
+ }
837
+ },
838
+ "403": {
839
+ "description": "Authenticated user not found.",
840
+ "content": {
841
+ "application/json": {
842
+ "schema": {
843
+ "allOf": [
844
+ { "$ref": "#/components/schemas/ApiResponse" },
845
+ {
846
+ "type": "object",
847
+ "properties": {
848
+ "data": { "type": "null" }
849
+ },
850
+ "required": ["data"]
851
+ }
852
+ ]
853
+ }
854
+ }
855
+ }
856
+ },
857
+ "404": {
858
+ "description": "Passkey not found.",
859
+ "content": {
860
+ "application/json": {
861
+ "schema": {
862
+ "allOf": [
863
+ { "$ref": "#/components/schemas/ApiResponse" },
864
+ {
865
+ "type": "object",
866
+ "properties": {
867
+ "data": { "type": "null" }
868
+ },
869
+ "required": ["data"]
870
+ }
871
+ ]
872
+ }
873
+ }
874
+ }
875
+ },
876
+ "501": {
877
+ "description": "Passkey management not configured.",
878
+ "content": {
879
+ "application/json": {
880
+ "schema": {
881
+ "allOf": [
882
+ { "$ref": "#/components/schemas/ApiResponse" },
883
+ {
884
+ "type": "object",
885
+ "properties": {
886
+ "data": { "type": "null" }
887
+ },
888
+ "required": ["data"]
889
+ }
890
+ ]
891
+ }
892
+ }
893
+ }
894
+ }
895
+ }
896
+ }
897
+ },
898
+ "/api/auth/v1/oauth2/{provider}/start": {
899
+ "post": {
900
+ "tags": ["oauth"],
901
+ "summary": "Begin an external OAuth flow",
902
+ "description": "Auth: none. Starts an external OAuth flow for the provider.",
903
+ "security": [],
904
+ "parameters": [
905
+ {
906
+ "name": "provider",
907
+ "in": "path",
908
+ "required": true,
909
+ "description": "OAuth provider identifier.",
910
+ "schema": { "type": "string" }
911
+ }
912
+ ],
913
+ "requestBody": {
914
+ "required": false,
915
+ "content": {
916
+ "application/json": {
917
+ "schema": { "$ref": "#/components/schemas/OAuthStartRequest" }
918
+ }
919
+ }
920
+ },
921
+ "responses": {
922
+ "200": {
923
+ "description": "Start payload for the provider.",
924
+ "content": {
925
+ "application/json": {
926
+ "schema": {
927
+ "allOf": [
928
+ { "$ref": "#/components/schemas/ApiResponse" },
929
+ {
930
+ "type": "object",
931
+ "properties": {
932
+ "data": { "$ref": "#/components/schemas/OAuthStartResponse" }
933
+ },
934
+ "required": ["data"]
935
+ }
936
+ ]
937
+ }
938
+ }
939
+ }
940
+ },
941
+ "400": {
942
+ "description": "Missing provider.",
943
+ "content": {
944
+ "application/json": {
945
+ "schema": {
946
+ "allOf": [
947
+ { "$ref": "#/components/schemas/ApiResponse" },
948
+ {
949
+ "type": "object",
950
+ "properties": {
951
+ "data": { "type": "null" }
952
+ },
953
+ "required": ["data"]
954
+ }
955
+ ]
956
+ }
957
+ }
958
+ }
959
+ },
960
+ "501": {
961
+ "description": "OAuth support not configured.",
962
+ "content": {
963
+ "application/json": {
964
+ "schema": {
965
+ "allOf": [
966
+ { "$ref": "#/components/schemas/ApiResponse" },
967
+ {
968
+ "type": "object",
969
+ "properties": {
970
+ "data": { "type": "null" }
971
+ },
972
+ "required": ["data"]
973
+ }
974
+ ]
975
+ }
976
+ }
977
+ }
978
+ }
979
+ }
980
+ }
981
+ },
982
+ "/api/auth/v1/oauth2/{provider}/callback": {
983
+ "post": {
984
+ "tags": ["oauth"],
985
+ "summary": "Complete an external OAuth flow",
986
+ "description": "Auth: none. Completes the provider callback and returns the provider result.",
987
+ "security": [],
988
+ "parameters": [
989
+ {
990
+ "name": "provider",
991
+ "in": "path",
992
+ "required": true,
993
+ "description": "OAuth provider identifier.",
994
+ "schema": { "type": "string" }
995
+ }
996
+ ],
997
+ "requestBody": {
998
+ "required": false,
999
+ "content": {
1000
+ "application/json": {
1001
+ "schema": {
1002
+ "type": "object",
1003
+ "additionalProperties": true
1004
+ }
1005
+ }
1006
+ }
1007
+ },
1008
+ "responses": {
1009
+ "200": {
1010
+ "description": "Provider callback result.",
1011
+ "content": {
1012
+ "application/json": {
1013
+ "schema": {
1014
+ "allOf": [
1015
+ { "$ref": "#/components/schemas/ApiResponse" },
1016
+ {
1017
+ "type": "object",
1018
+ "properties": {
1019
+ "data": { "$ref": "#/components/schemas/OAuthCallbackResponse" }
1020
+ },
1021
+ "required": ["data"]
1022
+ }
1023
+ ]
1024
+ }
1025
+ }
1026
+ }
1027
+ },
1028
+ "400": {
1029
+ "description": "Missing provider.",
1030
+ "content": {
1031
+ "application/json": {
1032
+ "schema": {
1033
+ "allOf": [
1034
+ { "$ref": "#/components/schemas/ApiResponse" },
1035
+ {
1036
+ "type": "object",
1037
+ "properties": {
1038
+ "data": { "type": "null" }
1039
+ },
1040
+ "required": ["data"]
1041
+ }
1042
+ ]
1043
+ }
1044
+ }
1045
+ }
1046
+ },
1047
+ "501": {
1048
+ "description": "OAuth support not configured.",
1049
+ "content": {
1050
+ "application/json": {
1051
+ "schema": {
1052
+ "allOf": [
1053
+ { "$ref": "#/components/schemas/ApiResponse" },
1054
+ {
1055
+ "type": "object",
1056
+ "properties": {
1057
+ "data": { "type": "null" }
1058
+ },
1059
+ "required": ["data"]
1060
+ }
1061
+ ]
1062
+ }
1063
+ }
1064
+ }
1065
+ }
1066
+ }
1067
+ }
1068
+ },
1069
+ "/api/auth/v1/oauth2/authorize": {
1070
+ "post": {
1071
+ "tags": ["oauth"],
1072
+ "summary": "Issue an authorization code",
1073
+ "description": "Auth: required. Issues an authorization code for an authenticated user using a refresh token cookie or login credentials.",
1074
+ "security": [{ "refreshTokenCookie": [] }],
1075
+ "requestBody": {
1076
+ "required": true,
1077
+ "content": {
1078
+ "application/json": {
1079
+ "schema": { "$ref": "#/components/schemas/OAuthAuthorizeRequest" }
1080
+ }
1081
+ }
1082
+ },
1083
+ "responses": {
1084
+ "200": {
1085
+ "description": "Authorization code issued.",
1086
+ "content": {
1087
+ "application/json": {
1088
+ "schema": {
1089
+ "allOf": [
1090
+ { "$ref": "#/components/schemas/ApiResponse" },
1091
+ {
1092
+ "type": "object",
1093
+ "properties": {
1094
+ "data": { "$ref": "#/components/schemas/OAuthAuthorizeResponse" }
1095
+ },
1096
+ "required": ["data"]
1097
+ }
1098
+ ]
1099
+ }
1100
+ }
1101
+ }
1102
+ },
1103
+ "400": {
1104
+ "description": "Invalid request or client configuration.",
1105
+ "content": {
1106
+ "application/json": {
1107
+ "schema": {
1108
+ "allOf": [
1109
+ { "$ref": "#/components/schemas/ApiResponse" },
1110
+ {
1111
+ "type": "object",
1112
+ "properties": {
1113
+ "data": { "type": "null" }
1114
+ },
1115
+ "required": ["data"]
1116
+ }
1117
+ ]
1118
+ }
1119
+ }
1120
+ }
1121
+ },
1122
+ "401": {
1123
+ "description": "User authentication required.",
1124
+ "content": {
1125
+ "application/json": {
1126
+ "schema": {
1127
+ "allOf": [
1128
+ { "$ref": "#/components/schemas/ApiResponse" },
1129
+ {
1130
+ "type": "object",
1131
+ "properties": {
1132
+ "data": { "type": "null" }
1133
+ },
1134
+ "required": ["data"]
1135
+ }
1136
+ ]
1137
+ }
1138
+ }
1139
+ }
1140
+ },
1141
+ "501": {
1142
+ "description": "OAuth authorization storage not configured.",
1143
+ "content": {
1144
+ "application/json": {
1145
+ "schema": {
1146
+ "allOf": [
1147
+ { "$ref": "#/components/schemas/ApiResponse" },
1148
+ {
1149
+ "type": "object",
1150
+ "properties": {
1151
+ "data": { "type": "null" }
1152
+ },
1153
+ "required": ["data"]
1154
+ }
1155
+ ]
1156
+ }
1157
+ }
1158
+ }
1159
+ }
1160
+ }
1161
+ }
1162
+ },
1163
+ "/api/auth/v1/oauth2/token": {
1164
+ "post": {
1165
+ "tags": ["oauth"],
1166
+ "summary": "Exchange a code or refresh token",
1167
+ "description": "Auth: none. Exchanges an authorization code or refresh token for OAuth tokens; client authentication may be required.",
1168
+ "security": [],
1169
+ "requestBody": {
1170
+ "required": true,
1171
+ "content": {
1172
+ "application/json": {
1173
+ "schema": { "$ref": "#/components/schemas/OAuthTokenRequest" }
1174
+ },
1175
+ "application/x-www-form-urlencoded": {
1176
+ "schema": { "$ref": "#/components/schemas/OAuthTokenRequest" }
1177
+ }
1178
+ }
1179
+ },
1180
+ "responses": {
1181
+ "200": {
1182
+ "description": "Token response.",
1183
+ "content": {
1184
+ "application/json": {
1185
+ "schema": {
1186
+ "allOf": [
1187
+ { "$ref": "#/components/schemas/ApiResponse" },
1188
+ {
1189
+ "type": "object",
1190
+ "properties": {
1191
+ "data": { "$ref": "#/components/schemas/OAuthTokenResponse" }
1192
+ },
1193
+ "required": ["data"]
1194
+ }
1195
+ ]
1196
+ }
1197
+ }
1198
+ }
1199
+ },
1200
+ "400": {
1201
+ "description": "Invalid request.",
1202
+ "content": {
1203
+ "application/json": {
1204
+ "schema": {
1205
+ "allOf": [
1206
+ { "$ref": "#/components/schemas/ApiResponse" },
1207
+ {
1208
+ "type": "object",
1209
+ "properties": {
1210
+ "data": { "type": "null" }
1211
+ },
1212
+ "required": ["data"]
1213
+ }
1214
+ ]
1215
+ }
1216
+ }
1217
+ }
1218
+ },
1219
+ "401": {
1220
+ "description": "Invalid client credentials.",
1221
+ "content": {
1222
+ "application/json": {
1223
+ "schema": {
1224
+ "allOf": [
1225
+ { "$ref": "#/components/schemas/ApiResponse" },
1226
+ {
1227
+ "type": "object",
1228
+ "properties": {
1229
+ "data": { "type": "null" }
1230
+ },
1231
+ "required": ["data"]
1232
+ }
1233
+ ]
1234
+ }
1235
+ }
1236
+ }
1237
+ },
1238
+ "501": {
1239
+ "description": "OAuth token storage not configured.",
1240
+ "content": {
1241
+ "application/json": {
1242
+ "schema": {
1243
+ "allOf": [
1244
+ { "$ref": "#/components/schemas/ApiResponse" },
1245
+ {
1246
+ "type": "object",
1247
+ "properties": {
1248
+ "data": { "type": "null" }
1249
+ },
1250
+ "required": ["data"]
1251
+ }
1252
+ ]
1253
+ }
1254
+ }
1255
+ }
1256
+ }
1257
+ }
1258
+ }
1259
+ }
1260
+ },
1261
+ "components": {
1262
+ "securitySchemes": {
1263
+ "accessTokenBearer": {
1264
+ "type": "http",
1265
+ "scheme": "bearer",
1266
+ "bearerFormat": "JWT",
1267
+ "description": "JWT access token via Authorization: Bearer <token>."
1268
+ },
1269
+ "accessTokenCookie": {
1270
+ "type": "apiKey",
1271
+ "in": "cookie",
1272
+ "name": "dat",
1273
+ "description": "Access token cookie (default name \"dat\", configurable via ApiServerConf.accessCookie)."
1274
+ },
1275
+ "refreshTokenCookie": {
1276
+ "type": "apiKey",
1277
+ "in": "cookie",
1278
+ "name": "drt",
1279
+ "description": "Refresh token cookie (default name \"drt\", configurable via ApiServerConf.refreshCookie)."
1280
+ },
1281
+ "apiKeyBearer": {
1282
+ "type": "http",
1283
+ "scheme": "bearer",
1284
+ "description": "API key via Authorization: Bearer apikey-<secret>."
1285
+ }
1286
+ },
1287
+ "schemas": {
1288
+ "SafeUser": {
1289
+ "type": "object",
1290
+ "description": "Filtered user representation returned by storage.filterUser().",
1291
+ "additionalProperties": true
1292
+ },
1293
+ "ApiResponse": {
1294
+ "type": "object",
1295
+ "description": "ApiResponse<T> standard envelope used by all endpoints (success or error). T is the endpoint-specific payload type carried in the data field. Mirrors ApiClientBase.ApiResponseData.",
1296
+ "properties": {
1297
+ "success": {
1298
+ "type": "boolean",
1299
+ "description": "True on success responses."
1300
+ },
1301
+ "code": {
1302
+ "type": "integer",
1303
+ "description": "HTTP status code mirrored in the body."
1304
+ },
1305
+ "message": {
1306
+ "type": "string",
1307
+ "description": "Message string; may be defaulted by the client."
1308
+ },
1309
+ "data": {
1310
+ "description": "Endpoint-specific payload.",
1311
+ "nullable": true
1312
+ },
1313
+ "errors": {
1314
+ "type": "object",
1315
+ "description": "Field-level validation errors keyed by field name.",
1316
+ "additionalProperties": {
1317
+ "type": "string"
1318
+ }
1319
+ }
1320
+ },
1321
+ "required": ["success", "code", "message", "data", "errors"]
1322
+ },
1323
+ "PingResponseData": {
1324
+ "type": "object",
1325
+ "description": "Data payload returned by GET /api/v1/ping.",
1326
+ "properties": {
1327
+ "success": {
1328
+ "type": "boolean",
1329
+ "description": "Always true (redundant with ApiResponse.success)."
1330
+ },
1331
+ "status": {
1332
+ "type": "string",
1333
+ "description": "Health indicator (\"ok\")."
1334
+ },
1335
+ "apiVersion": {
1336
+ "type": "string"
1337
+ },
1338
+ "minClientVersion": {
1339
+ "type": "string"
1340
+ },
1341
+ "uptimeSec": {
1342
+ "type": "number"
1343
+ },
1344
+ "startedAt": {
1345
+ "type": "integer",
1346
+ "format": "int64",
1347
+ "description": "Server start time as milliseconds since epoch."
1348
+ },
1349
+ "timestamp": {
1350
+ "type": "string",
1351
+ "format": "date-time"
1352
+ }
1353
+ },
1354
+ "required": ["success", "status", "uptimeSec", "startedAt", "timestamp"]
1355
+ },
1356
+ "AuthTokensResponseData": {
1357
+ "type": "object",
1358
+ "description": "Access and refresh tokens paired with the effective user.",
1359
+ "properties": {
1360
+ "accessToken": {
1361
+ "type": "string"
1362
+ },
1363
+ "refreshToken": {
1364
+ "type": "string"
1365
+ },
1366
+ "user": {
1367
+ "$ref": "#/components/schemas/SafeUser"
1368
+ }
1369
+ },
1370
+ "required": ["accessToken", "refreshToken", "user"]
1371
+ },
1372
+ "WhoAmIResponseData": {
1373
+ "type": "object",
1374
+ "description": "Identity payload returned by /auth/v1/whoami.",
1375
+ "properties": {
1376
+ "user": {
1377
+ "$ref": "#/components/schemas/SafeUser"
1378
+ },
1379
+ "isImpersonating": {
1380
+ "type": "boolean",
1381
+ "description": "True when the real user differs from the effective user."
1382
+ },
1383
+ "realUser": {
1384
+ "$ref": "#/components/schemas/SafeUser",
1385
+ "nullable": true
1386
+ },
1387
+ "realUserId": {
1388
+ "description": "Identifier of the real user when impersonating.",
1389
+ "nullable": true
1390
+ }
1391
+ },
1392
+ "required": ["user", "isImpersonating"]
1393
+ },
1394
+ "LogoutResponseData": {
1395
+ "type": "object",
1396
+ "description": "Payload returned by /auth/v1/logout.",
1397
+ "properties": {
1398
+ "revoked": {
1399
+ "type": "integer",
1400
+ "description": "Number of refresh tokens revoked."
1401
+ }
1402
+ },
1403
+ "required": ["revoked"]
1404
+ },
1405
+ "LoginRequest": {
1406
+ "type": "object",
1407
+ "properties": {
1408
+ "login": {
1409
+ "type": "string"
1410
+ },
1411
+ "password": {
1412
+ "type": "string"
1413
+ },
1414
+ "domain": {
1415
+ "type": "string",
1416
+ "nullable": true
1417
+ },
1418
+ "fingerprint": {
1419
+ "type": "string",
1420
+ "nullable": true
1421
+ },
1422
+ "label": {
1423
+ "type": "string",
1424
+ "nullable": true
1425
+ },
1426
+ "browser": {
1427
+ "type": "string",
1428
+ "nullable": true
1429
+ },
1430
+ "device": {
1431
+ "type": "string",
1432
+ "nullable": true
1433
+ },
1434
+ "ip": {
1435
+ "type": "string",
1436
+ "nullable": true
1437
+ },
1438
+ "os": {
1439
+ "type": "string",
1440
+ "nullable": true
1441
+ },
1442
+ "keepSession": {
1443
+ "description": "Boolean or TTL controlling refresh cookie persistence.",
1444
+ "nullable": true
1445
+ }
1446
+ },
1447
+ "required": ["login", "password"]
1448
+ },
1449
+ "RefreshRequest": {
1450
+ "type": "object",
1451
+ "properties": {
1452
+ "refreshToken": {
1453
+ "type": "string",
1454
+ "nullable": true
1455
+ },
1456
+ "domain": {
1457
+ "type": "string",
1458
+ "nullable": true
1459
+ },
1460
+ "fingerprint": {
1461
+ "type": "string",
1462
+ "nullable": true
1463
+ },
1464
+ "label": {
1465
+ "type": "string",
1466
+ "nullable": true
1467
+ },
1468
+ "keepSession": {
1469
+ "nullable": true
1470
+ }
1471
+ }
1472
+ },
1473
+ "LogoutRequest": {
1474
+ "type": "object",
1475
+ "properties": {
1476
+ "token": {
1477
+ "type": "string",
1478
+ "description": "Refresh token; falls back to cookie when omitted.",
1479
+ "nullable": true
1480
+ }
1481
+ }
1482
+ },
1483
+ "WhoAmIRequest": {
1484
+ "type": "object",
1485
+ "properties": {
1486
+ "refreshToken": {
1487
+ "type": "string",
1488
+ "nullable": true
1489
+ },
1490
+ "refresh": {
1491
+ "type": "boolean",
1492
+ "description": "Force issuing a new access token even if one is present.",
1493
+ "nullable": true
1494
+ }
1495
+ }
1496
+ },
1497
+ "ImpersonateRequest": {
1498
+ "type": "object",
1499
+ "properties": {
1500
+ "userId": {
1501
+ "description": "Target user id.",
1502
+ "nullable": true
1503
+ },
1504
+ "login": {
1505
+ "type": "string",
1506
+ "description": "Target login identifier.",
1507
+ "nullable": true
1508
+ },
1509
+ "keepSession": {
1510
+ "nullable": true
1511
+ },
1512
+ "domain": {
1513
+ "type": "string",
1514
+ "nullable": true
1515
+ },
1516
+ "fingerprint": {
1517
+ "type": "string",
1518
+ "nullable": true
1519
+ },
1520
+ "label": {
1521
+ "type": "string",
1522
+ "nullable": true
1523
+ },
1524
+ "browser": {
1525
+ "type": "string",
1526
+ "nullable": true
1527
+ },
1528
+ "device": {
1529
+ "type": "string",
1530
+ "nullable": true
1531
+ },
1532
+ "ip": {
1533
+ "type": "string",
1534
+ "nullable": true
1535
+ },
1536
+ "os": {
1537
+ "type": "string",
1538
+ "nullable": true
1539
+ },
1540
+ "clientId": {
1541
+ "type": "string",
1542
+ "nullable": true
1543
+ },
1544
+ "scope": {
1545
+ "description": "Space-delimited or array scope.",
1546
+ "nullable": true
1547
+ },
1548
+ "loginType": {
1549
+ "type": "string",
1550
+ "nullable": true
1551
+ }
1552
+ }
1553
+ },
1554
+ "ImpersonationEndRequest": {
1555
+ "type": "object",
1556
+ "properties": {
1557
+ "keepSession": {
1558
+ "nullable": true
1559
+ },
1560
+ "domain": {
1561
+ "type": "string",
1562
+ "nullable": true
1563
+ },
1564
+ "fingerprint": {
1565
+ "type": "string",
1566
+ "nullable": true
1567
+ },
1568
+ "label": {
1569
+ "type": "string",
1570
+ "nullable": true
1571
+ },
1572
+ "browser": {
1573
+ "type": "string",
1574
+ "nullable": true
1575
+ },
1576
+ "device": {
1577
+ "type": "string",
1578
+ "nullable": true
1579
+ },
1580
+ "ip": {
1581
+ "type": "string",
1582
+ "nullable": true
1583
+ },
1584
+ "os": {
1585
+ "type": "string",
1586
+ "nullable": true
1587
+ },
1588
+ "clientId": {
1589
+ "type": "string",
1590
+ "nullable": true
1591
+ },
1592
+ "scope": {
1593
+ "description": "Space-delimited or array scope.",
1594
+ "nullable": true
1595
+ },
1596
+ "loginType": {
1597
+ "type": "string",
1598
+ "nullable": true
1599
+ }
1600
+ }
1601
+ },
1602
+ "PasskeyChallenge": {
1603
+ "type": "object",
1604
+ "description": "Challenge payload returned when initiating a passkey operation.",
1605
+ "properties": {
1606
+ "challenge": {
1607
+ "type": "string"
1608
+ },
1609
+ "expiresAt": {
1610
+ "type": "string",
1611
+ "format": "date-time",
1612
+ "nullable": true
1613
+ },
1614
+ "userId": {
1615
+ "description": "User identifier for the challenge.",
1616
+ "nullable": true
1617
+ }
1618
+ },
1619
+ "additionalProperties": true,
1620
+ "required": ["challenge"]
1621
+ },
1622
+ "PasskeyCredential": {
1623
+ "type": "object",
1624
+ "description": "Passkey credential entry.",
1625
+ "properties": {
1626
+ "id": {
1627
+ "type": "string"
1628
+ },
1629
+ "transports": {
1630
+ "type": "array",
1631
+ "items": {
1632
+ "type": "string"
1633
+ },
1634
+ "nullable": true
1635
+ },
1636
+ "backedUp": {
1637
+ "type": "boolean"
1638
+ },
1639
+ "deviceType": {
1640
+ "type": "string",
1641
+ "enum": ["singleDevice", "multiDevice"]
1642
+ },
1643
+ "createdAt": {
1644
+ "type": "string",
1645
+ "format": "date-time",
1646
+ "nullable": true
1647
+ },
1648
+ "updatedAt": {
1649
+ "type": "string",
1650
+ "format": "date-time",
1651
+ "nullable": true
1652
+ }
1653
+ },
1654
+ "required": ["id", "backedUp", "deviceType"]
1655
+ },
1656
+ "PasskeyListResponseData": {
1657
+ "type": "object",
1658
+ "description": "Payload returned by GET /auth/v1/passkeys.",
1659
+ "properties": {
1660
+ "credentials": {
1661
+ "type": "array",
1662
+ "items": {
1663
+ "$ref": "#/components/schemas/PasskeyCredential"
1664
+ }
1665
+ }
1666
+ },
1667
+ "required": ["credentials"]
1668
+ },
1669
+ "PasskeyDeleteResponseData": {
1670
+ "type": "object",
1671
+ "description": "Payload returned after deleting a passkey credential.",
1672
+ "properties": {
1673
+ "deleted": {
1674
+ "type": "boolean"
1675
+ }
1676
+ },
1677
+ "required": ["deleted"]
1678
+ },
1679
+ "PasskeyChallengeRequest": {
1680
+ "type": "object",
1681
+ "properties": {
1682
+ "action": {
1683
+ "type": "string",
1684
+ "enum": ["register", "authenticate"]
1685
+ },
1686
+ "login": {
1687
+ "type": "string",
1688
+ "nullable": true
1689
+ },
1690
+ "userId": {
1691
+ "nullable": true
1692
+ }
1693
+ },
1694
+ "required": ["action"]
1695
+ },
1696
+ "PasskeyVerifyRequest": {
1697
+ "type": "object",
1698
+ "properties": {
1699
+ "expectedChallenge": {
1700
+ "type": "string"
1701
+ },
1702
+ "response": {
1703
+ "type": "object",
1704
+ "additionalProperties": true
1705
+ },
1706
+ "login": {
1707
+ "type": "string",
1708
+ "nullable": true
1709
+ },
1710
+ "userId": {
1711
+ "nullable": true
1712
+ },
1713
+ "userAgent": {
1714
+ "type": "string",
1715
+ "nullable": true
1716
+ },
1717
+ "domain": {
1718
+ "type": "string",
1719
+ "nullable": true
1720
+ },
1721
+ "fingerprint": {
1722
+ "type": "string",
1723
+ "nullable": true
1724
+ },
1725
+ "label": {
1726
+ "type": "string",
1727
+ "nullable": true
1728
+ },
1729
+ "browser": {
1730
+ "type": "string",
1731
+ "nullable": true
1732
+ },
1733
+ "device": {
1734
+ "type": "string",
1735
+ "nullable": true
1736
+ },
1737
+ "ip": {
1738
+ "type": "string",
1739
+ "nullable": true
1740
+ },
1741
+ "os": {
1742
+ "type": "string",
1743
+ "nullable": true
1744
+ },
1745
+ "keepSession": {
1746
+ "nullable": true
1747
+ }
1748
+ },
1749
+ "required": ["expectedChallenge", "response"]
1750
+ },
1751
+ "OAuthStartRequest": {
1752
+ "type": "object",
1753
+ "properties": {
1754
+ "redirectUri": {
1755
+ "type": "string",
1756
+ "nullable": true
1757
+ },
1758
+ "scope": {
1759
+ "nullable": true
1760
+ },
1761
+ "state": {
1762
+ "type": "string",
1763
+ "nullable": true
1764
+ },
1765
+ "extras": {
1766
+ "type": "object",
1767
+ "additionalProperties": true,
1768
+ "nullable": true
1769
+ }
1770
+ }
1771
+ },
1772
+ "OAuthAuthorizeRequest": {
1773
+ "type": "object",
1774
+ "properties": {
1775
+ "clientId": {
1776
+ "type": "string"
1777
+ },
1778
+ "redirectUri": {
1779
+ "type": "string"
1780
+ },
1781
+ "scope": {
1782
+ "nullable": true
1783
+ },
1784
+ "state": {
1785
+ "type": "string",
1786
+ "nullable": true
1787
+ },
1788
+ "codeChallenge": {
1789
+ "type": "string",
1790
+ "nullable": true
1791
+ },
1792
+ "codeChallengeMethod": {
1793
+ "type": "string",
1794
+ "nullable": true
1795
+ },
1796
+ "login": {
1797
+ "type": "string",
1798
+ "nullable": true
1799
+ },
1800
+ "password": {
1801
+ "type": "string",
1802
+ "nullable": true
1803
+ }
1804
+ },
1805
+ "required": ["clientId", "redirectUri"]
1806
+ },
1807
+ "OAuthTokenRequest": {
1808
+ "type": "object",
1809
+ "properties": {
1810
+ "grant_type": {
1811
+ "type": "string"
1812
+ },
1813
+ "code": {
1814
+ "type": "string",
1815
+ "nullable": true
1816
+ },
1817
+ "redirect_uri": {
1818
+ "type": "string",
1819
+ "nullable": true
1820
+ },
1821
+ "code_verifier": {
1822
+ "type": "string",
1823
+ "nullable": true
1824
+ },
1825
+ "refresh_token": {
1826
+ "type": "string",
1827
+ "nullable": true
1828
+ },
1829
+ "client_id": {
1830
+ "type": "string",
1831
+ "nullable": true
1832
+ },
1833
+ "client_secret": {
1834
+ "type": "string",
1835
+ "nullable": true
1836
+ }
1837
+ },
1838
+ "required": ["grant_type"]
1839
+ },
1840
+ "OAuthStartResponse": {
1841
+ "type": "object",
1842
+ "description": "Provider-specific start payload (e.g. redirect URL, state).",
1843
+ "additionalProperties": true
1844
+ },
1845
+ "OAuthCallbackResponse": {
1846
+ "type": "object",
1847
+ "description": "Provider-specific callback payload (may include tokens and user).",
1848
+ "additionalProperties": true
1849
+ },
1850
+ "OAuthAuthorizeResponse": {
1851
+ "type": "object",
1852
+ "description": "Authorization code response.",
1853
+ "properties": {
1854
+ "code": {
1855
+ "type": "string",
1856
+ "description": "Authorization code."
1857
+ },
1858
+ "redirectUri": {
1859
+ "type": "string",
1860
+ "description": "Redirect URI to continue the OAuth flow."
1861
+ },
1862
+ "state": {
1863
+ "type": "string",
1864
+ "nullable": true
1865
+ }
1866
+ },
1867
+ "required": ["code", "redirectUri"]
1868
+ },
1869
+ "OAuthTokenResponse": {
1870
+ "type": "object",
1871
+ "description": "Token response fields (access_token, refresh_token, etc.) as provided by the OAuth implementation.",
1872
+ "additionalProperties": true
1873
+ }
1874
+ }
1875
+ }
1876
+ }