@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
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
var _exportNames = {
|
|
7
7
|
OXY_CLOUD_URL: true,
|
|
8
8
|
OxyServices: true,
|
|
9
|
+
createAuthMiddleware: true,
|
|
9
10
|
DeviceManager: true
|
|
10
11
|
};
|
|
11
12
|
Object.defineProperty(exports, "DeviceManager", {
|
|
@@ -14,7 +15,7 @@ Object.defineProperty(exports, "DeviceManager", {
|
|
|
14
15
|
return _deviceManager.DeviceManager;
|
|
15
16
|
}
|
|
16
17
|
});
|
|
17
|
-
exports.default = exports.OxyServices = exports.OXY_CLOUD_URL = void 0;
|
|
18
|
+
exports.default = exports.createAuthMiddleware = exports.OxyServices = exports.OXY_CLOUD_URL = void 0;
|
|
18
19
|
var _axios = _interopRequireDefault(require("axios"));
|
|
19
20
|
var _jwtDecode = require("jwt-decode");
|
|
20
21
|
var _deviceManager = require("../utils/deviceManager");
|
|
@@ -63,7 +64,6 @@ const OXY_CLOUD_URL = exports.OXY_CLOUD_URL = 'https://cloud.oxy.so';
|
|
|
63
64
|
class OxyServices {
|
|
64
65
|
accessToken = null;
|
|
65
66
|
refreshToken = null;
|
|
66
|
-
refreshPromise = null;
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Creates a new instance of the OxyServices client
|
|
@@ -79,14 +79,25 @@ class OxyServices {
|
|
|
79
79
|
this.client.interceptors.request.use(async req => {
|
|
80
80
|
if (!this.accessToken) {
|
|
81
81
|
return req;
|
|
82
|
-
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Check if token is expired and refresh if needed
|
|
83
85
|
try {
|
|
84
86
|
const decoded = (0, _jwtDecode.jwtDecode)(this.accessToken);
|
|
85
87
|
const currentTime = Math.floor(Date.now() / 1000);
|
|
86
88
|
|
|
87
89
|
// If token expires in less than 60 seconds, refresh it
|
|
88
90
|
if (decoded.exp - currentTime < 60) {
|
|
89
|
-
|
|
91
|
+
// For session-based tokens, get a new token from the session
|
|
92
|
+
if (decoded.sessionId) {
|
|
93
|
+
try {
|
|
94
|
+
const res = await this.client.get(`/secure-session/token/${decoded.sessionId}`);
|
|
95
|
+
this.accessToken = res.data.accessToken;
|
|
96
|
+
} catch (refreshError) {
|
|
97
|
+
// If refresh fails, clear tokens
|
|
98
|
+
this.clearTokens();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
90
101
|
}
|
|
91
102
|
} catch (error) {
|
|
92
103
|
// If token can't be decoded, continue with request and let server handle it
|
|
@@ -101,18 +112,24 @@ class OxyServices {
|
|
|
101
112
|
this.client.interceptors.response.use(response => response, async error => {
|
|
102
113
|
const originalRequest = error.config;
|
|
103
114
|
// If the error is due to an expired token and we haven't tried refreshing yet
|
|
104
|
-
if (error.response?.status === 401 && this.
|
|
115
|
+
if (error.response?.status === 401 && this.accessToken && originalRequest && !originalRequest.headers?.['X-Retry-After-Refresh']) {
|
|
105
116
|
try {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
newRequest
|
|
117
|
+
// Check if token is session-based and try to refresh
|
|
118
|
+
const decoded = (0, _jwtDecode.jwtDecode)(this.accessToken);
|
|
119
|
+
if (decoded.sessionId) {
|
|
120
|
+
const res = await this.client.get(`/secure-session/token/${decoded.sessionId}`);
|
|
121
|
+
this.accessToken = res.data.accessToken;
|
|
122
|
+
|
|
123
|
+
// Retry the original request with new token
|
|
124
|
+
const newRequest = {
|
|
125
|
+
...originalRequest
|
|
126
|
+
};
|
|
127
|
+
if (newRequest.headers) {
|
|
128
|
+
newRequest.headers.Authorization = `Bearer ${this.accessToken}`;
|
|
129
|
+
newRequest.headers['X-Retry-After-Refresh'] = 'true';
|
|
130
|
+
}
|
|
131
|
+
return this.client(newRequest);
|
|
114
132
|
}
|
|
115
|
-
return this.client(newRequest);
|
|
116
133
|
} catch (refreshError) {
|
|
117
134
|
// If refresh fails, force user to login again
|
|
118
135
|
this.clearTokens();
|
|
@@ -145,43 +162,17 @@ class OxyServices {
|
|
|
145
162
|
}
|
|
146
163
|
|
|
147
164
|
/**
|
|
148
|
-
*
|
|
149
|
-
* @
|
|
165
|
+
* Set authentication tokens manually
|
|
166
|
+
* @param accessToken - The access token
|
|
167
|
+
* @param refreshToken - The refresh token (optional for session-based auth)
|
|
150
168
|
*/
|
|
151
|
-
|
|
152
|
-
if (!this.accessToken) return null;
|
|
153
|
-
try {
|
|
154
|
-
const decoded = (0, _jwtDecode.jwtDecode)(this.accessToken);
|
|
155
|
-
|
|
156
|
-
// Check for both userId (preferred) and id (fallback) for compatibility
|
|
157
|
-
return decoded.userId || decoded.id || null;
|
|
158
|
-
} catch (error) {
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Internal method to check if we have an access token
|
|
165
|
-
* @private
|
|
166
|
-
* @returns Boolean indicating if access token exists
|
|
167
|
-
* @internal - Use `isAuthenticated` from useOxy() context in UI components instead
|
|
168
|
-
*/
|
|
169
|
-
hasAccessToken() {
|
|
170
|
-
return this.accessToken !== null;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Sets authentication tokens directly (useful for initializing from storage)
|
|
175
|
-
* @param accessToken - JWT access token
|
|
176
|
-
* @param refreshToken - Refresh token for getting new access tokens
|
|
177
|
-
*/
|
|
178
|
-
setTokens(accessToken, refreshToken) {
|
|
169
|
+
setTokens(accessToken, refreshToken = '') {
|
|
179
170
|
this.accessToken = accessToken;
|
|
180
171
|
this.refreshToken = refreshToken;
|
|
181
172
|
}
|
|
182
173
|
|
|
183
174
|
/**
|
|
184
|
-
*
|
|
175
|
+
* Clear stored authentication tokens
|
|
185
176
|
*/
|
|
186
177
|
clearTokens() {
|
|
187
178
|
this.accessToken = null;
|
|
@@ -189,120 +180,27 @@ class OxyServices {
|
|
|
189
180
|
}
|
|
190
181
|
|
|
191
182
|
/**
|
|
192
|
-
*
|
|
193
|
-
* @
|
|
194
|
-
* @param email - User's email address
|
|
195
|
-
* @param password - User's password
|
|
196
|
-
* @returns Object containing the message, token and user data
|
|
197
|
-
*/
|
|
198
|
-
async signUp(username, email, password) {
|
|
199
|
-
try {
|
|
200
|
-
const res = await this.client.post('/auth/signup', {
|
|
201
|
-
username,
|
|
202
|
-
email,
|
|
203
|
-
password
|
|
204
|
-
});
|
|
205
|
-
const {
|
|
206
|
-
message,
|
|
207
|
-
token,
|
|
208
|
-
user
|
|
209
|
-
} = res.data;
|
|
210
|
-
this.accessToken = token;
|
|
211
|
-
return {
|
|
212
|
-
message,
|
|
213
|
-
token,
|
|
214
|
-
user
|
|
215
|
-
};
|
|
216
|
-
} catch (error) {
|
|
217
|
-
throw this.handleError(error);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Log in and store tokens
|
|
223
|
-
* @param username - User's username or email
|
|
224
|
-
* @param password - User's password
|
|
225
|
-
* @returns Login response containing tokens and user data
|
|
183
|
+
* Get the current user ID from the stored token
|
|
184
|
+
* @returns User ID or null if not authenticated
|
|
226
185
|
*/
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const res = await this.client.post('/auth/login', {
|
|
230
|
-
username,
|
|
231
|
-
password
|
|
232
|
-
});
|
|
233
|
-
const {
|
|
234
|
-
accessToken,
|
|
235
|
-
refreshToken,
|
|
236
|
-
user
|
|
237
|
-
} = res.data;
|
|
238
|
-
this.accessToken = accessToken;
|
|
239
|
-
this.refreshToken = refreshToken;
|
|
240
|
-
return {
|
|
241
|
-
accessToken,
|
|
242
|
-
refreshToken,
|
|
243
|
-
user
|
|
244
|
-
};
|
|
245
|
-
} catch (error) {
|
|
246
|
-
throw this.handleError(error);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Log out user
|
|
252
|
-
*/
|
|
253
|
-
async logout() {
|
|
254
|
-
if (!this.refreshToken) return;
|
|
186
|
+
getCurrentUserId() {
|
|
187
|
+
if (!this.accessToken) return null;
|
|
255
188
|
try {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
});
|
|
189
|
+
const decoded = (0, _jwtDecode.jwtDecode)(this.accessToken);
|
|
190
|
+
return decoded.userId || decoded.id || null;
|
|
259
191
|
} catch (error) {
|
|
260
|
-
|
|
261
|
-
} finally {
|
|
262
|
-
this.accessToken = null;
|
|
263
|
-
this.refreshToken = null;
|
|
192
|
+
return null;
|
|
264
193
|
}
|
|
265
194
|
}
|
|
266
195
|
|
|
267
196
|
/**
|
|
268
|
-
*
|
|
269
|
-
* @
|
|
197
|
+
* Internal method to check if we have an access token
|
|
198
|
+
* @private
|
|
199
|
+
* @returns Boolean indicating if access token exists
|
|
200
|
+
* @internal - Use `isAuthenticated` from useOxy() context in UI components instead
|
|
270
201
|
*/
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
throw new Error('No refresh token available');
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// If a refresh is already in progress, return that promise
|
|
277
|
-
if (this.refreshPromise) {
|
|
278
|
-
return this.refreshPromise;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Create a new refresh promise
|
|
282
|
-
this.refreshPromise = (async () => {
|
|
283
|
-
try {
|
|
284
|
-
const res = await this.client.post('/auth/refresh', {
|
|
285
|
-
refreshToken: this.refreshToken
|
|
286
|
-
});
|
|
287
|
-
const {
|
|
288
|
-
accessToken,
|
|
289
|
-
refreshToken
|
|
290
|
-
} = res.data;
|
|
291
|
-
this.accessToken = accessToken;
|
|
292
|
-
this.refreshToken = refreshToken;
|
|
293
|
-
return {
|
|
294
|
-
accessToken,
|
|
295
|
-
refreshToken
|
|
296
|
-
};
|
|
297
|
-
} catch (error) {
|
|
298
|
-
this.accessToken = null;
|
|
299
|
-
this.refreshToken = null;
|
|
300
|
-
throw this.handleError(error);
|
|
301
|
-
} finally {
|
|
302
|
-
this.refreshPromise = null;
|
|
303
|
-
}
|
|
304
|
-
})();
|
|
305
|
-
return this.refreshPromise;
|
|
202
|
+
hasAccessToken() {
|
|
203
|
+
return this.accessToken !== null;
|
|
306
204
|
}
|
|
307
205
|
|
|
308
206
|
/**
|
|
@@ -311,6 +209,22 @@ class OxyServices {
|
|
|
311
209
|
*/
|
|
312
210
|
async validate() {
|
|
313
211
|
try {
|
|
212
|
+
// Check if token contains sessionId (new session-based system)
|
|
213
|
+
if (this.accessToken) {
|
|
214
|
+
try {
|
|
215
|
+
const decoded = (0, _jwtDecode.jwtDecode)(this.accessToken);
|
|
216
|
+
if (decoded.sessionId) {
|
|
217
|
+
// Use session-based validation
|
|
218
|
+
const res = await this.client.get(`/secure-session/validate/${decoded.sessionId}`);
|
|
219
|
+
return res.data.valid;
|
|
220
|
+
}
|
|
221
|
+
} catch (decodeError) {
|
|
222
|
+
// If token can't be decoded, fall back to old validation
|
|
223
|
+
console.warn('Error decoding JWT token for session validation:', decodeError);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Fall back to old validation method
|
|
314
228
|
const res = await this.client.get('/auth/validate');
|
|
315
229
|
return res.data.valid;
|
|
316
230
|
} catch (error) {
|
|
@@ -320,59 +234,6 @@ class OxyServices {
|
|
|
320
234
|
|
|
321
235
|
/* Session Management Methods */
|
|
322
236
|
|
|
323
|
-
/**
|
|
324
|
-
* Get active sessions for the authenticated user
|
|
325
|
-
* @returns Array of active session objects
|
|
326
|
-
*/
|
|
327
|
-
async getUserSessions() {
|
|
328
|
-
try {
|
|
329
|
-
const res = await this.client.get('/sessions');
|
|
330
|
-
return res.data;
|
|
331
|
-
} catch (error) {
|
|
332
|
-
throw this.handleError(error);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Logout from a specific session
|
|
338
|
-
* @param sessionId - The session ID to logout from
|
|
339
|
-
* @returns Success status
|
|
340
|
-
*/
|
|
341
|
-
async logoutSession(sessionId) {
|
|
342
|
-
try {
|
|
343
|
-
const res = await this.client.delete(`/sessions/${sessionId}`);
|
|
344
|
-
return res.data;
|
|
345
|
-
} catch (error) {
|
|
346
|
-
throw this.handleError(error);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Logout from all other sessions (keep current session active)
|
|
352
|
-
* @returns Success status
|
|
353
|
-
*/
|
|
354
|
-
async logoutOtherSessions() {
|
|
355
|
-
try {
|
|
356
|
-
const res = await this.client.post('/sessions/logout-others');
|
|
357
|
-
return res.data;
|
|
358
|
-
} catch (error) {
|
|
359
|
-
throw this.handleError(error);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Logout from all sessions
|
|
365
|
-
* @returns Success status
|
|
366
|
-
*/
|
|
367
|
-
async logoutAllSessions() {
|
|
368
|
-
try {
|
|
369
|
-
const res = await this.client.post('/sessions/logout-all');
|
|
370
|
-
return res.data;
|
|
371
|
-
} catch (error) {
|
|
372
|
-
throw this.handleError(error);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
237
|
/**
|
|
377
238
|
* Get device sessions for a specific session ID
|
|
378
239
|
* @param sessionId - The session ID to get device sessions for
|
|
@@ -1197,12 +1058,47 @@ class OxyServices {
|
|
|
1197
1058
|
}
|
|
1198
1059
|
|
|
1199
1060
|
/**
|
|
1200
|
-
*
|
|
1061
|
+
* Sign up a new user and create a session
|
|
1062
|
+
* @param username - Desired username
|
|
1063
|
+
* @param email - User's email address
|
|
1064
|
+
* @param password - User's password
|
|
1065
|
+
* @returns Object containing the message, token and user data
|
|
1066
|
+
*/
|
|
1067
|
+
async signUp(username, email, password) {
|
|
1068
|
+
try {
|
|
1069
|
+
// First, create the user account
|
|
1070
|
+
const res = await this.client.post('/secure-session/register', {
|
|
1071
|
+
username,
|
|
1072
|
+
email,
|
|
1073
|
+
password
|
|
1074
|
+
});
|
|
1075
|
+
const {
|
|
1076
|
+
message,
|
|
1077
|
+
user
|
|
1078
|
+
} = res.data;
|
|
1079
|
+
|
|
1080
|
+
// Then log them in to create a session
|
|
1081
|
+
const loginRes = await this.secureLogin(username, password);
|
|
1082
|
+
|
|
1083
|
+
// Get the access token for the session
|
|
1084
|
+
const tokenRes = await this.getTokenBySession(loginRes.sessionId);
|
|
1085
|
+
return {
|
|
1086
|
+
message,
|
|
1087
|
+
token: tokenRes.accessToken,
|
|
1088
|
+
user: loginRes.user
|
|
1089
|
+
};
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
throw this.handleError(error);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Secure login that creates a device-based session
|
|
1201
1097
|
* @param username - User's username or email
|
|
1202
1098
|
* @param password - User's password
|
|
1203
|
-
* @param deviceName - Optional device name
|
|
1204
|
-
* @param deviceFingerprint -
|
|
1205
|
-
* @returns
|
|
1099
|
+
* @param deviceName - Optional device name
|
|
1100
|
+
* @param deviceFingerprint - Optional device fingerprint
|
|
1101
|
+
* @returns Login response with session data
|
|
1206
1102
|
*/
|
|
1207
1103
|
async secureLogin(username, password, deviceName, deviceFingerprint) {
|
|
1208
1104
|
try {
|
|
@@ -1380,122 +1276,47 @@ class OxyServices {
|
|
|
1380
1276
|
}
|
|
1381
1277
|
|
|
1382
1278
|
/**
|
|
1383
|
-
*
|
|
1384
|
-
* This
|
|
1385
|
-
* @param options - Configuration options for the middleware
|
|
1279
|
+
* Create authentication middleware for Express.js applications
|
|
1280
|
+
* This is the recommended way to protect routes in server applications
|
|
1386
1281
|
* @returns Express middleware function
|
|
1387
1282
|
*/
|
|
1388
|
-
|
|
1389
|
-
const {
|
|
1390
|
-
loadFullUser = true,
|
|
1391
|
-
onError
|
|
1392
|
-
} = options;
|
|
1283
|
+
createAuthMiddleware() {
|
|
1393
1284
|
return async (req, res, next) => {
|
|
1394
1285
|
try {
|
|
1395
|
-
const authHeader = req.headers
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
if (!token) {
|
|
1399
|
-
const error = {
|
|
1400
|
-
message: 'Access token required',
|
|
1401
|
-
code: 'MISSING_TOKEN',
|
|
1402
|
-
status: 401
|
|
1403
|
-
};
|
|
1404
|
-
if (onError) {
|
|
1405
|
-
return onError(error);
|
|
1406
|
-
}
|
|
1286
|
+
const authHeader = req.headers.authorization;
|
|
1287
|
+
if (!authHeader?.startsWith('Bearer ')) {
|
|
1407
1288
|
return res.status(401).json({
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
});
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
// Create a temporary OxyServices instance with the token to validate it
|
|
1414
|
-
const tempOxyServices = new OxyServices({
|
|
1415
|
-
baseURL: this.client.defaults.baseURL || ''
|
|
1416
|
-
});
|
|
1417
|
-
tempOxyServices.setTokens(token, ''); // Set access token
|
|
1418
|
-
|
|
1419
|
-
// Validate token using the validate method
|
|
1420
|
-
const isValid = await tempOxyServices.validate();
|
|
1421
|
-
if (!isValid) {
|
|
1422
|
-
const error = {
|
|
1423
|
-
message: 'Invalid or expired token',
|
|
1424
|
-
code: 'INVALID_TOKEN',
|
|
1425
|
-
status: 403
|
|
1426
|
-
};
|
|
1427
|
-
if (onError) {
|
|
1428
|
-
return onError(error);
|
|
1429
|
-
}
|
|
1430
|
-
return res.status(403).json({
|
|
1431
|
-
message: 'Invalid or expired token',
|
|
1432
|
-
code: 'INVALID_TOKEN'
|
|
1289
|
+
error: 'Authentication required',
|
|
1290
|
+
message: 'Invalid or missing authorization header'
|
|
1433
1291
|
});
|
|
1434
1292
|
}
|
|
1293
|
+
const token = authHeader.split(' ')[1];
|
|
1435
1294
|
|
|
1436
|
-
//
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
const error = {
|
|
1443
|
-
message: 'Invalid token payload',
|
|
1444
|
-
code: 'INVALID_PAYLOAD',
|
|
1445
|
-
status: 403
|
|
1446
|
-
};
|
|
1447
|
-
if (onError) {
|
|
1448
|
-
return onError(error);
|
|
1449
|
-
}
|
|
1450
|
-
return res.status(403).json({
|
|
1451
|
-
message: 'Invalid token payload',
|
|
1452
|
-
code: 'INVALID_PAYLOAD'
|
|
1453
|
-
});
|
|
1454
|
-
}
|
|
1455
|
-
if (!userId) {
|
|
1456
|
-
const error = {
|
|
1457
|
-
message: 'Invalid token payload',
|
|
1458
|
-
code: 'INVALID_PAYLOAD',
|
|
1459
|
-
status: 403
|
|
1460
|
-
};
|
|
1461
|
-
if (onError) {
|
|
1462
|
-
return onError(error);
|
|
1463
|
-
}
|
|
1464
|
-
return res.status(403).json({
|
|
1465
|
-
message: 'Invalid token payload',
|
|
1466
|
-
code: 'INVALID_PAYLOAD'
|
|
1295
|
+
// Use the authenticateToken method
|
|
1296
|
+
const result = await this.authenticateToken(token);
|
|
1297
|
+
if (!result.valid) {
|
|
1298
|
+
return res.status(401).json({
|
|
1299
|
+
error: 'Invalid token',
|
|
1300
|
+
message: result.error || 'The provided authentication token is invalid'
|
|
1467
1301
|
});
|
|
1468
1302
|
}
|
|
1469
1303
|
|
|
1470
1304
|
// Set user information on request object
|
|
1471
|
-
req.userId = userId;
|
|
1305
|
+
req.userId = result.userId || undefined;
|
|
1472
1306
|
req.accessToken = token;
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
if (
|
|
1476
|
-
try {
|
|
1477
|
-
const userProfile = await tempOxyServices.getUserById(userId);
|
|
1478
|
-
req.user = userProfile;
|
|
1479
|
-
} catch (userError) {
|
|
1480
|
-
// If we can't load user, continue with just ID
|
|
1481
|
-
req.user = {
|
|
1482
|
-
id: userId
|
|
1483
|
-
};
|
|
1484
|
-
}
|
|
1485
|
-
} else {
|
|
1307
|
+
if (result.user) {
|
|
1308
|
+
req.user = result.user;
|
|
1309
|
+
} else if (result.userId) {
|
|
1486
1310
|
req.user = {
|
|
1487
|
-
id: userId
|
|
1311
|
+
id: result.userId
|
|
1488
1312
|
};
|
|
1489
1313
|
}
|
|
1490
1314
|
next();
|
|
1491
1315
|
} catch (error) {
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
return res.status(apiError.status || 500).json({
|
|
1497
|
-
message: apiError.message,
|
|
1498
|
-
code: apiError.code
|
|
1316
|
+
console.error('Auth middleware error:', error);
|
|
1317
|
+
return res.status(500).json({
|
|
1318
|
+
error: 'Server error',
|
|
1319
|
+
message: 'An error occurred while authenticating your request'
|
|
1499
1320
|
});
|
|
1500
1321
|
}
|
|
1501
1322
|
};
|
|
@@ -1516,54 +1337,71 @@ class OxyServices {
|
|
|
1516
1337
|
};
|
|
1517
1338
|
}
|
|
1518
1339
|
|
|
1519
|
-
//
|
|
1520
|
-
const tempOxyServices = new OxyServices({
|
|
1521
|
-
baseURL: this.client.defaults.baseURL || ''
|
|
1522
|
-
});
|
|
1523
|
-
tempOxyServices.setTokens(token, '');
|
|
1524
|
-
|
|
1525
|
-
// Validate token
|
|
1526
|
-
const isValid = await tempOxyServices.validate();
|
|
1527
|
-
if (!isValid) {
|
|
1528
|
-
return {
|
|
1529
|
-
valid: false,
|
|
1530
|
-
error: 'Invalid or expired token'
|
|
1531
|
-
};
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
// Get user ID from token using JWT decode
|
|
1535
|
-
let userId = null;
|
|
1340
|
+
// Check if token contains sessionId (new session-based system)
|
|
1536
1341
|
try {
|
|
1537
1342
|
const decoded = (0, _jwtDecode.jwtDecode)(token);
|
|
1538
|
-
userId = decoded.userId || decoded.id;
|
|
1343
|
+
const userId = decoded.userId || decoded.id;
|
|
1344
|
+
if (decoded.sessionId) {
|
|
1345
|
+
// Use session-based validation
|
|
1346
|
+
const tempOxyServices = new OxyServices({
|
|
1347
|
+
baseURL: this.client.defaults.baseURL || ''
|
|
1348
|
+
});
|
|
1349
|
+
tempOxyServices.setTokens(token, '');
|
|
1350
|
+
const validation = await tempOxyServices.validateSession(decoded.sessionId);
|
|
1351
|
+
if (validation.valid) {
|
|
1352
|
+
return {
|
|
1353
|
+
valid: true,
|
|
1354
|
+
userId,
|
|
1355
|
+
user: validation.user
|
|
1356
|
+
};
|
|
1357
|
+
} else {
|
|
1358
|
+
return {
|
|
1359
|
+
valid: false,
|
|
1360
|
+
error: 'Invalid or expired session'
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
} else {
|
|
1364
|
+
// Use old validation method
|
|
1365
|
+
const tempOxyServices = new OxyServices({
|
|
1366
|
+
baseURL: this.client.defaults.baseURL || ''
|
|
1367
|
+
});
|
|
1368
|
+
tempOxyServices.setTokens(token, '');
|
|
1369
|
+
const isValid = await tempOxyServices.validate();
|
|
1370
|
+
if (!isValid) {
|
|
1371
|
+
return {
|
|
1372
|
+
valid: false,
|
|
1373
|
+
error: 'Invalid or expired token'
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
if (!userId) {
|
|
1377
|
+
return {
|
|
1378
|
+
valid: false,
|
|
1379
|
+
error: 'Invalid token payload'
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
// Try to get user profile
|
|
1384
|
+
let user;
|
|
1385
|
+
try {
|
|
1386
|
+
user = await tempOxyServices.getUserById(userId);
|
|
1387
|
+
} catch (error) {
|
|
1388
|
+
// Continue without full user data
|
|
1389
|
+
user = {
|
|
1390
|
+
id: userId
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
1393
|
+
return {
|
|
1394
|
+
valid: true,
|
|
1395
|
+
userId,
|
|
1396
|
+
user
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1539
1399
|
} catch (decodeError) {
|
|
1540
1400
|
return {
|
|
1541
1401
|
valid: false,
|
|
1542
1402
|
error: 'Invalid token payload'
|
|
1543
1403
|
};
|
|
1544
1404
|
}
|
|
1545
|
-
if (!userId) {
|
|
1546
|
-
return {
|
|
1547
|
-
valid: false,
|
|
1548
|
-
error: 'Invalid token payload'
|
|
1549
|
-
};
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
|
-
// Try to get user profile
|
|
1553
|
-
let user;
|
|
1554
|
-
try {
|
|
1555
|
-
user = await tempOxyServices.getUserById(userId);
|
|
1556
|
-
} catch (error) {
|
|
1557
|
-
// Continue without full user data
|
|
1558
|
-
user = {
|
|
1559
|
-
id: userId
|
|
1560
|
-
};
|
|
1561
|
-
}
|
|
1562
|
-
return {
|
|
1563
|
-
valid: true,
|
|
1564
|
-
userId,
|
|
1565
|
-
user
|
|
1566
|
-
};
|
|
1567
1405
|
} catch (error) {
|
|
1568
1406
|
return {
|
|
1569
1407
|
valid: false,
|
|
@@ -1895,6 +1733,14 @@ class OxyServices {
|
|
|
1895
1733
|
// Default export for backward compatibility
|
|
1896
1734
|
exports.OxyServices = OxyServices;
|
|
1897
1735
|
var _default = exports.default = OxyServices; // Re-export all models and types for convenience
|
|
1736
|
+
// Clean middleware exports - these will be available for server-side use
|
|
1737
|
+
// Note: These require Express.js and are only for server-side applications
|
|
1738
|
+
|
|
1739
|
+
// Export a simple function to create auth middleware
|
|
1740
|
+
const createAuthMiddleware = oxyServices => {
|
|
1741
|
+
return oxyServices.createAuthMiddleware();
|
|
1742
|
+
};
|
|
1743
|
+
exports.createAuthMiddleware = createAuthMiddleware;
|
|
1898
1744
|
if (typeof FormData === 'undefined') {
|
|
1899
1745
|
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.');
|
|
1900
1746
|
}
|