@oxyhq/services 5.7.5 → 5.8.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.
Files changed (239) hide show
  1. package/README.md +76 -76
  2. package/lib/commonjs/core/index.js +177 -102
  3. package/lib/commonjs/core/index.js.map +1 -1
  4. package/lib/commonjs/index.js +88 -29
  5. package/lib/commonjs/index.js.map +1 -1
  6. package/lib/commonjs/node/createAuth.js +585 -7
  7. package/lib/commonjs/node/createAuth.js.map +1 -1
  8. package/lib/commonjs/node/index.js +38 -1
  9. package/lib/commonjs/node/index.js.map +1 -1
  10. package/lib/commonjs/ui/components/Avatar.js +15 -6
  11. package/lib/commonjs/ui/components/Avatar.js.map +1 -1
  12. package/lib/commonjs/ui/components/GroupedItem.js +58 -13
  13. package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
  14. package/lib/commonjs/ui/components/GroupedSection.js +7 -1
  15. package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
  16. package/lib/commonjs/ui/components/Header.js +322 -0
  17. package/lib/commonjs/ui/components/Header.js.map +1 -0
  18. package/lib/commonjs/ui/components/OxyProvider.js +23 -7
  19. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  20. package/lib/commonjs/ui/components/index.js +7 -0
  21. package/lib/commonjs/ui/components/index.js.map +1 -1
  22. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +1 -1
  23. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
  24. package/lib/commonjs/ui/components/internal/TextField.js +606 -546
  25. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
  26. package/lib/commonjs/ui/components/internal/TextField.md +436 -0
  27. package/lib/commonjs/ui/context/OxyContext.js +122 -78
  28. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  29. package/lib/commonjs/ui/hooks/useSessionSocket.js +5 -2
  30. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
  31. package/lib/commonjs/ui/navigation/OxyRouter.js +1 -1
  32. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  33. package/lib/commonjs/ui/screens/AccountCenterScreen.js +6 -6
  34. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  35. package/lib/commonjs/ui/screens/AccountManagementDemo.js +3 -3
  36. package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +1 -1
  37. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +241 -598
  38. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +1151 -406
  40. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  41. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +135 -237
  42. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  43. package/lib/commonjs/ui/screens/AppInfoScreen.js +246 -463
  44. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  45. package/lib/commonjs/ui/screens/FeedbackScreen.js +3 -3
  46. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  47. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +808 -650
  48. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/RecoverAccountScreen.js +51 -72
  50. package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
  51. package/lib/commonjs/ui/screens/SessionManagementScreen.js +11 -29
  52. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  53. package/lib/commonjs/ui/screens/SignInScreen.js +30 -303
  54. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  55. package/lib/commonjs/ui/screens/SignUpScreen.js +4 -4
  56. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  57. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +19 -31
  58. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  59. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +7 -10
  60. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  61. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js +11 -5
  62. package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
  63. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js +11 -4
  64. package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
  65. package/lib/commonjs/ui/stores/authStore.js +12 -0
  66. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  67. package/lib/commonjs/ui/styles/authStyles.js +337 -0
  68. package/lib/commonjs/ui/styles/authStyles.js.map +1 -0
  69. package/lib/commonjs/ui/styles/index.js +11 -0
  70. package/lib/commonjs/ui/styles/index.js.map +1 -1
  71. package/lib/module/core/index.js +177 -41
  72. package/lib/module/core/index.js.map +1 -1
  73. package/lib/module/index.js +26 -4
  74. package/lib/module/index.js.map +1 -1
  75. package/lib/module/node/createAuth.js +584 -7
  76. package/lib/module/node/createAuth.js.map +1 -1
  77. package/lib/module/node/index.js +7 -1
  78. package/lib/module/node/index.js.map +1 -1
  79. package/lib/module/ui/components/Avatar.js +15 -6
  80. package/lib/module/ui/components/Avatar.js.map +1 -1
  81. package/lib/module/ui/components/GroupedItem.js +59 -14
  82. package/lib/module/ui/components/GroupedItem.js.map +1 -1
  83. package/lib/module/ui/components/GroupedSection.js +7 -1
  84. package/lib/module/ui/components/GroupedSection.js.map +1 -1
  85. package/lib/module/ui/components/Header.js +317 -0
  86. package/lib/module/ui/components/Header.js.map +1 -0
  87. package/lib/module/ui/components/OxyProvider.js +25 -9
  88. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  89. package/lib/module/ui/components/index.js +1 -0
  90. package/lib/module/ui/components/index.js.map +1 -1
  91. package/lib/module/ui/components/internal/GroupedPillButtons.js +1 -1
  92. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
  93. package/lib/module/ui/components/internal/TextField.js +607 -547
  94. package/lib/module/ui/components/internal/TextField.js.map +1 -1
  95. package/lib/module/ui/components/internal/TextField.md +436 -0
  96. package/lib/module/ui/context/OxyContext.js +121 -77
  97. package/lib/module/ui/context/OxyContext.js.map +1 -1
  98. package/lib/module/ui/hooks/useSessionSocket.js +5 -2
  99. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
  100. package/lib/module/ui/navigation/OxyRouter.js +1 -1
  101. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  102. package/lib/module/ui/screens/AccountCenterScreen.js +6 -6
  103. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  104. package/lib/module/ui/screens/AccountManagementDemo.js +3 -3
  105. package/lib/module/ui/screens/AccountManagementDemo.js.map +1 -1
  106. package/lib/module/ui/screens/AccountOverviewScreen.js +242 -597
  107. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  108. package/lib/module/ui/screens/AccountSettingsScreen.js +1152 -407
  109. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  110. package/lib/module/ui/screens/AccountSwitcherScreen.js +135 -237
  111. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  112. package/lib/module/ui/screens/AppInfoScreen.js +248 -465
  113. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  114. package/lib/module/ui/screens/FeedbackScreen.js +3 -3
  115. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  116. package/lib/module/ui/screens/PaymentGatewayScreen.js +809 -651
  117. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  118. package/lib/module/ui/screens/RecoverAccountScreen.js +53 -74
  119. package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
  120. package/lib/module/ui/screens/SessionManagementScreen.js +11 -29
  121. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  122. package/lib/module/ui/screens/SignInScreen.js +32 -305
  123. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  124. package/lib/module/ui/screens/SignUpScreen.js +5 -5
  125. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  126. package/lib/module/ui/screens/internal/SignInPasswordStep.js +19 -31
  127. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  128. package/lib/module/ui/screens/internal/SignInUsernameStep.js +7 -10
  129. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  130. package/lib/module/ui/screens/internal/SignUpIdentityStep.js +11 -5
  131. package/lib/module/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
  132. package/lib/module/ui/screens/internal/SignUpSecurityStep.js +11 -4
  133. package/lib/module/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
  134. package/lib/module/ui/stores/authStore.js +12 -0
  135. package/lib/module/ui/stores/authStore.js.map +1 -1
  136. package/lib/module/ui/styles/authStyles.js +332 -0
  137. package/lib/module/ui/styles/authStyles.js.map +1 -0
  138. package/lib/module/ui/styles/index.js +1 -0
  139. package/lib/module/ui/styles/index.js.map +1 -1
  140. package/lib/typescript/core/index.d.ts +68 -24
  141. package/lib/typescript/core/index.d.ts.map +1 -1
  142. package/lib/typescript/index.d.ts +13 -3
  143. package/lib/typescript/index.d.ts.map +1 -1
  144. package/lib/typescript/node/createAuth.d.ts +112 -0
  145. package/lib/typescript/node/createAuth.d.ts.map +1 -1
  146. package/lib/typescript/node/index.d.ts +2 -0
  147. package/lib/typescript/node/index.d.ts.map +1 -1
  148. package/lib/typescript/ui/components/Avatar.d.ts.map +1 -1
  149. package/lib/typescript/ui/components/GroupedItem.d.ts +6 -0
  150. package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
  151. package/lib/typescript/ui/components/GroupedSection.d.ts +6 -0
  152. package/lib/typescript/ui/components/GroupedSection.d.ts.map +1 -1
  153. package/lib/typescript/ui/components/Header.d.ts +22 -0
  154. package/lib/typescript/ui/components/Header.d.ts.map +1 -0
  155. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  156. package/lib/typescript/ui/components/index.d.ts +1 -0
  157. package/lib/typescript/ui/components/index.d.ts.map +1 -1
  158. package/lib/typescript/ui/components/internal/TextField.d.ts +31 -16
  159. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
  160. package/lib/typescript/ui/context/OxyContext.d.ts +5 -2
  161. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  162. package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
  163. package/lib/typescript/ui/navigation/types.d.ts +9 -2
  164. package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
  165. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  166. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  167. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  168. package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -1
  169. package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
  170. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts +5 -1
  171. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
  172. package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  173. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  174. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +1 -1
  175. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
  176. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +0 -1
  177. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
  178. package/lib/typescript/ui/screens/internal/SignUpIdentityStep.d.ts.map +1 -1
  179. package/lib/typescript/ui/screens/internal/SignUpSecurityStep.d.ts.map +1 -1
  180. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  181. package/lib/typescript/ui/styles/authStyles.d.ts +326 -0
  182. package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -0
  183. package/lib/typescript/ui/styles/index.d.ts +1 -0
  184. package/lib/typescript/ui/styles/index.d.ts.map +1 -1
  185. package/package.json +1 -4
  186. package/src/core/index.ts +195 -41
  187. package/src/index.ts +72 -4
  188. package/src/node/createAuth.ts +623 -7
  189. package/src/node/index.ts +19 -1
  190. package/src/ui/components/Avatar.tsx +11 -5
  191. package/src/ui/components/GroupedItem.tsx +57 -9
  192. package/src/ui/components/GroupedSection.tsx +12 -0
  193. package/src/ui/components/Header.tsx +364 -0
  194. package/src/ui/components/OxyProvider.tsx +31 -15
  195. package/src/ui/components/index.ts +1 -0
  196. package/src/ui/components/internal/GroupedPillButtons.tsx +1 -1
  197. package/src/ui/components/internal/TextField.md +436 -0
  198. package/src/ui/components/internal/TextField.tsx +720 -620
  199. package/src/ui/context/OxyContext.tsx +150 -63
  200. package/src/ui/hooks/useSessionSocket.ts +5 -2
  201. package/src/ui/navigation/OxyRouter.tsx +1 -1
  202. package/src/ui/navigation/types.ts +10 -2
  203. package/src/ui/screens/AccountCenterScreen.tsx +5 -5
  204. package/src/ui/screens/AccountManagementDemo.tsx +9 -9
  205. package/src/ui/screens/AccountOverviewScreen.tsx +265 -414
  206. package/src/ui/screens/AccountSettingsScreen.tsx +1165 -403
  207. package/src/ui/screens/AccountSwitcherScreen.tsx +158 -202
  208. package/src/ui/screens/AppInfoScreen.tsx +270 -497
  209. package/src/ui/screens/FeedbackScreen.tsx +3 -3
  210. package/src/ui/screens/PaymentGatewayScreen.tsx +668 -365
  211. package/src/ui/screens/ProfileScreen.tsx +5 -5
  212. package/src/ui/screens/RecoverAccountScreen.tsx +46 -74
  213. package/src/ui/screens/SessionManagementScreen.tsx +14 -22
  214. package/src/ui/screens/SignInScreen.tsx +27 -294
  215. package/src/ui/screens/SignUpScreen.tsx +5 -5
  216. package/src/ui/screens/internal/SignInPasswordStep.tsx +11 -22
  217. package/src/ui/screens/internal/SignInUsernameStep.tsx +3 -10
  218. package/src/ui/screens/internal/SignUpIdentityStep.tsx +2 -5
  219. package/src/ui/screens/internal/SignUpSecurityStep.tsx +3 -4
  220. package/src/ui/stores/authStore.ts +12 -0
  221. package/src/ui/styles/authStyles.ts +352 -0
  222. package/src/ui/styles/index.ts +1 -0
  223. package/lib/commonjs/core/auth-manager.js +0 -440
  224. package/lib/commonjs/core/auth-manager.js.map +0 -1
  225. package/lib/commonjs/core/use-auth.js +0 -244
  226. package/lib/commonjs/core/use-auth.js.map +0 -1
  227. package/lib/module/core/auth-manager.js +0 -432
  228. package/lib/module/core/auth-manager.js.map +0 -1
  229. package/lib/module/core/use-auth.js +0 -235
  230. package/lib/module/core/use-auth.js.map +0 -1
  231. package/lib/typescript/core/auth-manager.d.ts +0 -136
  232. package/lib/typescript/core/auth-manager.d.ts.map +0 -1
  233. package/lib/typescript/core/use-auth.d.ts +0 -79
  234. package/lib/typescript/core/use-auth.d.ts.map +0 -1
  235. package/src/__tests__/middleware.test.ts +0 -105
  236. package/src/__tests__/setup.ts +0 -10
  237. package/src/__tests__/zero-config-auth.test.ts +0 -607
  238. package/src/core/auth-manager.ts +0 -500
  239. package/src/core/use-auth.tsx +0 -245
