@0xmonaco/core 0.8.7 → 0.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/applications/api.d.ts +61 -8
- package/dist/api/applications/api.js +71 -7
- package/dist/api/auth/api.d.ts +44 -76
- package/dist/api/auth/api.js +61 -104
- package/dist/api/base.d.ts +48 -7
- package/dist/api/base.js +95 -12
- package/dist/api/delegated-agents/api.d.ts +2 -1
- package/dist/api/delegated-agents/api.js +4 -0
- package/dist/api/faucet/api.d.ts +25 -0
- package/dist/api/faucet/api.js +29 -0
- package/dist/api/faucet/index.d.ts +1 -0
- package/dist/api/faucet/index.js +1 -0
- package/dist/api/index.d.ts +4 -0
- package/dist/api/index.js +4 -0
- package/dist/api/margin-accounts/api.d.ts +3 -4
- package/dist/api/margin-accounts/api.js +8 -15
- package/dist/api/market/api.d.ts +3 -1
- package/dist/api/market/api.js +8 -0
- package/dist/api/orderbook/api.js +2 -1
- package/dist/api/perp/routes.d.ts +62 -4
- package/dist/api/perp/routes.js +27 -4
- package/dist/api/profile/api.d.ts +18 -1
- package/dist/api/profile/api.js +41 -1
- package/dist/api/sub-accounts/api.d.ts +62 -0
- package/dist/api/sub-accounts/api.js +80 -0
- package/dist/api/sub-accounts/index.d.ts +1 -0
- package/dist/api/sub-accounts/index.js +1 -0
- package/dist/api/trades/api.d.ts +12 -1
- package/dist/api/trades/api.js +13 -1
- package/dist/api/trading/api.d.ts +5 -2
- package/dist/api/trading/api.js +13 -27
- package/dist/api/websocket/types.d.ts +5 -5
- package/dist/api/websocket/websocket.js +43 -22
- package/dist/api/whitelist/api.d.ts +27 -0
- package/dist/api/whitelist/api.js +32 -0
- package/dist/api/whitelist/index.d.ts +1 -0
- package/dist/api/whitelist/index.js +1 -0
- package/dist/api/withdrawals/api.d.ts +15 -0
- package/dist/api/withdrawals/api.js +27 -0
- package/dist/api/withdrawals/index.d.ts +1 -0
- package/dist/api/withdrawals/index.js +1 -0
- package/dist/coverage.d.ts +85 -0
- package/dist/coverage.js +85 -0
- package/dist/crypto/session.d.ts +40 -0
- package/dist/crypto/session.js +60 -0
- package/dist/sdk.d.ts +56 -18
- package/dist/sdk.js +156 -53
- package/package.json +5 -3
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Applications API Implementation
|
|
3
3
|
*
|
|
4
|
-
* Handles application configuration operations.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* on the Monaco protocol.
|
|
4
|
+
* Handles application configuration and reporting operations. This is a
|
|
5
|
+
* mixed-auth domain: `getApplicationConfig` is session-authenticated, while
|
|
6
|
+
* the reporting methods are backend-authenticated via the application secret
|
|
7
|
+
* key (set with {@link BaseAPI.setServerKey}, sent as `x-server-key`).
|
|
9
8
|
*
|
|
10
9
|
* @example
|
|
11
10
|
* ```typescript
|
|
12
11
|
* const applicationsAPI = new ApplicationsAPIImpl(apiUrl);
|
|
13
12
|
*
|
|
14
|
-
* // Get application configuration
|
|
13
|
+
* // Get application configuration (session auth)
|
|
15
14
|
* const config = await applicationsAPI.getApplicationConfig();
|
|
16
15
|
* console.log(`App name: ${config.name}`);
|
|
17
|
-
*
|
|
16
|
+
*
|
|
17
|
+
* // Reporting endpoints (backend auth)
|
|
18
|
+
* applicationsAPI.setServerKey("sk_live_...");
|
|
19
|
+
* const orders = await applicationsAPI.listApplicationOrders({ status: "FILLED" });
|
|
18
20
|
* ```
|
|
19
21
|
*/
|
|
20
|
-
import type { ApplicationConfigResponse, ApplicationsAPI } from "@0xmonaco/types";
|
|
22
|
+
import type { ApplicationConfigResponse, ApplicationsAPI, GetAppStatsParams, GetAppStatsResponse, ListAppBalancesParams, ListAppBalancesResponse, ListAppMovementsParams, ListAppMovementsResponse, ListAppOrdersParams, ListAppOrdersResponse, ListAppUsersParams, ListAppUsersResponse } from "@0xmonaco/types";
|
|
21
23
|
import { BaseAPI } from "../base";
|
|
22
24
|
export declare class ApplicationsAPIImpl extends BaseAPI implements ApplicationsAPI {
|
|
23
25
|
/**
|
|
@@ -40,4 +42,55 @@ export declare class ApplicationsAPIImpl extends BaseAPI implements Applications
|
|
|
40
42
|
* ```
|
|
41
43
|
*/
|
|
42
44
|
getApplicationConfig(): Promise<ApplicationConfigResponse>;
|
|
45
|
+
/**
|
|
46
|
+
* Lists orders placed by the application's users.
|
|
47
|
+
*
|
|
48
|
+
* Backend-authenticated — call {@link BaseAPI.setServerKey} first.
|
|
49
|
+
*
|
|
50
|
+
* @param params - Pagination and filter options
|
|
51
|
+
* @returns Promise resolving to a paginated list of orders
|
|
52
|
+
* @throws {APIError} When the server key is unset or the request fails
|
|
53
|
+
*/
|
|
54
|
+
listApplicationOrders(params?: ListAppOrdersParams): Promise<ListAppOrdersResponse>;
|
|
55
|
+
/**
|
|
56
|
+
* Lists the application's users.
|
|
57
|
+
*
|
|
58
|
+
* Backend-authenticated — call {@link BaseAPI.setServerKey} first.
|
|
59
|
+
*
|
|
60
|
+
* @param params - Pagination and filter options
|
|
61
|
+
* @returns Promise resolving to a paginated list of users
|
|
62
|
+
* @throws {APIError} When the server key is unset or the request fails
|
|
63
|
+
*/
|
|
64
|
+
listApplicationUsers(params?: ListAppUsersParams): Promise<ListAppUsersResponse>;
|
|
65
|
+
/**
|
|
66
|
+
* Lists ledger movements for the application's users.
|
|
67
|
+
*
|
|
68
|
+
* Backend-authenticated — call {@link BaseAPI.setServerKey} first.
|
|
69
|
+
*
|
|
70
|
+
* @param params - Pagination and filter options
|
|
71
|
+
* @returns Promise resolving to a paginated list of movements
|
|
72
|
+
* @throws {APIError} When the server key is unset or the request fails
|
|
73
|
+
*/
|
|
74
|
+
listApplicationMovements(params?: ListAppMovementsParams): Promise<ListAppMovementsResponse>;
|
|
75
|
+
/**
|
|
76
|
+
* Lists user balances held within the application.
|
|
77
|
+
*
|
|
78
|
+
* Backend-authenticated — call {@link BaseAPI.setServerKey} first.
|
|
79
|
+
*
|
|
80
|
+
* @param params - Pagination and filter options
|
|
81
|
+
* @returns Promise resolving to a paginated list of balances
|
|
82
|
+
* @throws {APIError} When the server key is unset or the request fails
|
|
83
|
+
*/
|
|
84
|
+
listApplicationBalances(params?: ListAppBalancesParams): Promise<ListAppBalancesResponse>;
|
|
85
|
+
/**
|
|
86
|
+
* Gets aggregate volume and fee stats for the application.
|
|
87
|
+
*
|
|
88
|
+
* Stats are scoped to trades where the application's users were the taker.
|
|
89
|
+
* Backend-authenticated — call {@link BaseAPI.setServerKey} first.
|
|
90
|
+
*
|
|
91
|
+
* @param params - Optional `since` filter
|
|
92
|
+
* @returns Promise resolving to the application stats
|
|
93
|
+
* @throws {APIError} When the server key is unset or the request fails
|
|
94
|
+
*/
|
|
95
|
+
getApplicationStats(params?: GetAppStatsParams): Promise<GetAppStatsResponse>;
|
|
43
96
|
}
|
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Applications API Implementation
|
|
3
3
|
*
|
|
4
|
-
* Handles application configuration operations.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* on the Monaco protocol.
|
|
4
|
+
* Handles application configuration and reporting operations. This is a
|
|
5
|
+
* mixed-auth domain: `getApplicationConfig` is session-authenticated, while
|
|
6
|
+
* the reporting methods are backend-authenticated via the application secret
|
|
7
|
+
* key (set with {@link BaseAPI.setServerKey}, sent as `x-server-key`).
|
|
9
8
|
*
|
|
10
9
|
* @example
|
|
11
10
|
* ```typescript
|
|
12
11
|
* const applicationsAPI = new ApplicationsAPIImpl(apiUrl);
|
|
13
12
|
*
|
|
14
|
-
* // Get application configuration
|
|
13
|
+
* // Get application configuration (session auth)
|
|
15
14
|
* const config = await applicationsAPI.getApplicationConfig();
|
|
16
15
|
* console.log(`App name: ${config.name}`);
|
|
17
|
-
*
|
|
16
|
+
*
|
|
17
|
+
* // Reporting endpoints (backend auth)
|
|
18
|
+
* applicationsAPI.setServerKey("sk_live_...");
|
|
19
|
+
* const orders = await applicationsAPI.listApplicationOrders({ status: "FILLED" });
|
|
18
20
|
* ```
|
|
19
21
|
*/
|
|
20
22
|
import { BaseAPI } from "../base";
|
|
23
|
+
import { perpRoutes } from "../perp/routes";
|
|
21
24
|
export class ApplicationsAPIImpl extends BaseAPI {
|
|
22
25
|
/**
|
|
23
26
|
* Gets the configuration for the authenticated application.
|
|
@@ -51,4 +54,65 @@ export class ApplicationsAPIImpl extends BaseAPI {
|
|
|
51
54
|
clientId: data.client_id,
|
|
52
55
|
};
|
|
53
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Lists orders placed by the application's users.
|
|
59
|
+
*
|
|
60
|
+
* Backend-authenticated — call {@link BaseAPI.setServerKey} first.
|
|
61
|
+
*
|
|
62
|
+
* @param params - Pagination and filter options
|
|
63
|
+
* @returns Promise resolving to a paginated list of orders
|
|
64
|
+
* @throws {APIError} When the server key is unset or the request fails
|
|
65
|
+
*/
|
|
66
|
+
async listApplicationOrders(params) {
|
|
67
|
+
return await this.makeBackendRequest(perpRoutes.applications.orders(params));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Lists the application's users.
|
|
71
|
+
*
|
|
72
|
+
* Backend-authenticated — call {@link BaseAPI.setServerKey} first.
|
|
73
|
+
*
|
|
74
|
+
* @param params - Pagination and filter options
|
|
75
|
+
* @returns Promise resolving to a paginated list of users
|
|
76
|
+
* @throws {APIError} When the server key is unset or the request fails
|
|
77
|
+
*/
|
|
78
|
+
async listApplicationUsers(params) {
|
|
79
|
+
return await this.makeBackendRequest(perpRoutes.applications.users(params));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Lists ledger movements for the application's users.
|
|
83
|
+
*
|
|
84
|
+
* Backend-authenticated — call {@link BaseAPI.setServerKey} first.
|
|
85
|
+
*
|
|
86
|
+
* @param params - Pagination and filter options
|
|
87
|
+
* @returns Promise resolving to a paginated list of movements
|
|
88
|
+
* @throws {APIError} When the server key is unset or the request fails
|
|
89
|
+
*/
|
|
90
|
+
async listApplicationMovements(params) {
|
|
91
|
+
return await this.makeBackendRequest(perpRoutes.applications.movements(params));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Lists user balances held within the application.
|
|
95
|
+
*
|
|
96
|
+
* Backend-authenticated — call {@link BaseAPI.setServerKey} first.
|
|
97
|
+
*
|
|
98
|
+
* @param params - Pagination and filter options
|
|
99
|
+
* @returns Promise resolving to a paginated list of balances
|
|
100
|
+
* @throws {APIError} When the server key is unset or the request fails
|
|
101
|
+
*/
|
|
102
|
+
async listApplicationBalances(params) {
|
|
103
|
+
return await this.makeBackendRequest(perpRoutes.applications.balances(params));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Gets aggregate volume and fee stats for the application.
|
|
107
|
+
*
|
|
108
|
+
* Stats are scoped to trades where the application's users were the taker.
|
|
109
|
+
* Backend-authenticated — call {@link BaseAPI.setServerKey} first.
|
|
110
|
+
*
|
|
111
|
+
* @param params - Optional `since` filter
|
|
112
|
+
* @returns Promise resolving to the application stats
|
|
113
|
+
* @throws {APIError} When the server key is unset or the request fails
|
|
114
|
+
*/
|
|
115
|
+
async getApplicationStats(params) {
|
|
116
|
+
return await this.makeBackendRequest(perpRoutes.applications.stats(params));
|
|
117
|
+
}
|
|
54
118
|
}
|
package/dist/api/auth/api.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auth API Implementation
|
|
3
3
|
*
|
|
4
|
-
* Handles authentication operations including challenge creation, signature
|
|
5
|
-
* and
|
|
4
|
+
* Handles wallet authentication operations including challenge creation, signature
|
|
5
|
+
* verification, and session lifecycle. All operations go through the API Gateway.
|
|
6
6
|
*
|
|
7
|
-
* This class provides a complete interface for authentication on the
|
|
8
|
-
*
|
|
7
|
+
* This class provides a complete interface for wallet-based authentication on the
|
|
8
|
+
* Monaco protocol. Backend services authenticate separately by setting their
|
|
9
|
+
* application secret key (`sk_...`) via {@link BaseAPI.setServerKey}, which is sent
|
|
10
|
+
* in the `x-server-key` header on backend requests — there is no token exchange.
|
|
9
11
|
*
|
|
10
12
|
* @example
|
|
11
13
|
* ```typescript
|
|
@@ -23,12 +25,9 @@
|
|
|
23
25
|
* challenge.nonce,
|
|
24
26
|
* clientId
|
|
25
27
|
* );
|
|
26
|
-
*
|
|
27
|
-
* // Authenticate backend service
|
|
28
|
-
* const backendAuth = await authAPI.authenticateBackend(secretKey);
|
|
29
28
|
* ```
|
|
30
29
|
*/
|
|
31
|
-
import type { AuthAPI, AuthState,
|
|
30
|
+
import type { AuthAPI, AuthState, ChallengeResponse, SessionCredentials, SessionRefreshResponse } from "@0xmonaco/types";
|
|
32
31
|
import type { Chain, WalletClient } from "viem";
|
|
33
32
|
import { BaseAPI } from "../base";
|
|
34
33
|
export declare class AuthAPIImpl extends BaseAPI implements AuthAPI {
|
|
@@ -51,20 +50,24 @@ export declare class AuthAPIImpl extends BaseAPI implements AuthAPI {
|
|
|
51
50
|
* Complete authentication flow for frontend applications.
|
|
52
51
|
*
|
|
53
52
|
* This method handles the entire authentication process:
|
|
54
|
-
* 1.
|
|
55
|
-
* 2.
|
|
56
|
-
* 3.
|
|
53
|
+
* 1. Generates a fresh ed25519 session keypair locally
|
|
54
|
+
* 2. Creates a challenge that commits to the session public key
|
|
55
|
+
* 3. Signs the challenge message with the wallet
|
|
56
|
+
* 4. Verifies the signature, registering the session public key
|
|
57
|
+
*
|
|
58
|
+
* The returned {@link AuthState} carries the session keypair; sign subsequent
|
|
59
|
+
* requests with the private key (the wallet is not used again until the
|
|
60
|
+
* session expires).
|
|
57
61
|
*
|
|
58
62
|
* @param clientId - Client ID of the application
|
|
59
|
-
* @returns Promise resolving to the
|
|
63
|
+
* @returns Promise resolving to the authentication state (with the session keypair)
|
|
60
64
|
* @throws {APIError} When authentication fails
|
|
61
65
|
* @throws {InvalidConfigError} When wallet account is not available
|
|
62
66
|
*
|
|
63
67
|
* @example
|
|
64
68
|
* ```typescript
|
|
65
|
-
* // Complete authentication in one call
|
|
66
69
|
* const authResult = await authAPI.authenticate("my-app-client-id");
|
|
67
|
-
* console.log(`
|
|
70
|
+
* console.log(`Session public key: ${authResult.sessionPublicKey}`);
|
|
68
71
|
* console.log(`User ID: ${authResult.user.id}`);
|
|
69
72
|
* ```
|
|
70
73
|
*/
|
|
@@ -109,7 +112,7 @@ export declare class AuthAPIImpl extends BaseAPI implements AuthAPI {
|
|
|
109
112
|
* console.log(`Nonce: ${challenge.nonce}`);
|
|
110
113
|
* ```
|
|
111
114
|
*/
|
|
112
|
-
createChallenge(address: string, clientId: string): Promise<ChallengeResponse>;
|
|
115
|
+
createChallenge(address: string, clientId: string, sessionPublicKey: string): Promise<ChallengeResponse>;
|
|
113
116
|
/**
|
|
114
117
|
* Verifies a signature for frontend authentication.
|
|
115
118
|
*
|
|
@@ -117,90 +120,55 @@ export declare class AuthAPIImpl extends BaseAPI implements AuthAPI {
|
|
|
117
120
|
* authenticated API access. This is the second step in the authentication flow.
|
|
118
121
|
*
|
|
119
122
|
* @param address - Wallet address of the user
|
|
120
|
-
* @param signature -
|
|
123
|
+
* @param signature - Wallet signature of the challenge message
|
|
121
124
|
* @param nonce - Nonce from the challenge response
|
|
122
125
|
* @param clientId - Client ID of the application
|
|
123
|
-
* @
|
|
126
|
+
* @param session - The locally-generated session keypair (hex-encoded)
|
|
127
|
+
* @returns Promise resolving to the authentication state (with the session keypair)
|
|
124
128
|
* @throws {APIError} When signature verification fails
|
|
125
129
|
*
|
|
126
130
|
* @example
|
|
127
131
|
* ```typescript
|
|
128
|
-
*
|
|
129
|
-
* const
|
|
130
|
-
*
|
|
131
|
-
* // User signs the challenge message with their wallet
|
|
132
|
+
* const keypair = generateSessionKeypair();
|
|
133
|
+
* const session = { publicKey: publicKeyHex(keypair), privateKey: privateKeyHex(keypair) };
|
|
134
|
+
* const challenge = await authAPI.createChallenge(address, clientId, session.publicKey);
|
|
132
135
|
* const signature = await wallet.signMessage(challenge.message);
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* const authResult = await authAPI.verifySignature(
|
|
136
|
-
* address,
|
|
137
|
-
* signature,
|
|
138
|
-
* challenge.nonce,
|
|
139
|
-
* clientId
|
|
140
|
-
* );
|
|
141
|
-
*
|
|
142
|
-
* console.log(`Access token: ${authResult.accessToken}`);
|
|
143
|
-
* console.log(`User ID: ${authResult.user.id}`);
|
|
136
|
+
* const authResult = await authAPI.verifySignature(address, signature, challenge.nonce, clientId, session);
|
|
137
|
+
* console.log(`Session public key: ${authResult.sessionPublicKey}`);
|
|
144
138
|
* ```
|
|
145
139
|
*/
|
|
146
|
-
verifySignature(address: string, signature: string, nonce: string, clientId: string): Promise<AuthState>;
|
|
140
|
+
verifySignature(address: string, signature: string, nonce: string, clientId: string, session: SessionCredentials): Promise<AuthState>;
|
|
147
141
|
/**
|
|
148
|
-
*
|
|
142
|
+
* Extends the current session's expiry.
|
|
149
143
|
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
144
|
+
* The request is signed with the active session key (set via
|
|
145
|
+
* {@link setSessionKeypair}); the server bumps the session's `expires_at`.
|
|
146
|
+
* No new credential is issued — the same keypair keeps working.
|
|
152
147
|
*
|
|
153
|
-
* @
|
|
154
|
-
* @
|
|
155
|
-
* @throws {APIError} When backend authentication fails
|
|
148
|
+
* @returns Promise resolving to the new expiry
|
|
149
|
+
* @throws {APIError} When refresh fails (e.g. session expired or revoked)
|
|
156
150
|
*
|
|
157
151
|
* @example
|
|
158
152
|
* ```typescript
|
|
159
|
-
* const
|
|
160
|
-
* console.log(`
|
|
161
|
-
* console.log(`Application: ${backendAuth.application.name}`);
|
|
153
|
+
* const { expiresAt } = await authAPI.refreshSession();
|
|
154
|
+
* console.log(`Session now expires at: ${new Date(expiresAt * 1000)}`);
|
|
162
155
|
* ```
|
|
163
156
|
*/
|
|
164
|
-
|
|
157
|
+
refreshSession(): Promise<SessionRefreshResponse>;
|
|
165
158
|
/**
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* Obtains a new access token using a valid refresh token. This is useful for
|
|
169
|
-
* maintaining long-term authentication without requiring the user to sign
|
|
170
|
-
* a new challenge.
|
|
171
|
-
*
|
|
172
|
-
* @param refreshToken - The refresh token to use
|
|
173
|
-
* @returns Promise resolving to new access and refresh tokens
|
|
174
|
-
* @throws {APIError} When token refresh fails
|
|
175
|
-
*
|
|
176
|
-
* @example
|
|
177
|
-
* ```typescript
|
|
178
|
-
* const newTokens = await authAPI.refreshToken(refreshToken);
|
|
179
|
-
* console.log(`New access token: ${newTokens.accessToken}`);
|
|
180
|
-
* console.log(`Expires at: ${new Date(newTokens.expiresAt * 1000)}`);
|
|
181
|
-
* ```
|
|
182
|
-
*/
|
|
183
|
-
refreshToken(refreshToken: string): Promise<TokenRefreshResponse>;
|
|
184
|
-
/**
|
|
185
|
-
* Revokes the current session's refresh token.
|
|
186
|
-
*
|
|
187
|
-
* Invalidates the refresh token associated with the current access token,
|
|
188
|
-
* preventing it from being used to obtain new access tokens. This is useful
|
|
189
|
-
* for logout functionality or when a token has been compromised.
|
|
159
|
+
* Revokes the current session.
|
|
190
160
|
*
|
|
191
|
-
* The
|
|
192
|
-
*
|
|
161
|
+
* The request is signed with the active session key; the server deletes the
|
|
162
|
+
* matching session row. Used for logout or when a key may be compromised.
|
|
193
163
|
*
|
|
194
|
-
* @returns Promise resolving when the
|
|
195
|
-
* @throws {APIError} When
|
|
164
|
+
* @returns Promise resolving when the session is revoked
|
|
165
|
+
* @throws {APIError} When revocation fails
|
|
196
166
|
*
|
|
197
167
|
* @example
|
|
198
168
|
* ```typescript
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
* await authAPI.revokeToken();
|
|
202
|
-
* console.log("Token revoked successfully");
|
|
169
|
+
* await authAPI.revokeSession();
|
|
170
|
+
* console.log("Session revoked successfully");
|
|
203
171
|
* ```
|
|
204
172
|
*/
|
|
205
|
-
|
|
173
|
+
revokeSession(): Promise<void>;
|
|
206
174
|
}
|
package/dist/api/auth/api.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auth API Implementation
|
|
3
3
|
*
|
|
4
|
-
* Handles authentication operations including challenge creation, signature
|
|
5
|
-
* and
|
|
4
|
+
* Handles wallet authentication operations including challenge creation, signature
|
|
5
|
+
* verification, and session lifecycle. All operations go through the API Gateway.
|
|
6
6
|
*
|
|
7
|
-
* This class provides a complete interface for authentication on the
|
|
8
|
-
*
|
|
7
|
+
* This class provides a complete interface for wallet-based authentication on the
|
|
8
|
+
* Monaco protocol. Backend services authenticate separately by setting their
|
|
9
|
+
* application secret key (`sk_...`) via {@link BaseAPI.setServerKey}, which is sent
|
|
10
|
+
* in the `x-server-key` header on backend requests — there is no token exchange.
|
|
9
11
|
*
|
|
10
12
|
* @example
|
|
11
13
|
* ```typescript
|
|
@@ -23,11 +25,9 @@
|
|
|
23
25
|
* challenge.nonce,
|
|
24
26
|
* clientId
|
|
25
27
|
* );
|
|
26
|
-
*
|
|
27
|
-
* // Authenticate backend service
|
|
28
|
-
* const backendAuth = await authAPI.authenticateBackend(secretKey);
|
|
29
28
|
* ```
|
|
30
29
|
*/
|
|
30
|
+
import { generateSessionKeypair, privateKeyHex, publicKeyHex } from "../../crypto/session";
|
|
31
31
|
import { InvalidConfigError } from "../../errors";
|
|
32
32
|
import { BaseAPI } from "../base";
|
|
33
33
|
export class AuthAPIImpl extends BaseAPI {
|
|
@@ -56,20 +56,24 @@ export class AuthAPIImpl extends BaseAPI {
|
|
|
56
56
|
* Complete authentication flow for frontend applications.
|
|
57
57
|
*
|
|
58
58
|
* This method handles the entire authentication process:
|
|
59
|
-
* 1.
|
|
60
|
-
* 2.
|
|
61
|
-
* 3.
|
|
59
|
+
* 1. Generates a fresh ed25519 session keypair locally
|
|
60
|
+
* 2. Creates a challenge that commits to the session public key
|
|
61
|
+
* 3. Signs the challenge message with the wallet
|
|
62
|
+
* 4. Verifies the signature, registering the session public key
|
|
63
|
+
*
|
|
64
|
+
* The returned {@link AuthState} carries the session keypair; sign subsequent
|
|
65
|
+
* requests with the private key (the wallet is not used again until the
|
|
66
|
+
* session expires).
|
|
62
67
|
*
|
|
63
68
|
* @param clientId - Client ID of the application
|
|
64
|
-
* @returns Promise resolving to the
|
|
69
|
+
* @returns Promise resolving to the authentication state (with the session keypair)
|
|
65
70
|
* @throws {APIError} When authentication fails
|
|
66
71
|
* @throws {InvalidConfigError} When wallet account is not available
|
|
67
72
|
*
|
|
68
73
|
* @example
|
|
69
74
|
* ```typescript
|
|
70
|
-
* // Complete authentication in one call
|
|
71
75
|
* const authResult = await authAPI.authenticate("my-app-client-id");
|
|
72
|
-
* console.log(`
|
|
76
|
+
* console.log(`Session public key: ${authResult.sessionPublicKey}`);
|
|
73
77
|
* console.log(`User ID: ${authResult.user.id}`);
|
|
74
78
|
* ```
|
|
75
79
|
*/
|
|
@@ -81,12 +85,19 @@ export class AuthAPIImpl extends BaseAPI {
|
|
|
81
85
|
if (!account) {
|
|
82
86
|
throw new InvalidConfigError("No account available in wallet client", "account");
|
|
83
87
|
}
|
|
84
|
-
// 1.
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
// 1. Generate a fresh session keypair locally — the server never sees the
|
|
89
|
+
// private key.
|
|
90
|
+
const keypair = generateSessionKeypair();
|
|
91
|
+
const session = {
|
|
92
|
+
publicKey: publicKeyHex(keypair),
|
|
93
|
+
privateKey: privateKeyHex(keypair),
|
|
94
|
+
};
|
|
95
|
+
// 2. Create challenge (binds the session public key into the signed message)
|
|
96
|
+
const challenge = await this.createChallenge(account.address, clientId, session.publicKey);
|
|
97
|
+
// 3. Sign the challenge message with the wallet
|
|
87
98
|
const signature = await this.signChallenge(challenge.message);
|
|
88
|
-
//
|
|
89
|
-
return await this.verifySignature(account.address, signature, challenge.nonce, clientId);
|
|
99
|
+
// 4. Verify signature, registering the session public key
|
|
100
|
+
return await this.verifySignature(account.address, signature, challenge.nonce, clientId, session);
|
|
90
101
|
}
|
|
91
102
|
/**
|
|
92
103
|
* Signs a challenge message using the wallet client.
|
|
@@ -141,13 +152,14 @@ export class AuthAPIImpl extends BaseAPI {
|
|
|
141
152
|
* console.log(`Nonce: ${challenge.nonce}`);
|
|
142
153
|
* ```
|
|
143
154
|
*/
|
|
144
|
-
async createChallenge(address, clientId) {
|
|
155
|
+
async createChallenge(address, clientId, sessionPublicKey) {
|
|
145
156
|
const responseBody = await this.makePublicRequest("/api/v1/auth/challenge", {
|
|
146
157
|
method: "POST",
|
|
147
158
|
body: JSON.stringify({
|
|
148
159
|
address,
|
|
149
160
|
client_id: clientId,
|
|
150
161
|
chain_id: this.chain.id,
|
|
162
|
+
session_public_key: sessionPublicKey,
|
|
151
163
|
}),
|
|
152
164
|
});
|
|
153
165
|
return {
|
|
@@ -163,33 +175,24 @@ export class AuthAPIImpl extends BaseAPI {
|
|
|
163
175
|
* authenticated API access. This is the second step in the authentication flow.
|
|
164
176
|
*
|
|
165
177
|
* @param address - Wallet address of the user
|
|
166
|
-
* @param signature -
|
|
178
|
+
* @param signature - Wallet signature of the challenge message
|
|
167
179
|
* @param nonce - Nonce from the challenge response
|
|
168
180
|
* @param clientId - Client ID of the application
|
|
169
|
-
* @
|
|
181
|
+
* @param session - The locally-generated session keypair (hex-encoded)
|
|
182
|
+
* @returns Promise resolving to the authentication state (with the session keypair)
|
|
170
183
|
* @throws {APIError} When signature verification fails
|
|
171
184
|
*
|
|
172
185
|
* @example
|
|
173
186
|
* ```typescript
|
|
174
|
-
*
|
|
175
|
-
* const
|
|
176
|
-
*
|
|
177
|
-
* // User signs the challenge message with their wallet
|
|
187
|
+
* const keypair = generateSessionKeypair();
|
|
188
|
+
* const session = { publicKey: publicKeyHex(keypair), privateKey: privateKeyHex(keypair) };
|
|
189
|
+
* const challenge = await authAPI.createChallenge(address, clientId, session.publicKey);
|
|
178
190
|
* const signature = await wallet.signMessage(challenge.message);
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
* const authResult = await authAPI.verifySignature(
|
|
182
|
-
* address,
|
|
183
|
-
* signature,
|
|
184
|
-
* challenge.nonce,
|
|
185
|
-
* clientId
|
|
186
|
-
* );
|
|
187
|
-
*
|
|
188
|
-
* console.log(`Access token: ${authResult.accessToken}`);
|
|
189
|
-
* console.log(`User ID: ${authResult.user.id}`);
|
|
191
|
+
* const authResult = await authAPI.verifySignature(address, signature, challenge.nonce, clientId, session);
|
|
192
|
+
* console.log(`Session public key: ${authResult.sessionPublicKey}`);
|
|
190
193
|
* ```
|
|
191
194
|
*/
|
|
192
|
-
async verifySignature(address, signature, nonce, clientId) {
|
|
195
|
+
async verifySignature(address, signature, nonce, clientId, session) {
|
|
193
196
|
const responseBody = await this.makePublicRequest("/api/v1/auth/verify", {
|
|
194
197
|
method: "POST",
|
|
195
198
|
body: JSON.stringify({
|
|
@@ -198,11 +201,12 @@ export class AuthAPIImpl extends BaseAPI {
|
|
|
198
201
|
nonce,
|
|
199
202
|
client_id: clientId,
|
|
200
203
|
chain_id: this.chain.id,
|
|
204
|
+
session_public_key: session.publicKey,
|
|
201
205
|
}),
|
|
202
206
|
});
|
|
203
207
|
return {
|
|
204
|
-
|
|
205
|
-
|
|
208
|
+
sessionPublicKey: session.publicKey,
|
|
209
|
+
sessionPrivateKey: session.privateKey,
|
|
206
210
|
expiresAt: responseBody.expires_at,
|
|
207
211
|
user: {
|
|
208
212
|
id: responseBody.user.id,
|
|
@@ -212,92 +216,45 @@ export class AuthAPIImpl extends BaseAPI {
|
|
|
212
216
|
};
|
|
213
217
|
}
|
|
214
218
|
/**
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
* Returns JWT tokens for API access. This method is used for backend services
|
|
218
|
-
* that need to authenticate with the Monaco API Gateway.
|
|
219
|
-
*
|
|
220
|
-
* @param secretKey - Secret key of the application
|
|
221
|
-
* @returns Promise resolving to the backend auth response with JWT tokens
|
|
222
|
-
* @throws {APIError} When backend authentication fails
|
|
223
|
-
*
|
|
224
|
-
* @example
|
|
225
|
-
* ```typescript
|
|
226
|
-
* const backendAuth = await authAPI.authenticateBackend("my-secret-key");
|
|
227
|
-
* console.log(`Backend access token: ${backendAuth.accessToken}`);
|
|
228
|
-
* console.log(`Application: ${backendAuth.application.name}`);
|
|
229
|
-
* ```
|
|
230
|
-
*/
|
|
231
|
-
async authenticateBackend(secretKey) {
|
|
232
|
-
const responseBody = await this.makePublicRequest("/api/v1/auth/backend", {
|
|
233
|
-
method: "POST",
|
|
234
|
-
body: JSON.stringify({
|
|
235
|
-
secret_key: secretKey,
|
|
236
|
-
chain_id: this.chain.id,
|
|
237
|
-
}),
|
|
238
|
-
});
|
|
239
|
-
return {
|
|
240
|
-
accessToken: responseBody.access_token,
|
|
241
|
-
expiresAt: responseBody.expires_at,
|
|
242
|
-
application: {
|
|
243
|
-
id: responseBody.application.id,
|
|
244
|
-
name: responseBody.application.name,
|
|
245
|
-
clientId: responseBody.application.client_id,
|
|
246
|
-
},
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Refreshes an access token using a refresh token.
|
|
219
|
+
* Extends the current session's expiry.
|
|
251
220
|
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
221
|
+
* The request is signed with the active session key (set via
|
|
222
|
+
* {@link setSessionKeypair}); the server bumps the session's `expires_at`.
|
|
223
|
+
* No new credential is issued — the same keypair keeps working.
|
|
255
224
|
*
|
|
256
|
-
* @
|
|
257
|
-
* @
|
|
258
|
-
* @throws {APIError} When token refresh fails
|
|
225
|
+
* @returns Promise resolving to the new expiry
|
|
226
|
+
* @throws {APIError} When refresh fails (e.g. session expired or revoked)
|
|
259
227
|
*
|
|
260
228
|
* @example
|
|
261
229
|
* ```typescript
|
|
262
|
-
* const
|
|
263
|
-
* console.log(`
|
|
264
|
-
* console.log(`Expires at: ${new Date(newTokens.expiresAt * 1000)}`);
|
|
230
|
+
* const { expiresAt } = await authAPI.refreshSession();
|
|
231
|
+
* console.log(`Session now expires at: ${new Date(expiresAt * 1000)}`);
|
|
265
232
|
* ```
|
|
266
233
|
*/
|
|
267
|
-
async
|
|
268
|
-
const responseBody = await this.
|
|
234
|
+
async refreshSession() {
|
|
235
|
+
const responseBody = await this.makeAuthenticatedRequest("/api/v1/auth/refresh", {
|
|
269
236
|
method: "POST",
|
|
270
|
-
body: JSON.stringify({
|
|
271
|
-
refresh_token: refreshToken,
|
|
272
|
-
}),
|
|
273
237
|
});
|
|
274
238
|
return {
|
|
275
|
-
accessToken: responseBody.access_token,
|
|
276
239
|
expiresAt: responseBody.expires_at,
|
|
277
240
|
};
|
|
278
241
|
}
|
|
279
242
|
/**
|
|
280
|
-
* Revokes the current session
|
|
281
|
-
*
|
|
282
|
-
* Invalidates the refresh token associated with the current access token,
|
|
283
|
-
* preventing it from being used to obtain new access tokens. This is useful
|
|
284
|
-
* for logout functionality or when a token has been compromised.
|
|
243
|
+
* Revokes the current session.
|
|
285
244
|
*
|
|
286
|
-
* The
|
|
287
|
-
*
|
|
245
|
+
* The request is signed with the active session key; the server deletes the
|
|
246
|
+
* matching session row. Used for logout or when a key may be compromised.
|
|
288
247
|
*
|
|
289
|
-
* @returns Promise resolving when the
|
|
290
|
-
* @throws {APIError} When
|
|
248
|
+
* @returns Promise resolving when the session is revoked
|
|
249
|
+
* @throws {APIError} When revocation fails
|
|
291
250
|
*
|
|
292
251
|
* @example
|
|
293
252
|
* ```typescript
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
* await authAPI.revokeToken();
|
|
297
|
-
* console.log("Token revoked successfully");
|
|
253
|
+
* await authAPI.revokeSession();
|
|
254
|
+
* console.log("Session revoked successfully");
|
|
298
255
|
* ```
|
|
299
256
|
*/
|
|
300
|
-
async
|
|
257
|
+
async revokeSession() {
|
|
301
258
|
await this.makeAuthenticatedRequest("/api/v1/auth/revoke", {
|
|
302
259
|
method: "POST",
|
|
303
260
|
});
|