@0xmonaco/react 0.8.4 → 0.8.7-develop.0e951a5

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.
@@ -1,4 +1,4 @@
1
- import type { AuthState, ChallengeResponse, TokenRefreshResponse } from "@0xmonaco/types";
1
+ import type { AuthState, ChallengeResponse, SessionRefreshResponse } from "@0xmonaco/types";
2
2
  import type { AuthenticationStatus } from "../../provider";
3
3
  export interface UseAuthState {
4
4
  /** Current authentication status */
@@ -6,25 +6,30 @@ export interface UseAuthState {
6
6
  }
7
7
  export interface UseAuthReturn extends UseAuthState {
8
8
  /**
9
- * Complete authentication flow. Returns AuthState with accessToken and refreshToken.
9
+ * Complete authentication flow. Generates a session keypair, has the wallet
10
+ * authorize it, and returns the AuthState (including the session keypair).
10
11
  * @param options - Optional configuration
11
12
  * @param options.connectWebSocket - Auto-connect all authenticated WebSocket channels after login (currently Orders) (default: false)
12
13
  */
13
14
  login: (options?: {
14
15
  connectWebSocket?: boolean;
15
16
  }) => Promise<AuthState>;
16
- /** Logout user and clear state. Revokes the refresh token on the server. */
17
+ /** Logout user and clear state. Revokes the session on the server. */
17
18
  logout: () => Promise<void>;
18
- /** Refresh authentication tokens using the stored refresh token. */
19
+ /** Refresh the current session, extending its expiry. */
19
20
  refreshAuth: () => Promise<AuthState>;
20
21
  /** Sign a challenge message with the connected wallet. */
21
22
  signChallenge: (message: string) => Promise<string>;
22
- /** Create authentication challenge for the given address. */
23
- createChallenge: (address: string) => Promise<ChallengeResponse>;
24
- /** Complete authentication with signature. Returns tokens. */
23
+ /**
24
+ * Create an authentication challenge for the given address, binding the
25
+ * provided session public key. Advanced/manual flow — most callers should
26
+ * use `login`/`authenticate`, which manage the keypair for you.
27
+ */
28
+ createChallenge: (address: string, sessionPublicKey: string) => Promise<ChallengeResponse>;
29
+ /** Complete authentication with signature. Returns the AuthState. */
25
30
  authenticate: () => Promise<AuthState>;
26
- /** Refresh access token. Pass the refreshToken from authState. */
27
- refreshToken: (refreshToken: string) => Promise<TokenRefreshResponse>;
28
- /** Revoke the current session's refresh token on the server. */
29
- revokeToken: () => Promise<void>;
31
+ /** Extend the current session's expiry (signed with the active session key). */
32
+ refreshSession: () => Promise<SessionRefreshResponse>;
33
+ /** Revoke the current session on the server. */
34
+ revokeSession: () => Promise<void>;
30
35
  }
@@ -65,14 +65,16 @@ export const useAuth = () => {
65
65
  throw new Error("Message is required and cannot be empty");
66
66
  return await sdk.auth.signChallenge(message);
67
67
  }, [sdk]);
