-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathauth-api.yaml
More file actions
524 lines (498 loc) · 19.6 KB
/
auth-api.yaml
File metadata and controls
524 lines (498 loc) · 19.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
openapi: 3.0.3
info:
title: OIF Solver Authentication API
description: |
API endpoints for JWT-based authentication and authorization for the OIF Solver.
## Authentication Flow
1. **SIWE Admin Auth**: POST /auth/siwe/nonce then POST /auth/siwe/verify to obtain admin access + refresh tokens
2. **Optional Public Registration**: POST /auth/register (if enabled) for non-admin scopes
3. **API Access**: Include access token in Authorization header: `Bearer <access_token>`
4. **Token Refresh**: For register-issued or SIWE-issued tokens, POST /auth/refresh with refresh token
5. **Scope-Based Authorization**: Different endpoints require different scopes
## Token Lifecycle
- **Access Tokens**: Short-lived, used for API authentication
- **SIWE Access Tokens**: Default 900 seconds (with current constants)
- **SIWE Refresh Tokens**: Issued by /auth/siwe/verify and compatible with /auth/refresh
- **Refresh Tokens**: Long-lived (default 30 days), used to obtain new access tokens
- **Token Rotation**: Refresh endpoint returns a new refresh token
## Scopes
- `read-orders`: Read access to order information (GET /orders/{id})
- `create-orders`: Permission to create new orders (POST /orders)
- `admin-all`: Full administrative access to all endpoints
## Security Notes
- Authentication is optional and configured per solver instance
- If `auth.enabled = false`, auth endpoints are unavailable
- `/auth/register` cannot issue `admin-all`
- Client IDs must be between 3-100 characters
version: 1.0.0
servers:
- url: http://localhost:3000/api/v1
description: Local development server
- url: https://api.solver.example.com/api/v1
description: Production server (replace with actual URL)
paths:
/auth/siwe/nonce:
post:
summary: Create SIWE nonce and message
description: |
Creates a single-use SIWE nonce and returns a canonical message to sign.
This endpoint is intended for admin authentication via wallet signature.
operationId: issueSiweNonce
tags:
- Authentication
requestBody:
required: true
description: Address that will sign the SIWE message
content:
application/json:
schema:
$ref: "#/components/schemas/SiweNonceRequest"
example:
address: "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B"
responses:
"200":
description: SIWE nonce generated
content:
application/json:
schema:
$ref: "#/components/schemas/SiweNonceResponse"
example:
nonce: "00000000000001234567"
message: "solver.example.com wants you to sign in with your Ethereum account:\n0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B\n\nSign in to OIF Solver Admin API\n\nURI: https://solver.example.com\nVersion: 1\nChain ID: 1\nNonce: 00000000000001234567\nIssued At: 2026-02-18T12:00:00.000Z\nExpiration Time: 2026-02-18T12:05:00.000Z\n"
expires_in: 300
domain: "solver.example.com"
chain_id: 1
"400":
description: Invalid address
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "Invalid Ethereum address: invalid address checksum"
"500":
description: Failed to create nonce
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "Failed to generate SIWE nonce"
"503":
description: SIWE auth unavailable
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "SIWE authentication is not configured"
/auth/siwe/verify:
post:
summary: Verify SIWE message and issue admin tokens
description: |
Verifies the SIWE message signature, validates nonce/domain/chain, and issues
JWT access + refresh tokens with `admin-all` scope.
operationId: verifySiweToken
tags:
- Authentication
requestBody:
required: true
description: Signed SIWE payload
content:
application/json:
schema:
$ref: "#/components/schemas/SiweVerifyRequest"
example:
message: "solver.example.com wants you to sign in with your Ethereum account:\n0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B\n\nSign in to OIF Solver Admin API\n\nURI: https://solver.example.com\nVersion: 1\nChain ID: 1\nNonce: 00000000000001234567\nIssued At: 2026-02-18T12:00:00.000Z\nExpiration Time: 2026-02-18T12:05:00.000Z\n"
signature: "0x..."
responses:
"200":
description: SIWE verified and admin tokens issued
content:
application/json:
schema:
$ref: "#/components/schemas/RegisterResponse"
example:
access_token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
refresh_token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
client_id: "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B"
token_type: "Bearer"
access_token_expires_at: 1771463174
refresh_token_expires_at: 1774051574
scopes: ["admin-all"]
"400":
description: Invalid SIWE nonce format
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "SIWE nonce format is invalid"
"401":
description: Invalid signature or expired nonce/message
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
invalidSignature:
value:
error: "SIWE signature recovery failed: Recovery failed: ..."
expiredNonce:
value:
error: "Invalid or expired SIWE nonce"
"403":
description: Valid signer but not in admin allowlist
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "SIWE signer is not an authorized admin"
"500":
description: Failed to issue token
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
accessTokenError:
value:
error: "Failed to generate access token"
refreshTokenError:
value:
error: "Failed to generate refresh token"
"503":
description: SIWE auth unavailable
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "SIWE authentication is not configured"
/auth/register:
post:
summary: Register a new client
description: |
Allows clients to self-register and receive both access and refresh tokens
for API authentication. This endpoint is optional and typically disabled
unless explicitly enabled by the solver operator.
The access token has a short expiry (1 hour by default) and should be included
in the Authorization header for subsequent API calls. The refresh token has a
longer expiry (30 days by default) and should be used to obtain new tokens
when the access token expires.
If no scopes are provided, the client is granted basic read permissions (read-orders).
`admin-all` is not allowed on this endpoint.
operationId: registerClient
tags:
- Authentication
requestBody:
required: true
description: Client registration details
content:
application/json:
schema:
$ref: "#/components/schemas/RegisterRequest"
examples:
basicRegistration:
summary: Basic registration with default scopes
value:
client_id: "my-app-client"
client_name: "My Application"
customScopes:
summary: Registration with custom scopes
value:
client_id: "solver-integration"
client_name: "Solver Integration Service"
scopes: ["read-orders", "create-orders"]
responses:
"201":
description: Client successfully registered
content:
application/json:
schema:
$ref: "#/components/schemas/RegisterResponse"
example:
access_token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
refresh_token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
client_id: "my-app-client"
access_token_expires_at: 1700003600
refresh_token_expires_at: 1702595600
scopes: ["read-orders"]
token_type: "Bearer"
"400":
description: Invalid request (empty or invalid client_id, invalid or privileged scopes)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
emptyClientId:
value:
error: "Client ID cannot be empty"
invalidClientIdLength:
value:
error: "Client ID must be between 3 and 100 characters"
invalidScopes:
value:
error: "Invalid scopes: Unknown scope: invalid-scope"
privilegedScope:
value:
error: "Invalid scopes: admin-all scope is not allowed on /auth/register"
"403":
description: Public registration disabled
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "Public client registration is disabled"
"500":
description: Failed to generate tokens (internal server error)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "Failed to generate access token"
"503":
description: Authentication service not configured
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "Authentication service is not configured"
/auth/refresh:
post:
summary: Refresh access token
description: |
Exchanges a valid refresh token for new access and refresh tokens.
This endpoint returns a new refresh token alongside the new access token.
Use this endpoint when an access token from `/auth/register` or
`/auth/siwe/verify` expires to continue making authenticated API calls.
operationId: refreshToken
tags:
- Authentication
requestBody:
required: true
description: Refresh token to exchange
content:
application/json:
schema:
$ref: "#/components/schemas/RefreshRequest"
example:
refresh_token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
responses:
"200":
description: Tokens successfully refreshed
content:
application/json:
schema:
$ref: "#/components/schemas/RegisterResponse"
example:
access_token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
refresh_token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
client_id: "my-app-client"
access_token_expires_at: 1700007200
refresh_token_expires_at: 1702599200
scopes: ["read-orders"]
token_type: "Bearer"
"400":
description: Invalid request (empty refresh token)
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "Refresh token cannot be empty"
"401":
description: Invalid or expired refresh token
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "Invalid or expired refresh token"
"503":
description: Authentication service not configured
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
example:
error: "Authentication service is not configured"
components:
schemas:
SiweNonceRequest:
type: object
description: Request payload for SIWE nonce creation
required:
- address
properties:
address:
type: string
description: Ethereum address that will sign the SIWE message
example: "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B"
SiweNonceResponse:
type: object
description: Response payload for SIWE nonce creation
required:
- nonce
- message
- expires_in
- domain
- chain_id
properties:
nonce:
type: string
description: Single-use SIWE nonce
example: "00000000000001234567"
message:
type: string
description: Canonical SIWE message to sign
example: "solver.example.com wants you to sign in with your Ethereum account:\n0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B\n\nSign in to OIF Solver Admin API\n\nURI: https://solver.example.com\nVersion: 1\nChain ID: 1\nNonce: 00000000000001234567\nIssued At: 2026-02-18T12:00:00.000Z\nExpiration Time: 2026-02-18T12:05:00.000Z\n"
expires_in:
type: integer
description: Nonce validity in seconds
example: 300
domain:
type: string
description: Expected SIWE domain
example: "solver.example.com"
chain_id:
type: integer
description: Expected SIWE chain ID
example: 1
SiweVerifyRequest:
type: object
description: Request payload for SIWE verification
required:
- message
- signature
properties:
message:
type: string
description: Full SIWE message that was signed
example: "solver.example.com wants you to sign in with your Ethereum account:\n0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B\n\nSign in to OIF Solver Admin API\n\nURI: https://solver.example.com\nVersion: 1\nChain ID: 1\nNonce: 00000000000001234567\nIssued At: 2026-02-18T12:00:00.000Z\nExpiration Time: 2026-02-18T12:05:00.000Z\n"
signature:
type: string
description: Hex-encoded 65-byte personal_sign signature
example: "0x..."
RegisterRequest:
type: object
description: Request payload for client registration
required:
- client_id
properties:
client_id:
type: string
minLength: 3
maxLength: 100
description: |
Unique client identifier (e.g., application name, user email, service name).
Must be between 3 and 100 characters.
example: "my-app-client"
client_name:
type: string
description: Optional human-readable client name for display purposes
example: "My Application"
scopes:
type: array
description: |
Requested scopes for authorization. If not provided, defaults to ["read-orders"].
Available scopes:
- read-orders: Read access to order information
- create-orders: Permission to create new orders
items:
type: string
enum: ["read-orders", "create-orders", "read-quotes", "create-quotes"]
example: ["read-orders", "create-orders"]
RefreshRequest:
type: object
description: Request payload for token refresh
required:
- refresh_token
properties:
refresh_token:
type: string
description: The refresh token to exchange for new tokens
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
RegisterResponse:
type: object
description: Response payload for successful registration, SIWE verify, or refresh
required:
- access_token
- refresh_token
- client_id
- access_token_expires_at
- refresh_token_expires_at
- scopes
- token_type
properties:
access_token:
type: string
description: |
JWT access token for API authentication.
Include in Authorization header as: `Bearer <access_token>`
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJteS1hcHAtY2xpZW50Iiwic2NvcGUiOlsicmVhZC1vcmRlcnMiXSwiZXhwIjoxNzAwMDAzNjAwLCJpYXQiOjE3MDAwMDAwMDAsImlzcyI6Im9pZi1zb2x2ZXIifQ..."
refresh_token:
type: string
description: |
JWT refresh token for obtaining new access tokens.
Use with /auth/refresh endpoint when access token expires.
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJteS1hcHAtY2xpZW50Iiwic2NvcGUiOlsicmVhZC1vcmRlcnMiXSwiZXhwIjoxNzAyNTk1NjAwLCJpYXQiOjE3MDAwMDAwMDAsImlzcyI6Im9pZi1zb2x2ZXItcmVmcmVzaCJ9..."
client_id:
type: string
description: The client identifier
example: "my-app-client"
access_token_expires_at:
type: integer
format: int64
description: Unix timestamp when the access token expires
example: 1700003600
refresh_token_expires_at:
type: integer
format: int64
description: Unix timestamp when the refresh token expires
example: 1702595600
scopes:
type: array
description: Granted scopes for this client
items:
type: string
example: ["read-orders"]
token_type:
type: string
description: Token type (always "Bearer")
example: "Bearer"
ErrorResponse:
type: object
description: Error response for authentication failures
required:
- error
properties:
error:
type: string
description: Error message
example: "Client ID cannot be empty"
error_description:
type: string
description: Additional error detail
example: "Invalid or expired refresh token"
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
JWT token obtained from /auth/siwe/verify, /auth/register, or /auth/refresh.
Include in requests as: `Authorization: Bearer <access_token>`
security:
- bearerAuth: []
tags:
- name: Authentication
description: |
Endpoints for JWT-based authentication and authorization.
Use these endpoints to obtain and refresh access tokens for protected API endpoints.
Authentication is optional and configured per solver instance.