@oxyhq/services 5.8.11 → 5.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/core/index.js +192 -346
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/index.js +6 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/node/index.js +0 -9
- package/lib/commonjs/node/index.js.map +1 -1
- package/lib/commonjs/types/middleware.js +6 -0
- package/lib/commonjs/types/middleware.js.map +1 -0
- package/lib/commonjs/ui/components/OxyProvider.js +3 -9
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +0 -4
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js +0 -4
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +16 -27
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignUpScreen.js +4 -18
- package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +1 -2
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
- package/lib/module/core/index.js +190 -345
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/node/index.js +0 -4
- package/lib/module/node/index.js.map +1 -1
- package/lib/module/types/middleware.js +4 -0
- package/lib/module/types/middleware.js.map +1 -0
- package/lib/module/ui/components/OxyProvider.js +3 -9
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +0 -4
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/RecoverAccountScreen.js +0 -4
- package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +16 -27
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/SignUpScreen.js +4 -18
- package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +1 -2
- package/lib/module/ui/styles/authStyles.js.map +1 -1
- package/lib/typescript/core/index.d.ts +34 -86
- package/lib/typescript/core/index.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/node/index.d.ts +0 -2
- package/lib/typescript/node/index.d.ts.map +1 -1
- package/lib/typescript/types/middleware.d.ts +19 -0
- package/lib/typescript/types/middleware.d.ts.map +1 -0
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +0 -1
- package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/core/index.ts +196 -328
- package/src/index.ts +4 -0
- package/src/node/index.ts +0 -4
- package/src/types/middleware.ts +20 -0
- package/src/ui/components/OxyProvider.tsx +3 -9
- package/src/ui/screens/FeedbackScreen.tsx +0 -4
- package/src/ui/screens/RecoverAccountScreen.tsx +0 -4
- package/src/ui/screens/SignInScreen.tsx +16 -20
- package/src/ui/screens/SignUpScreen.tsx +4 -14
- package/src/ui/styles/authStyles.ts +0 -1
- package/lib/commonjs/node/createAuth.js +0 -95
- package/lib/commonjs/node/createAuth.js.map +0 -1
- package/lib/module/node/createAuth.js +0 -90
- package/lib/module/node/createAuth.js.map +0 -1
- package/lib/typescript/node/createAuth.d.ts +0 -7
- package/lib/typescript/node/createAuth.d.ts.map +0 -1
- package/src/node/createAuth.ts +0 -116
package/lib/module/core/index.js
CHANGED
|
@@ -23,7 +23,6 @@ export { DeviceManager } from '../utils/deviceManager';
|
|
|
23
23
|
export class OxyServices {
|
|
24
24
|
accessToken = null;
|
|
25
25
|
refreshToken = null;
|
|
26
|
-
refreshPromise = null;
|
|
27
26
|
|
|
28
27
|
/**
|
|
29
28
|
* Creates a new instance of the OxyServices client
|
|
@@ -39,14 +38,25 @@ export class OxyServices {
|
|
|
39
38
|
this.client.interceptors.request.use(async req => {
|
|
40
39
|
if (!this.accessToken) {
|
|
41
40
|
return req;
|
|
42
|
-
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Check if token is expired and refresh if needed
|
|
43
44
|
try {
|
|
44
45
|
const decoded = jwtDecode(this.accessToken);
|
|
45
46
|
const currentTime = Math.floor(Date.now() / 1000);
|
|
46
47
|
|
|
47
48
|
// If token expires in less than 60 seconds, refresh it
|
|
48
49
|
if (decoded.exp - currentTime < 60) {
|
|
49
|
-
|
|
50
|
+
// For session-based tokens, get a new token from the session
|
|
51
|
+
if (decoded.sessionId) {
|
|
52
|
+
try {
|
|
53
|
+
const res = await this.client.get(`/secure-session/token/${decoded.sessionId}`);
|
|
54
|
+
this.accessToken = res.data.accessToken;
|
|
55
|
+
} catch (refreshError) {
|
|
56
|
+
// If refresh fails, clear tokens
|
|
57
|
+
this.clearTokens();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
50
60
|
}
|
|
51
61
|
} catch (error) {
|
|
52
62
|
// If token can't be decoded, continue with request and let server handle it
|
|
@@ -61,18 +71,24 @@ export class OxyServices {
|
|
|
61
71
|
this.client.interceptors.response.use(response => response, async error => {
|
|
62
72
|
const originalRequest = error.config;
|
|
63
73
|
// If the error is due to an expired token and we haven't tried refreshing yet
|
|
64
|
-
if (error.response?.status === 401 && this.
|
|
74
|
+
if (error.response?.status === 401 && this.accessToken && originalRequest && !originalRequest.headers?.['X-Retry-After-Refresh']) {
|
|
65
75
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
newRequest
|
|
76
|
+
// Check if token is session-based and try to refresh
|
|
77
|
+
const decoded = jwtDecode(this.accessToken);
|
|
78
|
+
if (decoded.sessionId) {
|
|
79
|
+
const res = await this.client.get(`/secure-session/token/${decoded.sessionId}`);
|
|
80
|
+
this.accessToken = res.data.accessToken;
|
|
81
|
+
|
|
82
|
+
// Retry the original request with new token
|
|
83
|
+
const newRequest = {
|
|
84
|
+
...originalRequest
|
|
85
|
+
};
|
|
86
|
+
if (newRequest.headers) {
|
|
87
|
+
newRequest.headers.Authorization = `Bearer ${this.accessToken}`;
|
|
88
|
+
newRequest.headers['X-Retry-After-Refresh'] = 'true';
|
|
89
|
+
}
|
|
90
|
+
return this.client(newRequest);
|
|
74
91
|
}
|
|
75
|
-
return this.client(newRequest);
|
|
76
92
|
} catch (refreshError) {
|
|
77
93
|
// If refresh fails, force user to login again
|
|
78
94
|
this.clearTokens();
|
|
@@ -105,43 +121,17 @@ export class OxyServices {
|
|
|
105
121
|
}
|
|
106
122
|
|
|
107
123
|
/**
|
|
108
|
-
*
|
|
109
|
-
* @
|
|
124
|
+
* Set authentication tokens manually
|
|
125
|
+
* @param accessToken - The access token
|
|
126
|
+
* @param refreshToken - The refresh token (optional for session-based auth)
|
|
110
127
|
*/
|
|
111
|
-
|
|
112
|
-
if (!this.accessToken) return null;
|
|
113
|
-
try {
|
|
114
|
-
const decoded = jwtDecode(this.accessToken);
|
|
115
|
-
|
|
116
|
-
// Check for both userId (preferred) and id (fallback) for compatibility
|
|
117
|
-
return decoded.userId || decoded.id || null;
|
|
118
|
-
} catch (error) {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Internal method to check if we have an access token
|
|
125
|
-
* @private
|
|
126
|
-
* @returns Boolean indicating if access token exists
|
|
127
|
-
* @internal - Use `isAuthenticated` from useOxy() context in UI components instead
|
|
128
|
-
*/
|
|
129
|
-
hasAccessToken() {
|
|
130
|
-
return this.accessToken !== null;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Sets authentication tokens directly (useful for initializing from storage)
|
|
135
|
-
* @param accessToken - JWT access token
|
|
136
|
-
* @param refreshToken - Refresh token for getting new access tokens
|
|
137
|
-
*/
|
|
138
|
-
setTokens(accessToken, refreshToken) {
|
|
128
|
+
setTokens(accessToken, refreshToken = '') {
|
|
139
129
|
this.accessToken = accessToken;
|
|
140
130
|
this.refreshToken = refreshToken;
|
|
141
131
|
}
|
|
142
132
|
|
|
143
133
|
/**
|
|
144
|
-
*
|
|
134
|
+
* Clear stored authentication tokens
|
|
145
135
|
*/
|
|
146
136
|
clearTokens() {
|
|
147
137
|
this.accessToken = null;
|
|
@@ -149,120 +139,27 @@ export class OxyServices {
|
|
|
149
139
|
}
|
|
150
140
|
|
|
151
141
|
/**
|
|
152
|
-
*
|
|
153
|
-
* @
|
|
154
|
-
* @param email - User's email address
|
|
155
|
-
* @param password - User's password
|
|
156
|
-
* @returns Object containing the message, token and user data
|
|
157
|
-
*/
|
|
158
|
-
async signUp(username, email, password) {
|
|
159
|
-
try {
|
|
160
|
-
const res = await this.client.post('/auth/signup', {
|
|
161
|
-
username,
|
|
162
|
-
email,
|
|
163
|
-
password
|
|
164
|
-
});
|
|
165
|
-
const {
|
|
166
|
-
message,
|
|
167
|
-
token,
|
|
168
|
-
user
|
|
169
|
-
} = res.data;
|
|
170
|
-
this.accessToken = token;
|
|
171
|
-
return {
|
|
172
|
-
message,
|
|
173
|
-
token,
|
|
174
|
-
user
|
|
175
|
-
};
|
|
176
|
-
} catch (error) {
|
|
177
|
-
throw this.handleError(error);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Log in and store tokens
|
|
183
|
-
* @param username - User's username or email
|
|
184
|
-
* @param password - User's password
|
|
185
|
-
* @returns Login response containing tokens and user data
|
|
142
|
+
* Get the current user ID from the stored token
|
|
143
|
+
* @returns User ID or null if not authenticated
|
|
186
144
|
*/
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const res = await this.client.post('/auth/login', {
|
|
190
|
-
username,
|
|
191
|
-
password
|
|
192
|
-
});
|
|
193
|
-
const {
|
|
194
|
-
accessToken,
|
|
195
|
-
refreshToken,
|
|
196
|
-
user
|
|
197
|
-
} = res.data;
|
|
198
|
-
this.accessToken = accessToken;
|
|
199
|
-
this.refreshToken = refreshToken;
|
|
200
|
-
return {
|
|
201
|
-
accessToken,
|
|
202
|
-
refreshToken,
|
|
203
|
-
user
|
|
204
|
-
};
|
|
205
|
-
} catch (error) {
|
|
206
|
-
throw this.handleError(error);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Log out user
|
|
212
|
-
*/
|
|
213
|
-
async logout() {
|
|
214
|
-
if (!this.refreshToken) return;
|
|
145
|
+
getCurrentUserId() {
|
|
146
|
+
if (!this.accessToken) return null;
|
|
215
147
|
try {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
});
|
|
148
|
+
const decoded = jwtDecode(this.accessToken);
|
|
149
|
+
return decoded.userId || decoded.id || null;
|
|
219
150
|
} catch (error) {
|
|
220
|
-
|
|
221
|
-
} finally {
|
|
222
|
-
this.accessToken = null;
|
|
223
|
-
this.refreshToken = null;
|
|
151
|
+
return null;
|
|
224
152
|
}
|
|
225
153
|
}
|
|
226
154
|
|
|
227
155
|
/**
|
|
228
|
-
*
|
|
229
|
-
* @
|
|
156
|
+
* Internal method to check if we have an access token
|
|
157
|
+
* @private
|
|
158
|
+
* @returns Boolean indicating if access token exists
|
|
159
|
+
* @internal - Use `isAuthenticated` from useOxy() context in UI components instead
|
|
230
160
|
*/
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
throw new Error('No refresh token available');
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// If a refresh is already in progress, return that promise
|
|
237
|
-
if (this.refreshPromise) {
|
|
238
|
-
return this.refreshPromise;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Create a new refresh promise
|
|
242
|
-
this.refreshPromise = (async () => {
|
|
243
|
-
try {
|
|
244
|
-
const res = await this.client.post('/auth/refresh', {
|
|
245
|
-
refreshToken: this.refreshToken
|
|
246
|
-
});
|
|
247
|
-
const {
|
|
248
|
-
accessToken,
|
|
249
|
-
refreshToken
|
|
250
|
-
} = res.data;
|
|
251
|
-
this.accessToken = accessToken;
|
|
252
|
-
this.refreshToken = refreshToken;
|
|
253
|
-
return {
|
|
254
|
-
accessToken,
|
|
255
|
-
refreshToken
|
|
256
|
-
};
|
|
257
|
-
} catch (error) {
|
|
258
|
-
this.accessToken = null;
|
|
259
|
-
this.refreshToken = null;
|
|
260
|
-
throw this.handleError(error);
|
|
261
|
-
} finally {
|
|
262
|
-
this.refreshPromise = null;
|
|
263
|
-
}
|
|
264
|
-
})();
|
|
265
|
-
return this.refreshPromise;
|
|
161
|
+
hasAccessToken() {
|
|
162
|
+
return this.accessToken !== null;
|
|
266
163
|
}
|
|
267
164
|
|
|
268
165
|
/**
|
|
@@ -271,6 +168,22 @@ export class OxyServices {
|
|
|
271
168
|
*/
|
|
272
169
|
async validate() {
|
|
273
170
|
try {
|
|
171
|
+
// Check if token contains sessionId (new session-based system)
|
|
172
|
+
if (this.accessToken) {
|
|
173
|
+
try {
|
|
174
|
+
const decoded = jwtDecode(this.accessToken);
|
|
175
|
+
if (decoded.sessionId) {
|
|
176
|
+
// Use session-based validation
|
|
177
|
+
const res = await this.client.get(`/secure-session/validate/${decoded.sessionId}`);
|
|
178
|
+
return res.data.valid;
|
|
179
|
+
}
|
|
180
|
+
} catch (decodeError) {
|
|
181
|
+
// If token can't be decoded, fall back to old validation
|
|
182
|
+
console.warn('Error decoding JWT token for session validation:', decodeError);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Fall back to old validation method
|
|
274
187
|
const res = await this.client.get('/auth/validate');
|
|
275
188
|
return res.data.valid;
|
|
276
189
|
} catch (error) {
|
|
@@ -280,59 +193,6 @@ export class OxyServices {
|
|
|
280
193
|
|
|
281
194
|
/* Session Management Methods */
|
|
282
195
|
|
|
283
|
-
/**
|
|
284
|
-
* Get active sessions for the authenticated user
|
|
285
|
-
* @returns Array of active session objects
|
|
286
|
-
*/
|
|
287
|
-
async getUserSessions() {
|
|
288
|
-
try {
|
|
289
|
-
const res = await this.client.get('/sessions');
|
|
290
|
-
return res.data;
|
|
291
|
-
} catch (error) {
|
|
292
|
-
throw this.handleError(error);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Logout from a specific session
|
|
298
|
-
* @param sessionId - The session ID to logout from
|
|
299
|
-
* @returns Success status
|
|
300
|
-
*/
|
|
301
|
-
async logoutSession(sessionId) {
|
|
302
|
-
try {
|
|
303
|
-
const res = await this.client.delete(`/sessions/${sessionId}`);
|
|
304
|
-
return res.data;
|
|
305
|
-
} catch (error) {
|
|
306
|
-
throw this.handleError(error);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Logout from all other sessions (keep current session active)
|
|
312
|
-
* @returns Success status
|
|
313
|
-
*/
|
|
314
|
-
async logoutOtherSessions() {
|
|
315
|
-
try {
|
|
316
|
-
const res = await this.client.post('/sessions/logout-others');
|
|
317
|
-
return res.data;
|
|
318
|
-
} catch (error) {
|
|
319
|
-
throw this.handleError(error);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Logout from all sessions
|
|
325
|
-
* @returns Success status
|
|
326
|
-
*/
|
|
327
|
-
async logoutAllSessions() {
|
|
328
|
-
try {
|
|
329
|
-
const res = await this.client.post('/sessions/logout-all');
|
|
330
|
-
return res.data;
|
|
331
|
-
} catch (error) {
|
|
332
|
-
throw this.handleError(error);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
196
|
/**
|
|
337
197
|
* Get device sessions for a specific session ID
|
|
338
198
|
* @param sessionId - The session ID to get device sessions for
|
|
@@ -1157,12 +1017,47 @@ export class OxyServices {
|
|
|
1157
1017
|
}
|
|
1158
1018
|
|
|
1159
1019
|
/**
|
|
1160
|
-
*
|
|
1020
|
+
* Sign up a new user and create a session
|
|
1021
|
+
* @param username - Desired username
|
|
1022
|
+
* @param email - User's email address
|
|
1023
|
+
* @param password - User's password
|
|
1024
|
+
* @returns Object containing the message, token and user data
|
|
1025
|
+
*/
|
|
1026
|
+
async signUp(username, email, password) {
|
|
1027
|
+
try {
|
|
1028
|
+
// First, create the user account
|
|
1029
|
+
const res = await this.client.post('/secure-session/register', {
|
|
1030
|
+
username,
|
|
1031
|
+
email,
|
|
1032
|
+
password
|
|
1033
|
+
});
|
|
1034
|
+
const {
|
|
1035
|
+
message,
|
|
1036
|
+
user
|
|
1037
|
+
} = res.data;
|
|
1038
|
+
|
|
1039
|
+
// Then log them in to create a session
|
|
1040
|
+
const loginRes = await this.secureLogin(username, password);
|
|
1041
|
+
|
|
1042
|
+
// Get the access token for the session
|
|
1043
|
+
const tokenRes = await this.getTokenBySession(loginRes.sessionId);
|
|
1044
|
+
return {
|
|
1045
|
+
message,
|
|
1046
|
+
token: tokenRes.accessToken,
|
|
1047
|
+
user: loginRes.user
|
|
1048
|
+
};
|
|
1049
|
+
} catch (error) {
|
|
1050
|
+
throw this.handleError(error);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Secure login that creates a device-based session
|
|
1161
1056
|
* @param username - User's username or email
|
|
1162
1057
|
* @param password - User's password
|
|
1163
|
-
* @param deviceName - Optional device name
|
|
1164
|
-
* @param deviceFingerprint -
|
|
1165
|
-
* @returns
|
|
1058
|
+
* @param deviceName - Optional device name
|
|
1059
|
+
* @param deviceFingerprint - Optional device fingerprint
|
|
1060
|
+
* @returns Login response with session data
|
|
1166
1061
|
*/
|
|
1167
1062
|
async secureLogin(username, password, deviceName, deviceFingerprint) {
|
|
1168
1063
|
try {
|
|
@@ -1340,122 +1235,47 @@ export class OxyServices {
|
|
|
1340
1235
|
}
|
|
1341
1236
|
|
|
1342
1237
|
/**
|
|
1343
|
-
*
|
|
1344
|
-
* This
|
|
1345
|
-
* @param options - Configuration options for the middleware
|
|
1238
|
+
* Create authentication middleware for Express.js applications
|
|
1239
|
+
* This is the recommended way to protect routes in server applications
|
|
1346
1240
|
* @returns Express middleware function
|
|
1347
1241
|
*/
|
|
1348
|
-
|
|
1349
|
-
const {
|
|
1350
|
-
loadFullUser = true,
|
|
1351
|
-
onError
|
|
1352
|
-
} = options;
|
|
1242
|
+
createAuthMiddleware() {
|
|
1353
1243
|
return async (req, res, next) => {
|
|
1354
1244
|
try {
|
|
1355
|
-
const authHeader = req.headers
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
if (!token) {
|
|
1359
|
-
const error = {
|
|
1360
|
-
message: 'Access token required',
|
|
1361
|
-
code: 'MISSING_TOKEN',
|
|
1362
|
-
status: 401
|
|
1363
|
-
};
|
|
1364
|
-
if (onError) {
|
|
1365
|
-
return onError(error);
|
|
1366
|
-
}
|
|
1245
|
+
const authHeader = req.headers.authorization;
|
|
1246
|
+
if (!authHeader?.startsWith('Bearer ')) {
|
|
1367
1247
|
return res.status(401).json({
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
});
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
// Create a temporary OxyServices instance with the token to validate it
|
|
1374
|
-
const tempOxyServices = new OxyServices({
|
|
1375
|
-
baseURL: this.client.defaults.baseURL || ''
|
|
1376
|
-
});
|
|
1377
|
-
tempOxyServices.setTokens(token, ''); // Set access token
|
|
1378
|
-
|
|
1379
|
-
// Validate token using the validate method
|
|
1380
|
-
const isValid = await tempOxyServices.validate();
|
|
1381
|
-
if (!isValid) {
|
|
1382
|
-
const error = {
|
|
1383
|
-
message: 'Invalid or expired token',
|
|
1384
|
-
code: 'INVALID_TOKEN',
|
|
1385
|
-
status: 403
|
|
1386
|
-
};
|
|
1387
|
-
if (onError) {
|
|
1388
|
-
return onError(error);
|
|
1389
|
-
}
|
|
1390
|
-
return res.status(403).json({
|
|
1391
|
-
message: 'Invalid or expired token',
|
|
1392
|
-
code: 'INVALID_TOKEN'
|
|
1248
|
+
error: 'Authentication required',
|
|
1249
|
+
message: 'Invalid or missing authorization header'
|
|
1393
1250
|
});
|
|
1394
1251
|
}
|
|
1252
|
+
const token = authHeader.split(' ')[1];
|
|
1395
1253
|
|
|
1396
|
-
//
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
const error = {
|
|
1403
|
-
message: 'Invalid token payload',
|
|
1404
|
-
code: 'INVALID_PAYLOAD',
|
|
1405
|
-
status: 403
|
|
1406
|
-
};
|
|
1407
|
-
if (onError) {
|
|
1408
|
-
return onError(error);
|
|
1409
|
-
}
|
|
1410
|
-
return res.status(403).json({
|
|
1411
|
-
message: 'Invalid token payload',
|
|
1412
|
-
code: 'INVALID_PAYLOAD'
|
|
1413
|
-
});
|
|
1414
|
-
}
|
|
1415
|
-
if (!userId) {
|
|
1416
|
-
const error = {
|
|
1417
|
-
message: 'Invalid token payload',
|
|
1418
|
-
code: 'INVALID_PAYLOAD',
|
|
1419
|
-
status: 403
|
|
1420
|
-
};
|
|
1421
|
-
if (onError) {
|
|
1422
|
-
return onError(error);
|
|
1423
|
-
}
|
|
1424
|
-
return res.status(403).json({
|
|
1425
|
-
message: 'Invalid token payload',
|
|
1426
|
-
code: 'INVALID_PAYLOAD'
|
|
1254
|
+
// Use the authenticateToken method
|
|
1255
|
+
const result = await this.authenticateToken(token);
|
|
1256
|
+
if (!result.valid) {
|
|
1257
|
+
return res.status(401).json({
|
|
1258
|
+
error: 'Invalid token',
|
|
1259
|
+
message: result.error || 'The provided authentication token is invalid'
|
|
1427
1260
|
});
|
|
1428
1261
|
}
|
|
1429
1262
|
|
|
1430
1263
|
// Set user information on request object
|
|
1431
|
-
req.userId = userId;
|
|
1264
|
+
req.userId = result.userId || undefined;
|
|
1432
1265
|
req.accessToken = token;
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
if (
|
|
1436
|
-
try {
|
|
1437
|
-
const userProfile = await tempOxyServices.getUserById(userId);
|
|
1438
|
-
req.user = userProfile;
|
|
1439
|
-
} catch (userError) {
|
|
1440
|
-
// If we can't load user, continue with just ID
|
|
1441
|
-
req.user = {
|
|
1442
|
-
id: userId
|
|
1443
|
-
};
|
|
1444
|
-
}
|
|
1445
|
-
} else {
|
|
1266
|
+
if (result.user) {
|
|
1267
|
+
req.user = result.user;
|
|
1268
|
+
} else if (result.userId) {
|
|
1446
1269
|
req.user = {
|
|
1447
|
-
id: userId
|
|
1270
|
+
id: result.userId
|
|
1448
1271
|
};
|
|
1449
1272
|
}
|
|
1450
1273
|
next();
|
|
1451
1274
|
} catch (error) {
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
return res.status(apiError.status || 500).json({
|
|
1457
|
-
message: apiError.message,
|
|
1458
|
-
code: apiError.code
|
|
1275
|
+
console.error('Auth middleware error:', error);
|
|
1276
|
+
return res.status(500).json({
|
|
1277
|
+
error: 'Server error',
|
|
1278
|
+
message: 'An error occurred while authenticating your request'
|
|
1459
1279
|
});
|
|
1460
1280
|
}
|
|
1461
1281
|
};
|
|
@@ -1476,54 +1296,71 @@ export class OxyServices {
|
|
|
1476
1296
|
};
|
|
1477
1297
|
}
|
|
1478
1298
|
|
|
1479
|
-
//
|
|
1480
|
-
const tempOxyServices = new OxyServices({
|
|
1481
|
-
baseURL: this.client.defaults.baseURL || ''
|
|
1482
|
-
});
|
|
1483
|
-
tempOxyServices.setTokens(token, '');
|
|
1484
|
-
|
|
1485
|
-
// Validate token
|
|
1486
|
-
const isValid = await tempOxyServices.validate();
|
|
1487
|
-
if (!isValid) {
|
|
1488
|
-
return {
|
|
1489
|
-
valid: false,
|
|
1490
|
-
error: 'Invalid or expired token'
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
// Get user ID from token using JWT decode
|
|
1495
|
-
let userId = null;
|
|
1299
|
+
// Check if token contains sessionId (new session-based system)
|
|
1496
1300
|
try {
|
|
1497
1301
|
const decoded = jwtDecode(token);
|
|
1498
|
-
userId = decoded.userId || decoded.id;
|
|
1302
|
+
const userId = decoded.userId || decoded.id;
|
|
1303
|
+
if (decoded.sessionId) {
|
|
1304
|
+
// Use session-based validation
|
|
1305
|
+
const tempOxyServices = new OxyServices({
|
|
1306
|
+
baseURL: this.client.defaults.baseURL || ''
|
|
1307
|
+
});
|
|
1308
|
+
tempOxyServices.setTokens(token, '');
|
|
1309
|
+
const validation = await tempOxyServices.validateSession(decoded.sessionId);
|
|
1310
|
+
if (validation.valid) {
|
|
1311
|
+
return {
|
|
1312
|
+
valid: true,
|
|
1313
|
+
userId,
|
|
1314
|
+
user: validation.user
|
|
1315
|
+
};
|
|
1316
|
+
} else {
|
|
1317
|
+
return {
|
|
1318
|
+
valid: false,
|
|
1319
|
+
error: 'Invalid or expired session'
|
|
1320
|
+
};
|
|
1321
|
+
}
|
|
1322
|
+
} else {
|
|
1323
|
+
// Use old validation method
|
|
1324
|
+
const tempOxyServices = new OxyServices({
|
|
1325
|
+
baseURL: this.client.defaults.baseURL || ''
|
|
1326
|
+
});
|
|
1327
|
+
tempOxyServices.setTokens(token, '');
|
|
1328
|
+
const isValid = await tempOxyServices.validate();
|
|
1329
|
+
if (!isValid) {
|
|
1330
|
+
return {
|
|
1331
|
+
valid: false,
|
|
1332
|
+
error: 'Invalid or expired token'
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
if (!userId) {
|
|
1336
|
+
return {
|
|
1337
|
+
valid: false,
|
|
1338
|
+
error: 'Invalid token payload'
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// Try to get user profile
|
|
1343
|
+
let user;
|
|
1344
|
+
try {
|
|
1345
|
+
user = await tempOxyServices.getUserById(userId);
|
|
1346
|
+
} catch (error) {
|
|
1347
|
+
// Continue without full user data
|
|
1348
|
+
user = {
|
|
1349
|
+
id: userId
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
return {
|
|
1353
|
+
valid: true,
|
|
1354
|
+
userId,
|
|
1355
|
+
user
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1499
1358
|
} catch (decodeError) {
|
|
1500
1359
|
return {
|
|
1501
1360
|
valid: false,
|
|
1502
1361
|
error: 'Invalid token payload'
|
|
1503
1362
|
};
|
|
1504
1363
|
}
|
|
1505
|
-
if (!userId) {
|
|
1506
|
-
return {
|
|
1507
|
-
valid: false,
|
|
1508
|
-
error: 'Invalid token payload'
|
|
1509
|
-
};
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
// Try to get user profile
|
|
1513
|
-
let user;
|
|
1514
|
-
try {
|
|
1515
|
-
user = await tempOxyServices.getUserById(userId);
|
|
1516
|
-
} catch (error) {
|
|
1517
|
-
// Continue without full user data
|
|
1518
|
-
user = {
|
|
1519
|
-
id: userId
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
return {
|
|
1523
|
-
valid: true,
|
|
1524
|
-
userId,
|
|
1525
|
-
user
|
|
1526
|
-
};
|
|
1527
1364
|
} catch (error) {
|
|
1528
1365
|
return {
|
|
1529
1366
|
valid: false,
|
|
@@ -1858,6 +1695,14 @@ export default OxyServices;
|
|
|
1858
1695
|
// Re-export all models and types for convenience
|
|
1859
1696
|
export * from '../models/interfaces';
|
|
1860
1697
|
export * from '../models/secureSession';
|
|
1698
|
+
|
|
1699
|
+
// Clean middleware exports - these will be available for server-side use
|
|
1700
|
+
// Note: These require Express.js and are only for server-side applications
|
|
1701
|
+
|
|
1702
|
+
// Export a simple function to create auth middleware
|
|
1703
|
+
export const createAuthMiddleware = oxyServices => {
|
|
1704
|
+
return oxyServices.createAuthMiddleware();
|
|
1705
|
+
};
|
|
1861
1706
|
if (typeof FormData === 'undefined') {
|
|
1862
1707
|
console.warn('[OxyHQ/Services] FormData is not available. If you are using Hermes, add "import \'react-native-url-polyfill/auto\'" at the top of your app entry file.');
|
|
1863
1708
|
}
|