68
- const createChallenge = useCallback(async (address) => {
68
+ const createChallenge = useCallback(async (address, sessionPublicKey) => {
69
69
  if (!sdk)
70
70
  throw new Error("SDK not available");
71
71
  if (!address?.trim())
72
72
  throw new Error("Address is required and cannot be empty");
73
+ if (!sessionPublicKey?.trim())
74
+ throw new Error("Session public key is required and cannot be empty");
73
75
  if (!clientId?.trim())
74
76
  throw new Error("Client ID is required and cannot be empty");
75
- return await sdk.auth.createChallenge(address, clientId);
77
+ return await sdk.auth.createChallenge(address, clientId, sessionPublicKey);
76
78
  }, [sdk, clientId]);
77
79
  const authenticate = useCallback(async () => {
78
80
  if (!sdk)
@@ -84,26 +86,19 @@ export const useAuth = () => {
84
86
  const result = await sdk.auth.authenticate(clientId);
85
87
  const authenticated = sdk.isAuthenticated();
86
88
  setAuthenticationStatus(authenticated ? AuthenticationStatus.AUTHENTICATED : AuthenticationStatus.UNAUTHENTICATED);
87
- return {
88
- accessToken: result.accessToken,
89
- refreshToken: result.refreshToken,
90
- expiresAt: result.expiresAt,
91
- user: result.user,
92
- };
89
+ return result;
93
90
  }
94
91
  catch (error) {
95
92
  setAuthenticationStatus(AuthenticationStatus.UNAUTHENTICATED);
96
93
  throw error;
97
94
  }
98
95
  }, [sdk, clientId, setAuthenticationStatus]);
99
- const refreshToken = useCallback(async (token) => {
96
+ const refreshSession = useCallback(async () => {
100
97
  if (!sdk)
101
98
  throw new Error("SDK not available");
102
- if (!token?.trim())
103
- throw new Error("Refresh token is required and cannot be empty");
104
99
  setAuthenticationStatus(AuthenticationStatus.AUTHENTICATING);
105
100
  try {
106
- const result = await sdk.auth.refreshToken(token);
101
+ const result = await sdk.auth.refreshSession();
107
102
  const authenticated = sdk.isAuthenticated();
108
103
  setAuthenticationStatus(authenticated ? AuthenticationStatus.AUTHENTICATED : AuthenticationStatus.UNAUTHENTICATED);
109
104
  return result;
@@ -113,12 +108,12 @@ export const useAuth = () => {
113
108
  throw error;
114
109
  }
115
110
  }, [sdk, setAuthenticationStatus]);
116
- const revokeToken = useCallback(async () => {
111
+ const revokeSession = useCallback(async () => {
117
112
  if (!sdk)
118
113
  throw new Error("SDK not available");
119
114
  setAuthenticationStatus(AuthenticationStatus.AUTHENTICATING);
120
115
  try {
121
- await sdk.auth.revokeToken();
116
+ await sdk.auth.revokeSession();
122
117
  const authenticated = sdk.isAuthenticated();
123
118
  setAuthenticationStatus(authenticated ? AuthenticationStatus.AUTHENTICATED : AuthenticationStatus.UNAUTHENTICATED);
124
119
  }
@@ -133,10 +128,10 @@ export const useAuth = () => {
133
128
  // Primary auth actions
134
129
  login,
135
130
  logout,
136
- // Token management
131
+ // Session management
137
132
  refreshAuth,
138
- refreshToken,
139
- revokeToken,
133
+ refreshSession,
134
+ revokeSession,
140
135
  // Low-level auth functions
141
136
  authenticate,
142
137
  signChallenge,
@@ -53,8 +53,8 @@ export const useTokenLifecycle = (sdk, config = {}) => {
53
53
  return refreshPromiseRef.current;
54
54
  }
55
55
  const currentAuthState = currentAuthStateRef.current;
56
- if (!currentAuthState?.refreshToken) {
57
- console.warn("No refresh token available for token refresh");
56
+ if (!currentAuthState) {
57
+ console.warn("No active session available for refresh");
58
58
  return null;
59
59
  }
60
60
  const refreshPromise = (async () => {
@@ -75,7 +75,7 @@ export function useUserMovements(options = {}) {
75
75
  sdk.profile
76
76
  .getPaginatedUserMovements({ page_size: requestLimit, entry_type, transaction_type, asset_id })
77
77
  .then(async (response) => {
78
- // Combine latest_movements (from Redis) with movements (from PostgreSQL)
78
+ // Combine latest_movements (from the live engine cache) with movements (from PostgreSQL)
79
79
  // latest_movements contains real-time data that may not yet be in PostgreSQL
80
80
  // Deduplicate by id, preferring latest_movements (newer data)
81
81
  const latestMovements = (response.latest_movements || []).map((m) => ledgerMovementToEvent(m, userId));
@@ -25,7 +25,7 @@ export function useUserOrders(maxOrders = 50) {
25
25
  page: 1,
26
26
  page_size: maxOrders,
27
27
  });
28
- // Combine latest_orders (from Redis) with orders (from PostgreSQL)
28
+ // Combine latest_orders (from the live engine cache) with orders (from PostgreSQL)
29
29
  // latest_orders contains real-time data that may not yet be in PostgreSQL
30
30
  // Deduplicate by id, preferring latest_orders (newer data)
31
31
  const latestOrders = response.latest_orders || [];
@@ -2,14 +2,18 @@ import type { AuthState } from "@0xmonaco/types";
2
2
  /**
3
3
  * Save auth state to localStorage
4
4
  *
5
- * @security This function stores authentication tokens (including refresh tokens) in localStorage,
6
- * which is accessible to any JavaScript running on the page. This makes tokens vulnerable to XSS attacks.
5
+ * @security This function stores the session keypair (including the private
6
+ * key) in localStorage, which is accessible to any JavaScript running on the
7
+ * page. This is the same XSS exposure as the previous JWT-based scheme — an
8
+ * attacker who can read localStorage can act as the user until the session
9
+ * expires either way.
7
10
  *
8
11
  * Security recommendations:
9
12
  * - Implement Content Security Policy (CSP) headers to mitigate XSS risks
10
13
  * - Sanitize all user input to prevent XSS vulnerabilities
11
14
  * - Consider the tradeoffs: localStorage provides persistence across sessions but sacrifices XSS protection
12
- * - For high-security requirements, consider httpOnly cookies (requires backend changes)
15
+ * - For higher-security requirements, back the session key with a
16
+ * non-extractable WebCrypto key (out of scope for this default helper)
13
17
  *
14
18
  * @param authState - The authentication state to persist
15
19
  */
@@ -5,22 +5,26 @@ const STORAGE_KEY = "monaco_auth_state";
5
5
  /**
6
6
  * Save auth state to localStorage
7
7
  *
8
- * @security This function stores authentication tokens (including refresh tokens) in localStorage,
9
- * which is accessible to any JavaScript running on the page. This makes tokens vulnerable to XSS attacks.
8
+ * @security This function stores the session keypair (including the private
9
+ * key) in localStorage, which is accessible to any JavaScript running on the
10
+ * page. This is the same XSS exposure as the previous JWT-based scheme — an
11
+ * attacker who can read localStorage can act as the user until the session
12
+ * expires either way.
10
13
  *
11
14
  * Security recommendations:
12
15
  * - Implement Content Security Policy (CSP) headers to mitigate XSS risks
13
16
  * - Sanitize all user input to prevent XSS vulnerabilities
14
17
  * - Consider the tradeoffs: localStorage provides persistence across sessions but sacrifices XSS protection
15
- * - For high-security requirements, consider httpOnly cookies (requires backend changes)
18
+ * - For higher-security requirements, back the session key with a
19
+ * non-extractable WebCrypto key (out of scope for this default helper)
16
20
  *
17
21
  * @param authState - The authentication state to persist
18
22
  */
19
23
  export function saveAuthState(authState) {
20
24
  try {
21
25
  const data = JSON.stringify({
22
- accessToken: authState.accessToken,
23
- refreshToken: authState.refreshToken,
26
+ sessionPublicKey: authState.sessionPublicKey,
27
+ sessionPrivateKey: authState.sessionPrivateKey,
24
28
  expiresAt: authState.expiresAt,
25
29
  user: authState.user,
26
30
  });
@@ -41,10 +45,10 @@ export function loadAuthState() {
41
45
  return null;
42
46
  const parsed = JSON.parse(data);
43
47
  // Validate required fields and types
44
- if (typeof parsed.accessToken !== "string" ||
45
- parsed.accessToken.length === 0 ||
46
- typeof parsed.refreshToken !== "string" ||
47
- parsed.refreshToken.length === 0 ||
48
+ if (typeof parsed.sessionPublicKey !== "string" ||
49
+ parsed.sessionPublicKey.length === 0 ||
50
+ typeof parsed.sessionPrivateKey !== "string" ||
51
+ parsed.sessionPrivateKey.length === 0 ||
48
52
  typeof parsed.expiresAt !== "number" ||
49
53
  !Number.isFinite(parsed.expiresAt) ||
50
54
  parsed.expiresAt <= 0 ||
@@ -58,8 +62,8 @@ export function loadAuthState() {
58
62
  return null;
59
63
  }
60
64
  return {
61
- accessToken: parsed.accessToken,
62
- refreshToken: parsed.refreshToken,
65
+ sessionPublicKey: parsed.sessionPublicKey,
66
+ sessionPrivateKey: parsed.sessionPrivateKey,
63
67
  expiresAt: parsed.expiresAt,
64
68
  user: parsed.user,
65
69
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xmonaco/react",
3
- "version": "0.8.4",
3
+ "version": "0.8.7-develop.0e951a5",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,8 +20,8 @@
20
20
  "lint": "biome lint ."
21
21
  },
22
22
  "dependencies": {
23
- "@0xmonaco/core": "0.8.4",
24
- "@0xmonaco/types": "0.8.4"
23
+ "@0xmonaco/core": "0.8.7-develop.0e951a5",
24
+ "@0xmonaco/types": "0.8.7-develop.0e951a5"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/react": "^19.1.12",
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "peerDependencies": {
31
31
  "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
32
- "wagmi": "^2.0.0 || ^3.0.0",
33
- "viem": "^2.45.2"
32
+ "viem": "^2.45.2",
33
+ "wagmi": "^2.0.0 || ^3.0.0"
34
34
  },
35
35
  "exports": {
36
36
  ".": {