@@ -2,10 +2,423 @@
2
2
 
3
3
  import express from 'express';
4
4
  import { OxyServices } from '../core';
5
+ import { jwtDecode } from 'jwt-decode';
6
+
7
+ // Types for enhanced authentication
8
+
9
+ // User cache for performance
10
+ class UserCache {
11
+ cache = new Map();
12
+ constructor(ttl = 300) {
13
+ // 5 minutes default
14
+ this.ttl = ttl * 1000;
15
+ }
16
+ set(userId, user) {
17
+ this.cache.set(userId, {
18
+ user,
19
+ expiresAt: Date.now() + this.ttl
20
+ });
21
+ }
22
+ get(userId) {
23
+ const item = this.cache.get(userId);
24
+ if (!item || Date.now() > item.expiresAt) {
25
+ this.cache.delete(userId);
26
+ return null;
27
+ }
28
+ return item.user;
29
+ }
30
+ clear() {
31
+ this.cache.clear();
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Enhanced OxyAuth class for backend authentication
37
+ */
38
+ export class OxyAuth {
39
+ userCache = null;
40
+ constructor(options) {
41
+ this.options = {
42
+ loadFullUser: true,
43
+ enableSessionAuth: true,
44
+ enableDeviceAuth: true,
45
+ cacheUserData: true,
46
+ userCacheTTL: 300,
47
+ ...options
48
+ };
49
+ this.oxy = new OxyServices({
50
+ baseURL: options.baseURL
51
+ });
52
+ if (this.options.cacheUserData) {
53
+ this.userCache = new UserCache(this.options.userCacheTTL);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Create authentication middleware
59
+ */
60
+ createAuthMiddleware(options = {}) {
61
+ return async (req, res, next) => {
62
+ try {
63
+ const result = await this.authenticateRequest(req);
64
+ if (!result.valid && options.required !== false) {
65
+ const error = {
66
+ message: 'Authentication required',
67
+ code: 'AUTH_REQUIRED'
68
+ };
69
+ if (options.onError) {
70
+ options.onError(error, req, res);
71
+ } else {
72
+ res.status(401).json(error);
73
+ }
74
+ return;
75
+ }
76
+
77
+ // Check roles if specified
78
+ if (result.valid && options.roles && result.user) {
79
+ const hasRole = options.roles.some(role => result.user.roles?.includes(role) || result.user.role === role);
80
+ if (!hasRole) {
81
+ const error = {
82
+ message: 'Insufficient permissions',
83
+ code: 'INSUFFICIENT_ROLES'
84
+ };
85
+ if (options.onError) {
86
+ options.onError(error, req, res);
87
+ } else {
88
+ res.status(403).json(error);
89
+ }
90
+ return;
91
+ }
92
+ }
93
+
94
+ // Check permissions if specified
95
+ if (result.valid && options.permissions && result.userId) {
96
+ for (const permission of options.permissions) {
97
+ const hasPermission = await this.hasPermission(result.userId, permission);
98
+ if (!hasPermission) {
99
+ const error = {
100
+ message: 'Insufficient permissions',
101
+ code: 'INSUFFICIENT_PERMISSIONS'
102
+ };
103
+ if (options.onError) {
104
+ options.onError(error, req, res);
105
+ } else {
106
+ res.status(403).json(error);
107
+ }
108
+ return;
109
+ }
110
+ }
111
+ }
112
+ next();
113
+ } catch (error) {
114
+ if (options.onError) {
115
+ options.onError(error, req, res);
116
+ } else {
117
+ res.status(500).json({
118
+ message: 'Authentication error'
119
+ });
120
+ }
121
+ }
122
+ };
123
+ }
124
+
125
+ /**
126
+ * Authenticate request and populate user data
127
+ */
128
+ async authenticateRequest(req) {
129
+ // Try JWT token first
130
+ const authHeader = req.headers.authorization;
131
+ if (authHeader && authHeader.startsWith('Bearer ')) {
132
+ const token = authHeader.substring(7);
133
+ const result = await this.validateToken(token);
134
+ if (result.valid) {
135
+ req.user = result.user;
136
+ req.userId = result.userId;
137
+ req.accessToken = token;
138
+ return {
139
+ ...result,
140
+ accessToken: token
141
+ };
142
+ }
143
+ }
144
+
145
+ // Try session-based auth
146
+ if (this.options.enableSessionAuth) {
147
+ const sessionId = req.headers['x-session-id'];
148
+ if (sessionId) {
149
+ const result = await this.validateSession(sessionId);
150
+ if (result.valid) {
151
+ req.user = result.user;
152
+ req.userId = result.userId;
153
+ req.sessionId = sessionId;
154
+ return result;
155
+ }
156
+ }
157
+ }
158
+
159
+ // Try device-based auth
160
+ if (this.options.enableDeviceAuth) {
161
+ const deviceFingerprint = req.headers['x-device-fingerprint'];
162
+ const userId = req.headers['x-user-id'];
163
+ if (deviceFingerprint && userId) {
164
+ const result = await this.validateDevice(userId, deviceFingerprint);
165
+ if (result.valid) {
166
+ req.user = result.user;
167
+ req.userId = result.userId;
168
+ req.deviceFingerprint = deviceFingerprint;
169
+ return result;
170
+ }
171
+ }
172
+ }
173
+ return {
174
+ valid: false,
175
+ error: 'No valid authentication found'
176
+ };
177
+ }
178
+
179
+ /**
180
+ * Validate JWT token
181
+ */
182
+ async validateToken(token) {
183
+ try {
184
+ // Local JWT validation if secret is provided
185
+ if (this.options.jwtSecret) {
186
+ const decoded = jwtDecode(token);
187
+ const currentTime = Math.floor(Date.now() / 1000);
188
+ if (decoded.exp && decoded.exp < currentTime) {
189
+ return {
190
+ valid: false,
191
+ error: 'Token expired',
192
+ code: 'TOKEN_EXPIRED',
193
+ expiresAt: decoded.exp
194
+ };
195
+ }
196
+ const userId = decoded.userId || decoded.id;
197
+ if (!userId) {
198
+ return {
199
+ valid: false,
200
+ error: 'Invalid token payload',
201
+ code: 'INVALID_PAYLOAD'
202
+ };
203
+ }
204
+
205
+ // Get user data from cache or API
206
+ let user = this.userCache?.get(userId);
207
+ const cached = !!user;
208
+ if (!user && this.options.loadFullUser) {
209
+ try {
210
+ user = await this.oxy.getUserById(userId);
211
+ this.userCache?.set(userId, user);
212
+ } catch (error) {
213
+ user = {
214
+ id: userId
215
+ };
216
+ }
217
+ } else if (!user) {
218
+ user = {
219
+ id: userId
220
+ };
221
+ }
222
+ return {
223
+ valid: true,
224
+ userId,
225
+ user,
226
+ expiresAt: decoded.exp,
227
+ cached
228
+ };
229
+ }
230
+
231
+ // Remote validation using OxyServices
232
+ const tempOxy = new OxyServices({
233
+ baseURL: this.oxy.getBaseURL()
234
+ });
235
+ tempOxy.setTokens(token, '');
236
+ const isValid = await tempOxy.validate();
237
+ if (!isValid) {
238
+ return {
239
+ valid: false,
240
+ error: 'Invalid token',
241
+ code: 'INVALID_TOKEN'
242
+ };
243
+ }
244
+ const userId = tempOxy.getCurrentUserId();
245
+ if (!userId) {
246
+ return {
247
+ valid: false,
248
+ error: 'Invalid token payload',
249
+ code: 'INVALID_PAYLOAD'
250
+ };
251
+ }
252
+
253
+ // Get user data
254
+ let user = this.userCache?.get(userId);
255
+ const cached = !!user;
256
+ if (!user && this.options.loadFullUser) {
257
+ try {
258
+ user = await tempOxy.getUserById(userId);
259
+ this.userCache?.set(userId, user);
260
+ } catch (error) {
261
+ user = {
262
+ id: userId
263
+ };
264
+ }
265
+ } else if (!user) {
266
+ user = {
267
+ id: userId
268
+ };
269
+ }
270
+ return {
271
+ valid: true,
272
+ userId,
273
+ user,
274
+ cached
275
+ };
276
+ } catch (error) {
277
+ return {
278
+ valid: false,
279
+ error: 'Token validation failed',
280
+ code: 'VALIDATION_ERROR'
281
+ };
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Validate session-based authentication
287
+ */
288
+ async validateSession(sessionId, deviceFingerprint) {
289
+ try {
290
+ // This would integrate with your session management system
291
+ // For now, it's a placeholder implementation
292
+ return {
293
+ valid: false,
294
+ error: 'Session validation not implemented',
295
+ code: 'NOT_IMPLEMENTED'
296
+ };
297
+ } catch (error) {
298
+ return {
299
+ valid: false,
300
+ error: 'Session validation failed',
301
+ code: 'VALIDATION_ERROR'
302
+ };
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Validate device-based authentication
308
+ */
309
+ async validateDevice(userId, deviceFingerprint) {
310
+ try {
311
+ // This would validate device fingerprint against stored data
312
+ // For now, it's a placeholder implementation
313
+ return {
314
+ valid: false,
315
+ error: 'Device validation not implemented',
316
+ code: 'NOT_IMPLEMENTED'
317
+ };
318
+ } catch (error) {
319
+ return {
320
+ valid: false,
321
+ error: 'Device validation failed',
322
+ code: 'VALIDATION_ERROR'
323
+ };
324
+ }
325
+ }
326
+
327
+ /**
328
+ * Create role-based middleware
329
+ */
330
+ requireRole(roles) {
331
+ const roleArray = Array.isArray(roles) ? roles : [roles];
332
+ return this.createAuthMiddleware({
333
+ required: true,
334
+ roles: roleArray
335
+ });
336
+ }
337
+
338
+ /**
339
+ * Create permission-based middleware
340
+ */
341
+ requirePermission(permissions) {
342
+ const permissionArray = Array.isArray(permissions) ? permissions : [permissions];
343
+ return this.createAuthMiddleware({
344
+ required: true,
345
+ permissions: permissionArray
346
+ });
347
+ }
348
+
349
+ /**
350
+ * Create optional authentication middleware
351
+ */
352
+ optionalAuth() {
353
+ return this.createAuthMiddleware({
354
+ required: false,
355
+ onError: () => {} // No error thrown for optional auth
356
+ });
357
+ }
358
+
359
+ /**
360
+ * Clear user cache
361
+ */
362
+ clearCache() {
363
+ this.userCache?.clear();
364
+ }
365
+
366
+ /**
367
+ * Check if user data is cached for a given token
368
+ */
369
+ isUserCached(token) {
370
+ try {
371
+ const decoded = jwtDecode(token);
372
+ const userId = decoded.userId || decoded.id;
373
+ return userId ? this.userCache?.get(userId) !== null : false;
374
+ } catch {
375
+ return false;
376
+ }
377
+ }
378
+
379
+ /**
380
+ * Check if user has a specific permission
381
+ */
382
+ async hasPermission(userId, permission) {
383
+ try {
384
+ // This is a placeholder implementation
385
+ // In a real implementation, you would check against user roles/permissions
386
+ const user = this.userCache?.get(userId) || (await this.oxy.getUserById(userId));
387
+ return user?.permissions?.includes(permission) || user?.role === 'admin' || false;
388
+ } catch {
389
+ return false;
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Get OxyServices instance
395
+ */
396
+ getOxyServices() {
397
+ return this.oxy;
398
+ }
399
+ }
400
+ /**
401
+ * Enhanced createAuth function that provides both router and middleware capabilities
402
+ *
403
+ * This is a unified authentication system that:
404
+ * 1. Maintains backward compatibility with the old router-based approach
405
+ * 2. Adds powerful new middleware capabilities
406
+ * 3. Includes caching, role-based access, and performance optimizations
407
+ * 4. Supports multiple authentication strategies
408
+ */
5
409
  export function createAuth(options) {
6
- const oxy = new OxyServices({
7
- baseURL: options.baseURL
8
- });
410
+ // Create the enhanced OxyAuth instance
411
+ const authOptions = {
412
+ baseURL: options.baseURL,
413
+ jwtSecret: options.jwtSecret,
414
+ loadFullUser: options.loadFullUser ?? true,
415
+ enableSessionAuth: options.enableSessionAuth ?? true,
416
+ enableDeviceAuth: options.enableDeviceAuth ?? true,
417
+ cacheUserData: options.cacheUserData ?? true,
418
+ userCacheTTL: options.userCacheTTL ?? 300
419
+ };
420
+ const oxyAuth = new OxyAuth(authOptions);
421
+ const oxy = oxyAuth.getOxyServices();
9
422
  const router = express.Router();
10
423
 
11
424
  // Helper to handle async route functions
@@ -18,73 +431,237 @@ export function createAuth(options) {
18
431
  });
19
432
  }
20
433
  };
434
+
435
+ // Enhanced signup with validation
21
436
  router.post('/signup', wrap(async (req, res) => {
22
437
  const {
23
438
  username,
24
439
  email,
25
440
  password
26
441
  } = req.body;
442
+
443
+ // Enhanced validation
444
+ if (!username || !email || !password) {
445
+ return res.status(400).json({
446
+ message: 'Username, email, and password are required'
447
+ });
448
+ }
27
449
  const result = await oxy.signUp(username, email, password);
28
450
  res.json(result);
29
451
  }));
452
+
453
+ // Enhanced login with device fingerprinting
30
454
  router.post('/login', wrap(async (req, res) => {
31
455
  const {
32
456
  username,
33
- password
457
+ password,
458
+ deviceFingerprint
34
459
  } = req.body;
460
+ if (!username || !password) {
461
+ return res.status(400).json({
462
+ message: 'Username and password are required'
463
+ });
464
+ }
35
465
  const result = await oxy.login(username, password);
466
+
467
+ // Store device fingerprint if provided
468
+ if (deviceFingerprint && result.user?.id) {
469
+ // This could be stored in a database for device tracking
470
+ console.log(`Device login: ${deviceFingerprint} for user ${result.user.id}`);
471
+ }
36
472
  res.json(result);
37
473
  }));
474
+
475
+ // Enhanced logout with session management
38
476
  router.post('/logout', wrap(async (req, res) => {
39
477
  const token = req.headers.authorization?.split(' ')[1];
40
478
  const refreshToken = req.body.refreshToken;
479
+ const sessionId = req.body.sessionId;
41
480
  if (token) oxy.setTokens(token, refreshToken);
42
- await oxy.logout();
481
+
482
+ // Enhanced logout with session tracking
483
+ if (sessionId) {
484
+ await oxy.logoutSession(sessionId);
485
+ } else {
486
+ await oxy.logout();
487
+ }
43
488
  res.json({
44
489
  success: true
45
490
  });
46
491
  }));
492
+
493
+ // Enhanced token refresh
47
494
  router.post('/refresh', wrap(async (req, res) => {
48
495
  const refreshToken = req.body.refreshToken;
49
496
  const accessToken = req.headers.authorization?.split(' ')[1] || '';
497
+ if (!refreshToken) {
498
+ return res.status(400).json({
499
+ message: 'Refresh token is required'
500
+ });
501
+ }
50
502
  oxy.setTokens(accessToken, refreshToken);
51
503
  const tokens = await oxy.refreshTokens();
52
504
  res.json(tokens);
53
505
  }));
506
+
507
+ // Enhanced token validation with caching
54
508
  router.get('/validate', wrap(async (req, res) => {
55
509
  const token = req.headers.authorization?.split(' ')[1] || '';
510
+ if (!token) {
511
+ return res.status(401).json({
512
+ valid: false,
513
+ message: 'No token provided'
514
+ });
515
+ }
56
516
  oxy.setTokens(token, '');
57
517
  const valid = await oxy.validate();
518
+
519
+ // Enhanced response with more details
58
520
  res.json({
59
- valid
521
+ valid,
522
+ timestamp: new Date().toISOString(),
523
+ cached: oxyAuth.isUserCached(token) // Check if user data is cached
60
524
  });
61
525
  }));
526
+
527
+ // Enhanced sessions management
62
528
  router.get('/sessions', wrap(async (req, res) => {
63
529
  const token = req.headers.authorization?.split(' ')[1] || '';
530
+ if (!token) {
531
+ return res.status(401).json({
532
+ message: 'Authentication required'
533
+ });
534
+ }
64
535
  oxy.setTokens(token, '');
65
536
  const sessions = await oxy.getUserSessions();
66
537
  res.json(sessions);
67
538
  }));
539
+
540
+ // Enhanced session deletion
68
541
  router.delete('/sessions/:id', wrap(async (req, res) => {
69
542
  const token = req.headers.authorization?.split(' ')[1] || '';
543
+ if (!token) {
544
+ return res.status(401).json({
545
+ message: 'Authentication required'
546
+ });
547
+ }
70
548
  oxy.setTokens(token, '');
71
549
  const result = await oxy.logoutSession(req.params.id);
550
+
551
+ // Clear cache for this user if logout was successful
552
+ if (result.success) {
553
+ oxyAuth.clearCache();
554
+ }
72
555
  res.json(result);
73
556
  }));
557
+
558
+ // Enhanced logout other sessions
74
559
  router.post('/sessions/logout-others', wrap(async (req, res) => {
75
560
  const token = req.headers.authorization?.split(' ')[1] || '';
561
+ if (!token) {
562
+ return res.status(401).json({
563
+ message: 'Authentication required'
564
+ });
565
+ }
76
566
  oxy.setTokens(token, '');
77
567
  const result = await oxy.logoutOtherSessions();
568
+
569
+ // Clear cache for this user
570
+ if (result.success) {
571
+ oxyAuth.clearCache();
572
+ }
78
573
  res.json(result);
79
574
  }));
575
+
576
+ // Enhanced logout all sessions
80
577
  router.post('/sessions/logout-all', wrap(async (req, res) => {
81
578
  const token = req.headers.authorization?.split(' ')[1] || '';
579
+ if (!token) {
580
+ return res.status(401).json({
581
+ message: 'Authentication required'
582
+ });
583
+ }
82
584
  oxy.setTokens(token, '');
83
585
  const result = await oxy.logoutAllSessions();
586
+
587
+ // Clear all cache
588
+ if (result.success) {
589
+ oxyAuth.clearCache();
590
+ }
84
591
  res.json(result);
85
592
  }));
593
+
594
+ // NEW: Get current user profile with caching
595
+ router.get('/profile', wrap(async (req, res) => {
596
+ const token = req.headers.authorization?.split(' ')[1] || '';
597
+ if (!token) {
598
+ return res.status(401).json({
599
+ message: 'Authentication required'
600
+ });
601
+ }
602
+
603
+ // Use the enhanced auth system for better performance
604
+ const validation = await oxyAuth.validateToken(token);
605
+ if (!validation.valid) {
606
+ return res.status(401).json({
607
+ message: 'Invalid token'
608
+ });
609
+ }
610
+ res.json({
611
+ user: validation.user,
612
+ cached: validation.cached,
613
+ expiresAt: validation.expiresAt
614
+ });
615
+ }));
616
+
617
+ // NEW: Check user permissions
618
+ router.post('/check-permissions', wrap(async (req, res) => {
619
+ const token = req.headers.authorization?.split(' ')[1] || '';
620
+ const {
621
+ permissions
622
+ } = req.body;
623
+ if (!token) {
624
+ return res.status(401).json({
625
+ message: 'Authentication required'
626
+ });
627
+ }
628
+ if (!permissions || !Array.isArray(permissions)) {
629
+ return res.status(400).json({
630
+ message: 'Permissions array is required'
631
+ });
632
+ }
633
+ const validation = await oxyAuth.validateToken(token);
634
+ if (!validation.valid) {
635
+ return res.status(401).json({
636
+ message: 'Invalid token'
637
+ });
638
+ }
639
+
640
+ // Check each permission
641
+ const results = await Promise.all(permissions.map(async permission => {
642
+ const hasPermission = await oxyAuth.hasPermission(validation.userId, permission);
643
+ return {
644
+ permission,
645
+ granted: hasPermission
646
+ };
647
+ }));
648
+ res.json({
649
+ permissions: results
650
+ });
651
+ }));
86
652
  return {
87
- middleware: router
653
+ middleware: router,
654
+ // NEW: Expose the enhanced auth system
655
+ auth: oxyAuth,
656
+ // NEW: Convenience methods for middleware
657
+ requireAuth: (roles, permissions) => oxyAuth.createAuthMiddleware({
658
+ required: true,
659
+ roles: Array.isArray(roles) ? roles : roles ? [roles] : undefined,
660
+ permissions: Array.isArray(permissions) ? permissions : permissions ? [permissions] : undefined
661
+ }),
662
+ optionalAuth: () => oxyAuth.optionalAuth(),
663
+ requireRole: roles => oxyAuth.requireRole(roles),
664
+ requirePermission: permissions => oxyAuth.requirePermission(permissions)
88
665
  };
89
666
  }
90
667
  //# sourceMappingURL=createAuth.js.map