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