@technomoron/api-server-base 2.0.0-beta.11 → 2.0.0-beta.14

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.
@@ -0,0 +1,2010 @@
1
+ {
2
+ "openapi": "3.1.0",
3
+ "info": {
4
+ "title": "API Server Base",
5
+ "version": "1.0.0",
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 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
+ "delete": {
765
+ "tags": ["passkey"],
766
+ "summary": "Delete a passkey credential",
767
+ "description": "Auth: strict. Deletes a passkey credential by id provided in the request body.",
768
+ "security": [{ "accessTokenBearer": [] }, { "accessTokenCookie": [] }, { "apiKeyBearer": [] }],
769
+ "requestBody": {
770
+ "required": true,
771
+ "content": {
772
+ "application/json": {
773
+ "schema": {
774
+ "type": "object",
775
+ "properties": {
776
+ "credentialId": {
777
+ "type": "string",
778
+ "description": "Credential id (base64url)."
779
+ }
780
+ },
781
+ "required": ["credentialId"]
782
+ }
783
+ }
784
+ }
785
+ },
786
+ "responses": {
787
+ "200": {
788
+ "description": "Credential deleted.",
789
+ "content": {
790
+ "application/json": {
791
+ "schema": {
792
+ "allOf": [
793
+ { "$ref": "#/components/schemas/ApiResponse" },
794
+ {
795
+ "type": "object",
796
+ "properties": {
797
+ "data": { "$ref": "#/components/schemas/PasskeyDeleteResponseData" }
798
+ },
799
+ "required": ["data"]
800
+ }
801
+ ]
802
+ }
803
+ }
804
+ }
805
+ },
806
+ "400": {
807
+ "description": "Missing or invalid credentialId.",
808
+ "content": {
809
+ "application/json": {
810
+ "schema": {
811
+ "allOf": [
812
+ { "$ref": "#/components/schemas/ApiResponse" },
813
+ {
814
+ "type": "object",
815
+ "properties": {
816
+ "data": { "type": "null" }
817
+ },
818
+ "required": ["data"]
819
+ }
820
+ ]
821
+ }
822
+ }
823
+ }
824
+ },
825
+ "401": {
826
+ "description": "Authentication required.",
827
+ "content": {
828
+ "application/json": {
829
+ "schema": {
830
+ "allOf": [
831
+ { "$ref": "#/components/schemas/ApiResponse" },
832
+ {
833
+ "type": "object",
834
+ "properties": {
835
+ "data": { "type": "null" }
836
+ },
837
+ "required": ["data"]
838
+ }
839
+ ]
840
+ }
841
+ }
842
+ }
843
+ },
844
+ "403": {
845
+ "description": "Authenticated user not found.",
846
+ "content": {
847
+ "application/json": {
848
+ "schema": {
849
+ "allOf": [
850
+ { "$ref": "#/components/schemas/ApiResponse" },
851
+ {
852
+ "type": "object",
853
+ "properties": {
854
+ "data": { "type": "null" }
855
+ },
856
+ "required": ["data"]
857
+ }
858
+ ]
859
+ }
860
+ }
861
+ }
862
+ },
863
+ "404": {
864
+ "description": "Passkey not found.",
865
+ "content": {
866
+ "application/json": {
867
+ "schema": {
868
+ "allOf": [
869
+ { "$ref": "#/components/schemas/ApiResponse" },
870
+ {
871
+ "type": "object",
872
+ "properties": {
873
+ "data": { "type": "null" }
874
+ },
875
+ "required": ["data"]
876
+ }
877
+ ]
878
+ }
879
+ }
880
+ }
881
+ },
882
+ "501": {
883
+ "description": "Passkey management not configured.",
884
+ "content": {
885
+ "application/json": {
886
+ "schema": {
887
+ "allOf": [
888
+ { "$ref": "#/components/schemas/ApiResponse" },
889
+ {
890
+ "type": "object",
891
+ "properties": {
892
+ "data": { "type": "null" }
893
+ },
894
+ "required": ["data"]
895
+ }
896
+ ]
897
+ }
898
+ }
899
+ }
900
+ }
901
+ }
902
+ }
903
+ },
904
+ "/api/auth/v1/passkeys/{credentialId}": {
905
+ "delete": {
906
+ "tags": ["passkey"],
907
+ "summary": "Delete a passkey credential",
908
+ "description": "Auth: strict. Deletes the passkey credential identified by the path parameter.",
909
+ "security": [{ "accessTokenBearer": [] }, { "accessTokenCookie": [] }, { "apiKeyBearer": [] }],
910
+ "parameters": [
911
+ {
912
+ "name": "credentialId",
913
+ "in": "path",
914
+ "required": true,
915
+ "description": "Credential id (base64url).",
916
+ "schema": { "type": "string" }
917
+ }
918
+ ],
919
+ "responses": {
920
+ "200": {
921
+ "description": "Credential deleted.",
922
+ "content": {
923
+ "application/json": {
924
+ "schema": {
925
+ "allOf": [
926
+ { "$ref": "#/components/schemas/ApiResponse" },
927
+ {
928
+ "type": "object",
929
+ "properties": {
930
+ "data": { "$ref": "#/components/schemas/PasskeyDeleteResponseData" }
931
+ },
932
+ "required": ["data"]
933
+ }
934
+ ]
935
+ }
936
+ }
937
+ }
938
+ },
939
+ "400": {
940
+ "description": "Missing or invalid credentialId.",
941
+ "content": {
942
+ "application/json": {
943
+ "schema": {
944
+ "allOf": [
945
+ { "$ref": "#/components/schemas/ApiResponse" },
946
+ {
947
+ "type": "object",
948
+ "properties": {
949
+ "data": { "type": "null" }
950
+ },
951
+ "required": ["data"]
952
+ }
953
+ ]
954
+ }
955
+ }
956
+ }
957
+ },
958
+ "401": {
959
+ "description": "Authentication required.",
960
+ "content": {
961
+ "application/json": {
962
+ "schema": {
963
+ "allOf": [
964
+ { "$ref": "#/components/schemas/ApiResponse" },
965
+ {
966
+ "type": "object",
967
+ "properties": {
968
+ "data": { "type": "null" }
969
+ },
970
+ "required": ["data"]
971
+ }
972
+ ]
973
+ }
974
+ }
975
+ }
976
+ },
977
+ "403": {
978
+ "description": "Authenticated user not found.",
979
+ "content": {
980
+ "application/json": {
981
+ "schema": {
982
+ "allOf": [
983
+ { "$ref": "#/components/schemas/ApiResponse" },
984
+ {
985
+ "type": "object",
986
+ "properties": {
987
+ "data": { "type": "null" }
988
+ },
989
+ "required": ["data"]
990
+ }
991
+ ]
992
+ }
993
+ }
994
+ }
995
+ },
996
+ "404": {
997
+ "description": "Passkey not found.",
998
+ "content": {
999
+ "application/json": {
1000
+ "schema": {
1001
+ "allOf": [
1002
+ { "$ref": "#/components/schemas/ApiResponse" },
1003
+ {
1004
+ "type": "object",
1005
+ "properties": {
1006
+ "data": { "type": "null" }
1007
+ },
1008
+ "required": ["data"]
1009
+ }
1010
+ ]
1011
+ }
1012
+ }
1013
+ }
1014
+ },
1015
+ "501": {
1016
+ "description": "Passkey management not configured.",
1017
+ "content": {
1018
+ "application/json": {
1019
+ "schema": {
1020
+ "allOf": [
1021
+ { "$ref": "#/components/schemas/ApiResponse" },
1022
+ {
1023
+ "type": "object",
1024
+ "properties": {
1025
+ "data": { "type": "null" }
1026
+ },
1027
+ "required": ["data"]
1028
+ }
1029
+ ]
1030
+ }
1031
+ }
1032
+ }
1033
+ }
1034
+ }
1035
+ }
1036
+ },
1037
+ "/api/auth/v1/oauth2/{provider}/start": {
1038
+ "post": {
1039
+ "tags": ["oauth"],
1040
+ "summary": "Begin an external OAuth flow",
1041
+ "description": "Auth: none. Starts an external OAuth flow for the provider.",
1042
+ "security": [],
1043
+ "parameters": [
1044
+ {
1045
+ "name": "provider",
1046
+ "in": "path",
1047
+ "required": true,
1048
+ "description": "OAuth provider identifier.",
1049
+ "schema": { "type": "string" }
1050
+ }
1051
+ ],
1052
+ "requestBody": {
1053
+ "required": false,
1054
+ "content": {
1055
+ "application/json": {
1056
+ "schema": { "$ref": "#/components/schemas/OAuthStartRequest" }
1057
+ }
1058
+ }
1059
+ },
1060
+ "responses": {
1061
+ "200": {
1062
+ "description": "Start payload for the provider.",
1063
+ "content": {
1064
+ "application/json": {
1065
+ "schema": {
1066
+ "allOf": [
1067
+ { "$ref": "#/components/schemas/ApiResponse" },
1068
+ {
1069
+ "type": "object",
1070
+ "properties": {
1071
+ "data": { "$ref": "#/components/schemas/OAuthStartResponse" }
1072
+ },
1073
+ "required": ["data"]
1074
+ }
1075
+ ]
1076
+ }
1077
+ }
1078
+ }
1079
+ },
1080
+ "400": {
1081
+ "description": "Missing provider.",
1082
+ "content": {
1083
+ "application/json": {
1084
+ "schema": {
1085
+ "allOf": [
1086
+ { "$ref": "#/components/schemas/ApiResponse" },
1087
+ {
1088
+ "type": "object",
1089
+ "properties": {
1090
+ "data": { "type": "null" }
1091
+ },
1092
+ "required": ["data"]
1093
+ }
1094
+ ]
1095
+ }
1096
+ }
1097
+ }
1098
+ },
1099
+ "501": {
1100
+ "description": "OAuth support not configured.",
1101
+ "content": {
1102
+ "application/json": {
1103
+ "schema": {
1104
+ "allOf": [
1105
+ { "$ref": "#/components/schemas/ApiResponse" },
1106
+ {
1107
+ "type": "object",
1108
+ "properties": {
1109
+ "data": { "type": "null" }
1110
+ },
1111
+ "required": ["data"]
1112
+ }
1113
+ ]
1114
+ }
1115
+ }
1116
+ }
1117
+ }
1118
+ }
1119
+ }
1120
+ },
1121
+ "/api/auth/v1/oauth2/{provider}/callback": {
1122
+ "post": {
1123
+ "tags": ["oauth"],
1124
+ "summary": "Complete an external OAuth flow",
1125
+ "description": "Auth: none. Completes the provider callback and returns the provider result.",
1126
+ "security": [],
1127
+ "parameters": [
1128
+ {
1129
+ "name": "provider",
1130
+ "in": "path",
1131
+ "required": true,
1132
+ "description": "OAuth provider identifier.",
1133
+ "schema": { "type": "string" }
1134
+ }
1135
+ ],
1136
+ "requestBody": {
1137
+ "required": false,
1138
+ "content": {
1139
+ "application/json": {
1140
+ "schema": {
1141
+ "type": "object",
1142
+ "additionalProperties": true
1143
+ }
1144
+ }
1145
+ }
1146
+ },
1147
+ "responses": {
1148
+ "200": {
1149
+ "description": "Provider callback result.",
1150
+ "content": {
1151
+ "application/json": {
1152
+ "schema": {
1153
+ "allOf": [
1154
+ { "$ref": "#/components/schemas/ApiResponse" },
1155
+ {
1156
+ "type": "object",
1157
+ "properties": {
1158
+ "data": { "$ref": "#/components/schemas/OAuthCallbackResponse" }
1159
+ },
1160
+ "required": ["data"]
1161
+ }
1162
+ ]
1163
+ }
1164
+ }
1165
+ }
1166
+ },
1167
+ "400": {
1168
+ "description": "Missing provider.",
1169
+ "content": {
1170
+ "application/json": {
1171
+ "schema": {
1172
+ "allOf": [
1173
+ { "$ref": "#/components/schemas/ApiResponse" },
1174
+ {
1175
+ "type": "object",
1176
+ "properties": {
1177
+ "data": { "type": "null" }
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
+ { "$ref": "#/components/schemas/ApiResponse" },
1193
+ {
1194
+ "type": "object",
1195
+ "properties": {
1196
+ "data": { "type": "null" }
1197
+ },
1198
+ "required": ["data"]
1199
+ }
1200
+ ]
1201
+ }
1202
+ }
1203
+ }
1204
+ }
1205
+ }
1206
+ }
1207
+ },
1208
+ "/api/auth/v1/oauth2/authorize": {
1209
+ "post": {
1210
+ "tags": ["oauth"],
1211
+ "summary": "Issue an authorization code",
1212
+ "description": "Auth: required. Issues an authorization code for an authenticated user using a refresh token cookie or login credentials.",
1213
+ "security": [{ "refreshTokenCookie": [] }],
1214
+ "requestBody": {
1215
+ "required": true,
1216
+ "content": {
1217
+ "application/json": {
1218
+ "schema": { "$ref": "#/components/schemas/OAuthAuthorizeRequest" }
1219
+ }
1220
+ }
1221
+ },
1222
+ "responses": {
1223
+ "200": {
1224
+ "description": "Authorization code issued.",
1225
+ "content": {
1226
+ "application/json": {
1227
+ "schema": {
1228
+ "allOf": [
1229
+ { "$ref": "#/components/schemas/ApiResponse" },
1230
+ {
1231
+ "type": "object",
1232
+ "properties": {
1233
+ "data": { "$ref": "#/components/schemas/OAuthAuthorizeResponse" }
1234
+ },
1235
+ "required": ["data"]
1236
+ }
1237
+ ]
1238
+ }
1239
+ }
1240
+ }
1241
+ },
1242
+ "400": {
1243
+ "description": "Invalid request or client configuration.",
1244
+ "content": {
1245
+ "application/json": {
1246
+ "schema": {
1247
+ "allOf": [
1248
+ { "$ref": "#/components/schemas/ApiResponse" },
1249
+ {
1250
+ "type": "object",
1251
+ "properties": {
1252
+ "data": { "type": "null" }
1253
+ },
1254
+ "required": ["data"]
1255
+ }
1256
+ ]
1257
+ }
1258
+ }
1259
+ }
1260
+ },
1261
+ "401": {
1262
+ "description": "User authentication required.",
1263
+ "content": {
1264
+ "application/json": {
1265
+ "schema": {
1266
+ "allOf": [
1267
+ { "$ref": "#/components/schemas/ApiResponse" },
1268
+ {
1269
+ "type": "object",
1270
+ "properties": {
1271
+ "data": { "type": "null" }
1272
+ },
1273
+ "required": ["data"]
1274
+ }
1275
+ ]
1276
+ }
1277
+ }
1278
+ }
1279
+ },
1280
+ "501": {
1281
+ "description": "OAuth authorization storage not configured.",
1282
+ "content": {
1283
+ "application/json": {
1284
+ "schema": {
1285
+ "allOf": [
1286
+ { "$ref": "#/components/schemas/ApiResponse" },
1287
+ {
1288
+ "type": "object",
1289
+ "properties": {
1290
+ "data": { "type": "null" }
1291
+ },
1292
+ "required": ["data"]
1293
+ }
1294
+ ]
1295
+ }
1296
+ }
1297
+ }
1298
+ }
1299
+ }
1300
+ }
1301
+ },
1302
+ "/api/auth/v1/oauth2/token": {
1303
+ "post": {
1304
+ "tags": ["oauth"],
1305
+ "summary": "Exchange a code or refresh token",
1306
+ "description": "Auth: none. Exchanges an authorization code or refresh token for OAuth tokens; client authentication may be required.",
1307
+ "security": [],
1308
+ "requestBody": {
1309
+ "required": true,
1310
+ "content": {
1311
+ "application/json": {
1312
+ "schema": { "$ref": "#/components/schemas/OAuthTokenRequest" }
1313
+ },
1314
+ "application/x-www-form-urlencoded": {
1315
+ "schema": { "$ref": "#/components/schemas/OAuthTokenRequest" }
1316
+ }
1317
+ }
1318
+ },
1319
+ "responses": {
1320
+ "200": {
1321
+ "description": "Token response.",
1322
+ "content": {
1323
+ "application/json": {
1324
+ "schema": {
1325
+ "allOf": [
1326
+ { "$ref": "#/components/schemas/ApiResponse" },
1327
+ {
1328
+ "type": "object",
1329
+ "properties": {
1330
+ "data": { "$ref": "#/components/schemas/OAuthTokenResponse" }
1331
+ },
1332
+ "required": ["data"]
1333
+ }
1334
+ ]
1335
+ }
1336
+ }
1337
+ }
1338
+ },
1339
+ "400": {
1340
+ "description": "Invalid request.",
1341
+ "content": {
1342
+ "application/json": {
1343
+ "schema": {
1344
+ "allOf": [
1345
+ { "$ref": "#/components/schemas/ApiResponse" },
1346
+ {
1347
+ "type": "object",
1348
+ "properties": {
1349
+ "data": { "type": "null" }
1350
+ },
1351
+ "required": ["data"]
1352
+ }
1353
+ ]
1354
+ }
1355
+ }
1356
+ }
1357
+ },
1358
+ "401": {
1359
+ "description": "Invalid client credentials.",
1360
+ "content": {
1361
+ "application/json": {
1362
+ "schema": {
1363
+ "allOf": [
1364
+ { "$ref": "#/components/schemas/ApiResponse" },
1365
+ {
1366
+ "type": "object",
1367
+ "properties": {
1368
+ "data": { "type": "null" }
1369
+ },
1370
+ "required": ["data"]
1371
+ }
1372
+ ]
1373
+ }
1374
+ }
1375
+ }
1376
+ },
1377
+ "501": {
1378
+ "description": "OAuth token storage not configured.",
1379
+ "content": {
1380
+ "application/json": {
1381
+ "schema": {
1382
+ "allOf": [
1383
+ { "$ref": "#/components/schemas/ApiResponse" },
1384
+ {
1385
+ "type": "object",
1386
+ "properties": {
1387
+ "data": { "type": "null" }
1388
+ },
1389
+ "required": ["data"]
1390
+ }
1391
+ ]
1392
+ }
1393
+ }
1394
+ }
1395
+ }
1396
+ }
1397
+ }
1398
+ }
1399
+ },
1400
+ "components": {
1401
+ "securitySchemes": {
1402
+ "accessTokenBearer": {
1403
+ "type": "http",
1404
+ "scheme": "bearer",
1405
+ "bearerFormat": "JWT",
1406
+ "description": "JWT access token via Authorization: Bearer <token>."
1407
+ },
1408
+ "accessTokenCookie": {
1409
+ "type": "apiKey",
1410
+ "in": "cookie",
1411
+ "name": "dat",
1412
+ "description": "Access token cookie (default name \"dat\", configurable via ApiServerConf.accessCookie)."
1413
+ },
1414
+ "refreshTokenCookie": {
1415
+ "type": "apiKey",
1416
+ "in": "cookie",
1417
+ "name": "drt",
1418
+ "description": "Refresh token cookie (default name \"drt\", configurable via ApiServerConf.refreshCookie)."
1419
+ },
1420
+ "apiKeyBearer": {
1421
+ "type": "http",
1422
+ "scheme": "bearer",
1423
+ "description": "API key via Authorization: Bearer apikey-<secret>."
1424
+ }
1425
+ },
1426
+ "schemas": {
1427
+ "SafeUser": {
1428
+ "type": "object",
1429
+ "description": "Filtered user representation returned by storage.filterUser().",
1430
+ "additionalProperties": true
1431
+ },
1432
+ "ApiResponse": {
1433
+ "type": "object",
1434
+ "description": "Standard envelope used by all endpoints (success or error). Mirrors ApiClientBase.ApiResponseData.",
1435
+ "properties": {
1436
+ "success": {
1437
+ "type": "boolean",
1438
+ "description": "True on success responses."
1439
+ },
1440
+ "code": {
1441
+ "type": "integer",
1442
+ "description": "HTTP status code mirrored in the body."
1443
+ },
1444
+ "message": {
1445
+ "type": "string",
1446
+ "description": "Message string; may be defaulted by the client."
1447
+ },
1448
+ "data": {
1449
+ "description": "Endpoint-specific payload.",
1450
+ "nullable": true
1451
+ },
1452
+ "errors": {
1453
+ "type": "object",
1454
+ "description": "Field-level validation errors keyed by field name.",
1455
+ "additionalProperties": {
1456
+ "type": "string"
1457
+ }
1458
+ }
1459
+ },
1460
+ "required": ["success", "code", "message", "data", "errors"]
1461
+ },
1462
+ "PingResponseData": {
1463
+ "type": "object",
1464
+ "description": "Data payload returned by GET /api/v1/ping.",
1465
+ "properties": {
1466
+ "status": {
1467
+ "type": "string",
1468
+ "description": "Health indicator (\"ok\")."
1469
+ },
1470
+ "apiVersion": {
1471
+ "type": "string"
1472
+ },
1473
+ "minClientVersion": {
1474
+ "type": "string"
1475
+ },
1476
+ "uptimeSec": {
1477
+ "type": "number"
1478
+ },
1479
+ "startedAt": {
1480
+ "type": "string",
1481
+ "format": "date-time"
1482
+ },
1483
+ "timestamp": {
1484
+ "type": "string",
1485
+ "format": "date-time"
1486
+ }
1487
+ },
1488
+ "required": ["status", "uptimeSec", "startedAt", "timestamp"]
1489
+ },
1490
+ "AuthTokensResponseData": {
1491
+ "type": "object",
1492
+ "description": "Access and refresh tokens paired with the effective user.",
1493
+ "properties": {
1494
+ "accessToken": {
1495
+ "type": "string"
1496
+ },
1497
+ "refreshToken": {
1498
+ "type": "string"
1499
+ },
1500
+ "user": {
1501
+ "$ref": "#/components/schemas/SafeUser"
1502
+ }
1503
+ },
1504
+ "required": ["accessToken", "refreshToken", "user"]
1505
+ },
1506
+ "WhoAmIResponseData": {
1507
+ "type": "object",
1508
+ "description": "Identity payload returned by /auth/v1/whoami.",
1509
+ "properties": {
1510
+ "user": {
1511
+ "$ref": "#/components/schemas/SafeUser"
1512
+ },
1513
+ "isImpersonating": {
1514
+ "type": "boolean",
1515
+ "description": "True when the real user differs from the effective user."
1516
+ },
1517
+ "realUser": {
1518
+ "$ref": "#/components/schemas/SafeUser",
1519
+ "nullable": true
1520
+ },
1521
+ "realUserId": {
1522
+ "description": "Identifier of the real user when impersonating.",
1523
+ "nullable": true
1524
+ }
1525
+ },
1526
+ "required": ["user", "isImpersonating"]
1527
+ },
1528
+ "LogoutResponseData": {
1529
+ "type": "object",
1530
+ "description": "Payload returned by /auth/v1/logout.",
1531
+ "properties": {
1532
+ "revoked": {
1533
+ "type": "integer",
1534
+ "description": "Number of refresh tokens revoked."
1535
+ }
1536
+ },
1537
+ "required": ["revoked"]
1538
+ },
1539
+ "LoginRequest": {
1540
+ "type": "object",
1541
+ "properties": {
1542
+ "login": {
1543
+ "type": "string"
1544
+ },
1545
+ "password": {
1546
+ "type": "string"
1547
+ },
1548
+ "domain": {
1549
+ "type": "string",
1550
+ "nullable": true
1551
+ },
1552
+ "fingerprint": {
1553
+ "type": "string",
1554
+ "nullable": true
1555
+ },
1556
+ "label": {
1557
+ "type": "string",
1558
+ "nullable": true
1559
+ },
1560
+ "browser": {
1561
+ "type": "string",
1562
+ "nullable": true
1563
+ },
1564
+ "device": {
1565
+ "type": "string",
1566
+ "nullable": true
1567
+ },
1568
+ "ip": {
1569
+ "type": "string",
1570
+ "nullable": true
1571
+ },
1572
+ "os": {
1573
+ "type": "string",
1574
+ "nullable": true
1575
+ },
1576
+ "keepSession": {
1577
+ "description": "Boolean or TTL controlling refresh cookie persistence.",
1578
+ "nullable": true
1579
+ }
1580
+ },
1581
+ "required": ["login", "password"]
1582
+ },
1583
+ "RefreshRequest": {
1584
+ "type": "object",
1585
+ "properties": {
1586
+ "refreshToken": {
1587
+ "type": "string",
1588
+ "nullable": true
1589
+ },
1590
+ "domain": {
1591
+ "type": "string",
1592
+ "nullable": true
1593
+ },
1594
+ "fingerprint": {
1595
+ "type": "string",
1596
+ "nullable": true
1597
+ },
1598
+ "label": {
1599
+ "type": "string",
1600
+ "nullable": true
1601
+ },
1602
+ "keepSession": {
1603
+ "nullable": true
1604
+ }
1605
+ }
1606
+ },
1607
+ "LogoutRequest": {
1608
+ "type": "object",
1609
+ "properties": {
1610
+ "token": {
1611
+ "type": "string",
1612
+ "description": "Refresh token; falls back to cookie when omitted.",
1613
+ "nullable": true
1614
+ }
1615
+ }
1616
+ },
1617
+ "WhoAmIRequest": {
1618
+ "type": "object",
1619
+ "properties": {
1620
+ "refreshToken": {
1621
+ "type": "string",
1622
+ "nullable": true
1623
+ },
1624
+ "refresh": {
1625
+ "type": "boolean",
1626
+ "description": "Force issuing a new access token even if one is present.",
1627
+ "nullable": true
1628
+ }
1629
+ }
1630
+ },
1631
+ "ImpersonateRequest": {
1632
+ "type": "object",
1633
+ "properties": {
1634
+ "userId": {
1635
+ "description": "Target user id.",
1636
+ "nullable": true
1637
+ },
1638
+ "login": {
1639
+ "type": "string",
1640
+ "description": "Target login identifier.",
1641
+ "nullable": true
1642
+ },
1643
+ "keepSession": {
1644
+ "nullable": true
1645
+ },
1646
+ "domain": {
1647
+ "type": "string",
1648
+ "nullable": true
1649
+ },
1650
+ "fingerprint": {
1651
+ "type": "string",
1652
+ "nullable": true
1653
+ },
1654
+ "label": {
1655
+ "type": "string",
1656
+ "nullable": true
1657
+ },
1658
+ "browser": {
1659
+ "type": "string",
1660
+ "nullable": true
1661
+ },
1662
+ "device": {
1663
+ "type": "string",
1664
+ "nullable": true
1665
+ },
1666
+ "ip": {
1667
+ "type": "string",
1668
+ "nullable": true
1669
+ },
1670
+ "os": {
1671
+ "type": "string",
1672
+ "nullable": true
1673
+ },
1674
+ "clientId": {
1675
+ "type": "string",
1676
+ "nullable": true
1677
+ },
1678
+ "scope": {
1679
+ "description": "Space-delimited or array scope.",
1680
+ "nullable": true
1681
+ },
1682
+ "loginType": {
1683
+ "type": "string",
1684
+ "nullable": true
1685
+ }
1686
+ }
1687
+ },
1688
+ "ImpersonationEndRequest": {
1689
+ "type": "object",
1690
+ "properties": {
1691
+ "keepSession": {
1692
+ "nullable": true
1693
+ },
1694
+ "domain": {
1695
+ "type": "string",
1696
+ "nullable": true
1697
+ },
1698
+ "fingerprint": {
1699
+ "type": "string",
1700
+ "nullable": true
1701
+ },
1702
+ "label": {
1703
+ "type": "string",
1704
+ "nullable": true
1705
+ },
1706
+ "browser": {
1707
+ "type": "string",
1708
+ "nullable": true
1709
+ },
1710
+ "device": {
1711
+ "type": "string",
1712
+ "nullable": true
1713
+ },
1714
+ "ip": {
1715
+ "type": "string",
1716
+ "nullable": true
1717
+ },
1718
+ "os": {
1719
+ "type": "string",
1720
+ "nullable": true
1721
+ },
1722
+ "clientId": {
1723
+ "type": "string",
1724
+ "nullable": true
1725
+ },
1726
+ "scope": {
1727
+ "description": "Space-delimited or array scope.",
1728
+ "nullable": true
1729
+ },
1730
+ "loginType": {
1731
+ "type": "string",
1732
+ "nullable": true
1733
+ }
1734
+ }
1735
+ },
1736
+ "PasskeyChallenge": {
1737
+ "type": "object",
1738
+ "description": "Challenge payload returned when initiating a passkey operation.",
1739
+ "properties": {
1740
+ "challenge": {
1741
+ "type": "string"
1742
+ },
1743
+ "expiresAt": {
1744
+ "type": "string",
1745
+ "format": "date-time",
1746
+ "nullable": true
1747
+ },
1748
+ "userId": {
1749
+ "description": "User identifier for the challenge.",
1750
+ "nullable": true
1751
+ }
1752
+ },
1753
+ "additionalProperties": true,
1754
+ "required": ["challenge"]
1755
+ },
1756
+ "PasskeyCredential": {
1757
+ "type": "object",
1758
+ "description": "Passkey credential entry.",
1759
+ "properties": {
1760
+ "id": {
1761
+ "type": "string"
1762
+ },
1763
+ "transports": {
1764
+ "type": "array",
1765
+ "items": {
1766
+ "type": "string"
1767
+ },
1768
+ "nullable": true
1769
+ },
1770
+ "backedUp": {
1771
+ "type": "boolean"
1772
+ },
1773
+ "deviceType": {
1774
+ "type": "string",
1775
+ "enum": ["singleDevice", "multiDevice"]
1776
+ },
1777
+ "createdAt": {
1778
+ "type": "string",
1779
+ "format": "date-time",
1780
+ "nullable": true
1781
+ },
1782
+ "updatedAt": {
1783
+ "type": "string",
1784
+ "format": "date-time",
1785
+ "nullable": true
1786
+ }
1787
+ },
1788
+ "required": ["id", "backedUp", "deviceType"]
1789
+ },
1790
+ "PasskeyListResponseData": {
1791
+ "type": "object",
1792
+ "description": "Payload returned by GET /auth/v1/passkeys.",
1793
+ "properties": {
1794
+ "credentials": {
1795
+ "type": "array",
1796
+ "items": {
1797
+ "$ref": "#/components/schemas/PasskeyCredential"
1798
+ }
1799
+ }
1800
+ },
1801
+ "required": ["credentials"]
1802
+ },
1803
+ "PasskeyDeleteResponseData": {
1804
+ "type": "object",
1805
+ "description": "Payload returned after deleting a passkey credential.",
1806
+ "properties": {
1807
+ "deleted": {
1808
+ "type": "boolean"
1809
+ }
1810
+ },
1811
+ "required": ["deleted"]
1812
+ },
1813
+ "PasskeyChallengeRequest": {
1814
+ "type": "object",
1815
+ "properties": {
1816
+ "action": {
1817
+ "type": "string",
1818
+ "enum": ["register", "authenticate"]
1819
+ },
1820
+ "login": {
1821
+ "type": "string",
1822
+ "nullable": true
1823
+ },
1824
+ "userId": {
1825
+ "nullable": true
1826
+ }
1827
+ },
1828
+ "required": ["action"]
1829
+ },
1830
+ "PasskeyVerifyRequest": {
1831
+ "type": "object",
1832
+ "properties": {
1833
+ "expectedChallenge": {
1834
+ "type": "string"
1835
+ },
1836
+ "response": {
1837
+ "type": "object",
1838
+ "additionalProperties": true
1839
+ },
1840
+ "login": {
1841
+ "type": "string",
1842
+ "nullable": true
1843
+ },
1844
+ "userId": {
1845
+ "nullable": true
1846
+ },
1847
+ "userAgent": {
1848
+ "type": "string",
1849
+ "nullable": true
1850
+ },
1851
+ "domain": {
1852
+ "type": "string",
1853
+ "nullable": true
1854
+ },
1855
+ "fingerprint": {
1856
+ "type": "string",
1857
+ "nullable": true
1858
+ },
1859
+ "label": {
1860
+ "type": "string",
1861
+ "nullable": true
1862
+ },
1863
+ "browser": {
1864
+ "type": "string",
1865
+ "nullable": true
1866
+ },
1867
+ "device": {
1868
+ "type": "string",
1869
+ "nullable": true
1870
+ },
1871
+ "ip": {
1872
+ "type": "string",
1873
+ "nullable": true
1874
+ },
1875
+ "os": {
1876
+ "type": "string",
1877
+ "nullable": true
1878
+ },
1879
+ "keepSession": {
1880
+ "nullable": true
1881
+ }
1882
+ },
1883
+ "required": ["expectedChallenge", "response"]
1884
+ },
1885
+ "OAuthStartRequest": {
1886
+ "type": "object",
1887
+ "properties": {
1888
+ "redirectUri": {
1889
+ "type": "string",
1890
+ "nullable": true
1891
+ },
1892
+ "scope": {
1893
+ "nullable": true
1894
+ },
1895
+ "state": {
1896
+ "type": "string",
1897
+ "nullable": true
1898
+ },
1899
+ "extras": {
1900
+ "type": "object",
1901
+ "additionalProperties": true,
1902
+ "nullable": true
1903
+ }
1904
+ }
1905
+ },
1906
+ "OAuthAuthorizeRequest": {
1907
+ "type": "object",
1908
+ "properties": {
1909
+ "clientId": {
1910
+ "type": "string"
1911
+ },
1912
+ "redirectUri": {
1913
+ "type": "string"
1914
+ },
1915
+ "scope": {
1916
+ "nullable": true
1917
+ },
1918
+ "state": {
1919
+ "type": "string",
1920
+ "nullable": true
1921
+ },
1922
+ "codeChallenge": {
1923
+ "type": "string",
1924
+ "nullable": true
1925
+ },
1926
+ "codeChallengeMethod": {
1927
+ "type": "string",
1928
+ "nullable": true
1929
+ },
1930
+ "login": {
1931
+ "type": "string",
1932
+ "nullable": true
1933
+ },
1934
+ "password": {
1935
+ "type": "string",
1936
+ "nullable": true
1937
+ }
1938
+ },
1939
+ "required": ["clientId", "redirectUri"]
1940
+ },
1941
+ "OAuthTokenRequest": {
1942
+ "type": "object",
1943
+ "properties": {
1944
+ "grant_type": {
1945
+ "type": "string"
1946
+ },
1947
+ "code": {
1948
+ "type": "string",
1949
+ "nullable": true
1950
+ },
1951
+ "redirect_uri": {
1952
+ "type": "string",
1953
+ "nullable": true
1954
+ },
1955
+ "code_verifier": {
1956
+ "type": "string",
1957
+ "nullable": true
1958
+ },
1959
+ "refresh_token": {
1960
+ "type": "string",
1961
+ "nullable": true
1962
+ },
1963
+ "client_id": {
1964
+ "type": "string",
1965
+ "nullable": true
1966
+ },
1967
+ "client_secret": {
1968
+ "type": "string",
1969
+ "nullable": true
1970
+ }
1971
+ },
1972
+ "required": ["grant_type"]
1973
+ },
1974
+ "OAuthStartResponse": {
1975
+ "type": "object",
1976
+ "description": "Provider-specific start payload (e.g. redirect URL, state).",
1977
+ "additionalProperties": true
1978
+ },
1979
+ "OAuthCallbackResponse": {
1980
+ "type": "object",
1981
+ "description": "Provider-specific callback payload (may include tokens and user).",
1982
+ "additionalProperties": true
1983
+ },
1984
+ "OAuthAuthorizeResponse": {
1985
+ "type": "object",
1986
+ "description": "Authorization code response.",
1987
+ "properties": {
1988
+ "code": {
1989
+ "type": "string",
1990
+ "description": "Authorization code."
1991
+ },
1992
+ "redirectUri": {
1993
+ "type": "string",
1994
+ "description": "Redirect URI to continue the OAuth flow."
1995
+ },
1996
+ "state": {
1997
+ "type": "string",
1998
+ "nullable": true
1999
+ }
2000
+ },
2001
+ "required": ["code", "redirectUri"]
2002
+ },
2003
+ "OAuthTokenResponse": {
2004
+ "type": "object",
2005
+ "description": "Token response fields (access_token, refresh_token, etc.) as provided by the OAuth implementation.",
2006
+ "additionalProperties": true
2007
+ }
2008
+ }
2009
+ }
2010
+ }