@classic-homes/auth 0.1.23 → 0.1.24
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/README.md +486 -81
- package/dist/config-C-iBNu07.d.ts +86 -0
- package/dist/core/index.d.ts +72 -94
- package/dist/core/index.js +822 -430
- package/dist/index.d.ts +3 -2
- package/dist/index.js +867 -718
- package/dist/svelte/index.d.ts +12 -1
- package/dist/svelte/index.js +840 -193
- package/dist/testing/index.d.ts +1082 -0
- package/dist/testing/index.js +2033 -0
- package/dist/{types-exFUQyBX.d.ts → types-DGN45Uih.d.ts} +9 -1
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
+
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
|
|
1
11
|
// src/core/config.ts
|
|
2
|
-
var config = null;
|
|
3
12
|
function initAuth(options) {
|
|
4
13
|
config = {
|
|
5
14
|
...options,
|
|
@@ -44,10 +53,714 @@ function getFetch() {
|
|
|
44
53
|
const cfg = getConfig();
|
|
45
54
|
return cfg.fetch ?? fetch;
|
|
46
55
|
}
|
|
56
|
+
var config;
|
|
57
|
+
var init_config = __esm({
|
|
58
|
+
"src/core/config.ts"() {
|
|
59
|
+
config = null;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// src/core/jwt.ts
|
|
64
|
+
function decodeJWT(token) {
|
|
65
|
+
try {
|
|
66
|
+
const parts = token.split(".");
|
|
67
|
+
if (parts.length !== 3) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const payload = parts[1];
|
|
71
|
+
const decoded = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
|
|
72
|
+
return JSON.parse(decoded);
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function isTokenExpired(token) {
|
|
78
|
+
const payload = decodeJWT(token);
|
|
79
|
+
if (!payload || !payload.exp) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return payload.exp * 1e3 < Date.now();
|
|
83
|
+
}
|
|
84
|
+
function getTokenRemainingTime(token) {
|
|
85
|
+
const payload = decodeJWT(token);
|
|
86
|
+
if (!payload || !payload.exp) {
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
const remainingMs = payload.exp * 1e3 - Date.now();
|
|
90
|
+
return Math.max(0, remainingMs);
|
|
91
|
+
}
|
|
92
|
+
function getTokenExpiration(token) {
|
|
93
|
+
const payload = decodeJWT(token);
|
|
94
|
+
if (!payload || !payload.exp) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return new Date(payload.exp * 1e3);
|
|
98
|
+
}
|
|
99
|
+
function extractClaims(token, claims) {
|
|
100
|
+
const payload = decodeJWT(token);
|
|
101
|
+
if (!payload) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const result = {};
|
|
105
|
+
for (const claim of claims) {
|
|
106
|
+
if (claim in payload) {
|
|
107
|
+
result[claim] = payload[claim];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
var init_jwt = __esm({
|
|
113
|
+
"src/core/jwt.ts"() {
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// src/core/api.ts
|
|
118
|
+
var authApi;
|
|
119
|
+
var init_api = __esm({
|
|
120
|
+
"src/core/api.ts"() {
|
|
121
|
+
init_client();
|
|
122
|
+
init_config();
|
|
123
|
+
authApi = {
|
|
124
|
+
// ============================================================================
|
|
125
|
+
// Authentication
|
|
126
|
+
// ============================================================================
|
|
127
|
+
/**
|
|
128
|
+
* Login with username and password.
|
|
129
|
+
*/
|
|
130
|
+
async login(credentials) {
|
|
131
|
+
const response = await api.post("/auth/login", credentials);
|
|
132
|
+
return extractData(response);
|
|
133
|
+
},
|
|
134
|
+
/**
|
|
135
|
+
* Logout the current user.
|
|
136
|
+
* Returns SSO logout URL if applicable for SSO users.
|
|
137
|
+
*/
|
|
138
|
+
async logout() {
|
|
139
|
+
try {
|
|
140
|
+
const response = await api.post("/auth/logout", {}, true);
|
|
141
|
+
return extractData(response);
|
|
142
|
+
} catch {
|
|
143
|
+
return { success: true };
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
/**
|
|
147
|
+
* Register a new user.
|
|
148
|
+
*/
|
|
149
|
+
async register(data) {
|
|
150
|
+
const response = await api.post("/auth/register", data);
|
|
151
|
+
return extractData(response);
|
|
152
|
+
},
|
|
153
|
+
/**
|
|
154
|
+
* Request a password reset email.
|
|
155
|
+
*/
|
|
156
|
+
async forgotPassword(email) {
|
|
157
|
+
await api.post("/auth/forgot-password", { email });
|
|
158
|
+
},
|
|
159
|
+
/**
|
|
160
|
+
* Reset password with a token.
|
|
161
|
+
*/
|
|
162
|
+
async resetPassword(token, newPassword) {
|
|
163
|
+
await api.post("/auth/reset-password", { token, newPassword });
|
|
164
|
+
},
|
|
165
|
+
/**
|
|
166
|
+
* Refresh the access token.
|
|
167
|
+
*/
|
|
168
|
+
async refreshToken(refreshToken) {
|
|
169
|
+
const response = await api.post("/auth/refresh", { refreshToken });
|
|
170
|
+
return extractData(response);
|
|
171
|
+
},
|
|
172
|
+
/**
|
|
173
|
+
* Initiate SSO login by redirecting to the SSO provider.
|
|
174
|
+
* @param options.callbackUrl - The URL where the SSO provider should redirect after auth
|
|
175
|
+
* @param options.redirectUrl - The final URL to redirect to after processing the callback
|
|
176
|
+
*/
|
|
177
|
+
initiateSSOLogin(options) {
|
|
178
|
+
if (typeof window === "undefined") return;
|
|
179
|
+
const config2 = getConfig();
|
|
180
|
+
const authorizeUrl = config2.sso?.authorizeUrl ?? `${config2.baseUrl}/auth/sso/authorize`;
|
|
181
|
+
const params = new URLSearchParams();
|
|
182
|
+
if (options?.callbackUrl) {
|
|
183
|
+
params.set("callback", options.callbackUrl);
|
|
184
|
+
}
|
|
185
|
+
if (options?.redirectUrl) {
|
|
186
|
+
params.set("redirect", options.redirectUrl);
|
|
187
|
+
}
|
|
188
|
+
const url = params.toString() ? `${authorizeUrl}?${params}` : authorizeUrl;
|
|
189
|
+
window.location.href = url;
|
|
190
|
+
},
|
|
191
|
+
// ============================================================================
|
|
192
|
+
// Profile
|
|
193
|
+
// ============================================================================
|
|
194
|
+
/**
|
|
195
|
+
* Get the current user's profile.
|
|
196
|
+
*/
|
|
197
|
+
async getProfile(customFetch) {
|
|
198
|
+
const response = await api.get("/auth/profile", true, customFetch);
|
|
199
|
+
return response;
|
|
200
|
+
},
|
|
201
|
+
/**
|
|
202
|
+
* Update the current user's profile.
|
|
203
|
+
*/
|
|
204
|
+
async updateProfile(data) {
|
|
205
|
+
const response = await api.put("/auth/profile", data, true);
|
|
206
|
+
return extractData(response);
|
|
207
|
+
},
|
|
208
|
+
/**
|
|
209
|
+
* Change the current user's password.
|
|
210
|
+
*/
|
|
211
|
+
async changePassword(data) {
|
|
212
|
+
await api.put("/auth/change-password", data, true);
|
|
213
|
+
},
|
|
214
|
+
// ============================================================================
|
|
215
|
+
// Email Verification
|
|
216
|
+
// ============================================================================
|
|
217
|
+
/**
|
|
218
|
+
* Resend email verification.
|
|
219
|
+
*/
|
|
220
|
+
async resendVerification() {
|
|
221
|
+
await api.post("/auth/resend-verification", {}, true);
|
|
222
|
+
},
|
|
223
|
+
/**
|
|
224
|
+
* Verify email with a token.
|
|
225
|
+
*/
|
|
226
|
+
async verifyEmail(token) {
|
|
227
|
+
const response = await api.post("/auth/verify-email", {
|
|
228
|
+
token
|
|
229
|
+
});
|
|
230
|
+
return extractData(response);
|
|
231
|
+
},
|
|
232
|
+
// ============================================================================
|
|
233
|
+
// Session Management
|
|
234
|
+
// ============================================================================
|
|
235
|
+
/**
|
|
236
|
+
* Get all active sessions.
|
|
237
|
+
*/
|
|
238
|
+
async getSessions(customFetch) {
|
|
239
|
+
const response = await api.get(
|
|
240
|
+
"/auth/sessions",
|
|
241
|
+
true,
|
|
242
|
+
customFetch
|
|
243
|
+
);
|
|
244
|
+
return response;
|
|
245
|
+
},
|
|
246
|
+
/**
|
|
247
|
+
* Revoke a specific session.
|
|
248
|
+
*/
|
|
249
|
+
async revokeSession(sessionId) {
|
|
250
|
+
await api.delete(`/auth/sessions/${sessionId}`, true);
|
|
251
|
+
},
|
|
252
|
+
/**
|
|
253
|
+
* Revoke all sessions except the current one.
|
|
254
|
+
*/
|
|
255
|
+
async revokeAllSessions() {
|
|
256
|
+
await api.delete("/auth/sessions", true);
|
|
257
|
+
},
|
|
258
|
+
// ============================================================================
|
|
259
|
+
// API Key Management
|
|
260
|
+
// ============================================================================
|
|
261
|
+
/**
|
|
262
|
+
* Get all API keys.
|
|
263
|
+
*/
|
|
264
|
+
async getApiKeys(customFetch) {
|
|
265
|
+
const response = await api.get("/auth/api-keys", true, customFetch);
|
|
266
|
+
return response;
|
|
267
|
+
},
|
|
268
|
+
/**
|
|
269
|
+
* Create a new API key.
|
|
270
|
+
*/
|
|
271
|
+
async createApiKey(data) {
|
|
272
|
+
const response = await api.post("/auth/api-keys", data, true);
|
|
273
|
+
return extractData(response);
|
|
274
|
+
},
|
|
275
|
+
/**
|
|
276
|
+
* Revoke an API key.
|
|
277
|
+
*/
|
|
278
|
+
async revokeApiKey(keyId) {
|
|
279
|
+
await api.delete(`/auth/api-keys/${keyId}`, true);
|
|
280
|
+
},
|
|
281
|
+
/**
|
|
282
|
+
* Update an API key's name.
|
|
283
|
+
*/
|
|
284
|
+
async updateApiKey(keyId, data) {
|
|
285
|
+
await api.put(`/auth/api-keys/${keyId}`, data, true);
|
|
286
|
+
},
|
|
287
|
+
// ============================================================================
|
|
288
|
+
// MFA Management
|
|
289
|
+
// ============================================================================
|
|
290
|
+
/**
|
|
291
|
+
* Get MFA status for the current user.
|
|
292
|
+
*/
|
|
293
|
+
async getMFAStatus() {
|
|
294
|
+
const response = await api.get("/auth/mfa/status", true);
|
|
295
|
+
return response;
|
|
296
|
+
},
|
|
297
|
+
/**
|
|
298
|
+
* Setup MFA (get QR code and backup codes).
|
|
299
|
+
*/
|
|
300
|
+
async setupMFA() {
|
|
301
|
+
const response = await api.post("/auth/mfa-setup", {}, true);
|
|
302
|
+
return extractData(response);
|
|
303
|
+
},
|
|
304
|
+
/**
|
|
305
|
+
* Verify MFA setup with a code.
|
|
306
|
+
*/
|
|
307
|
+
async verifyMFASetup(code) {
|
|
308
|
+
await api.post("/auth/mfa/verify", { code }, true);
|
|
309
|
+
},
|
|
310
|
+
/**
|
|
311
|
+
* Disable MFA.
|
|
312
|
+
*/
|
|
313
|
+
async disableMFA(password) {
|
|
314
|
+
await api.delete("/auth/mfa", true, void 0, { password });
|
|
315
|
+
},
|
|
316
|
+
/**
|
|
317
|
+
* Regenerate MFA backup codes.
|
|
318
|
+
*/
|
|
319
|
+
async regenerateBackupCodes(password) {
|
|
320
|
+
const response = await api.post(
|
|
321
|
+
"/auth/mfa/regenerate-backup-codes",
|
|
322
|
+
{ password },
|
|
323
|
+
true
|
|
324
|
+
);
|
|
325
|
+
return extractData(response);
|
|
326
|
+
},
|
|
327
|
+
/**
|
|
328
|
+
* Verify MFA challenge during login.
|
|
329
|
+
*/
|
|
330
|
+
async verifyMFAChallenge(data) {
|
|
331
|
+
const config2 = getConfig();
|
|
332
|
+
const fetchFn = config2.fetch ?? fetch;
|
|
333
|
+
const requestBody = {
|
|
334
|
+
code: data.code,
|
|
335
|
+
type: data.method === "backup" ? "backup" : "totp",
|
|
336
|
+
trustDevice: data.trustDevice
|
|
337
|
+
};
|
|
338
|
+
const response = await fetchFn(`${config2.baseUrl}/auth/mfa/challenge`, {
|
|
339
|
+
method: "POST",
|
|
340
|
+
headers: {
|
|
341
|
+
"Content-Type": "application/json",
|
|
342
|
+
Authorization: `Bearer ${data.mfaToken}`
|
|
343
|
+
},
|
|
344
|
+
body: JSON.stringify(requestBody)
|
|
345
|
+
});
|
|
346
|
+
if (!response.ok) {
|
|
347
|
+
const error = await response.json().catch(() => ({ message: "Verification failed" }));
|
|
348
|
+
throw new Error(error.error?.message || error.message || "Invalid verification code");
|
|
349
|
+
}
|
|
350
|
+
const result = await response.json();
|
|
351
|
+
return extractData(result);
|
|
352
|
+
},
|
|
353
|
+
// ============================================================================
|
|
354
|
+
// Device Management
|
|
355
|
+
// ============================================================================
|
|
356
|
+
/**
|
|
357
|
+
* Get all devices.
|
|
358
|
+
*/
|
|
359
|
+
async getDevices(customFetch) {
|
|
360
|
+
const response = await api.get(
|
|
361
|
+
"/auth/devices",
|
|
362
|
+
true,
|
|
363
|
+
customFetch
|
|
364
|
+
);
|
|
365
|
+
return response;
|
|
366
|
+
},
|
|
367
|
+
/**
|
|
368
|
+
* Trust a device.
|
|
369
|
+
*/
|
|
370
|
+
async trustDevice(deviceId) {
|
|
371
|
+
await api.put(`/auth/devices/${deviceId}/trust`, {}, true);
|
|
372
|
+
},
|
|
373
|
+
/**
|
|
374
|
+
* Revoke device trust.
|
|
375
|
+
*/
|
|
376
|
+
async revokeDevice(deviceId) {
|
|
377
|
+
await api.delete(`/auth/devices/${deviceId}/revoke`, true);
|
|
378
|
+
},
|
|
379
|
+
/**
|
|
380
|
+
* Remove a device completely.
|
|
381
|
+
*/
|
|
382
|
+
async removeDevice(deviceId) {
|
|
383
|
+
await api.delete(`/auth/devices/${deviceId}`, true);
|
|
384
|
+
},
|
|
385
|
+
/**
|
|
386
|
+
* Approve a device with a token.
|
|
387
|
+
*/
|
|
388
|
+
async approveDevice(token) {
|
|
389
|
+
const response = await api.post("/auth/device/approve", {
|
|
390
|
+
token
|
|
391
|
+
});
|
|
392
|
+
return extractData(response);
|
|
393
|
+
},
|
|
394
|
+
/**
|
|
395
|
+
* Block a device with a token.
|
|
396
|
+
*/
|
|
397
|
+
async blockDevice(token) {
|
|
398
|
+
const response = await api.post("/auth/device/block", {
|
|
399
|
+
token
|
|
400
|
+
});
|
|
401
|
+
return extractData(response);
|
|
402
|
+
},
|
|
403
|
+
// ============================================================================
|
|
404
|
+
// Preferences
|
|
405
|
+
// ============================================================================
|
|
406
|
+
/**
|
|
407
|
+
* Get user preferences.
|
|
408
|
+
*/
|
|
409
|
+
async getPreferences(customFetch) {
|
|
410
|
+
const response = await api.get(
|
|
411
|
+
"/auth/preferences",
|
|
412
|
+
true,
|
|
413
|
+
customFetch
|
|
414
|
+
);
|
|
415
|
+
if (response && typeof response === "object" && "preferences" in response) {
|
|
416
|
+
return response.preferences;
|
|
417
|
+
}
|
|
418
|
+
return response ?? {};
|
|
419
|
+
},
|
|
420
|
+
/**
|
|
421
|
+
* Update user preferences.
|
|
422
|
+
*/
|
|
423
|
+
async updatePreferences(data) {
|
|
424
|
+
await api.put("/auth/preferences", data, true);
|
|
425
|
+
},
|
|
426
|
+
// ============================================================================
|
|
427
|
+
// SSO / Linked Accounts
|
|
428
|
+
// ============================================================================
|
|
429
|
+
/**
|
|
430
|
+
* Get SSO linked accounts.
|
|
431
|
+
*/
|
|
432
|
+
async getSSOAccounts(customFetch) {
|
|
433
|
+
const response = await api.get(
|
|
434
|
+
"/auth/sso/accounts",
|
|
435
|
+
true,
|
|
436
|
+
customFetch
|
|
437
|
+
);
|
|
438
|
+
if (response && typeof response === "object" && "accounts" in response) {
|
|
439
|
+
return response.accounts;
|
|
440
|
+
}
|
|
441
|
+
return Array.isArray(response) ? response : [];
|
|
442
|
+
},
|
|
443
|
+
/**
|
|
444
|
+
* Unlink an SSO account.
|
|
445
|
+
*/
|
|
446
|
+
async unlinkSSOAccount(provider, password) {
|
|
447
|
+
await api.delete("/auth/sso/unlink", true, void 0, { provider, password });
|
|
448
|
+
},
|
|
449
|
+
/**
|
|
450
|
+
* Link an SSO account (redirects to SSO provider).
|
|
451
|
+
*/
|
|
452
|
+
async linkSSOAccount(provider = "authentik") {
|
|
453
|
+
if (typeof window === "undefined") return;
|
|
454
|
+
const accessToken = getAccessToken();
|
|
455
|
+
if (!accessToken) {
|
|
456
|
+
throw new Error("Not authenticated");
|
|
457
|
+
}
|
|
458
|
+
const config2 = getConfig();
|
|
459
|
+
const params = new URLSearchParams({
|
|
460
|
+
token: accessToken,
|
|
461
|
+
provider
|
|
462
|
+
});
|
|
463
|
+
window.location.href = `${config2.baseUrl}/auth/sso/link?${params.toString()}`;
|
|
464
|
+
},
|
|
465
|
+
// ============================================================================
|
|
466
|
+
// Security Events
|
|
467
|
+
// ============================================================================
|
|
468
|
+
/**
|
|
469
|
+
* Get security event history.
|
|
470
|
+
*/
|
|
471
|
+
async getSecurityEvents(params, customFetch) {
|
|
472
|
+
const queryParams = new URLSearchParams();
|
|
473
|
+
if (params?.page) queryParams.append("page", params.page.toString());
|
|
474
|
+
if (params?.limit) queryParams.append("limit", params.limit.toString());
|
|
475
|
+
if (params?.type) queryParams.append("type", params.type);
|
|
476
|
+
const response = await api.get(`/auth/security/events?${queryParams.toString()}`, true, customFetch);
|
|
477
|
+
return extractData(response);
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
// src/svelte/stores/auth.svelte.ts
|
|
484
|
+
var auth_svelte_exports = {};
|
|
485
|
+
__export(auth_svelte_exports, {
|
|
486
|
+
authActions: () => authActions,
|
|
487
|
+
authStore: () => authStore,
|
|
488
|
+
currentUser: () => currentUser,
|
|
489
|
+
isAuthenticated: () => isAuthenticated
|
|
490
|
+
});
|
|
491
|
+
function getStorageKey() {
|
|
492
|
+
return isInitialized() ? getConfig().storageKey ?? "classic_auth" : "classic_auth";
|
|
493
|
+
}
|
|
494
|
+
function getStorageAdapter() {
|
|
495
|
+
return isInitialized() ? getStorage() : getDefaultStorage();
|
|
496
|
+
}
|
|
497
|
+
function loadAuthFromStorage() {
|
|
498
|
+
try {
|
|
499
|
+
const storage = getStorageAdapter();
|
|
500
|
+
const data = storage.getItem(getStorageKey());
|
|
501
|
+
if (!data) {
|
|
502
|
+
return {
|
|
503
|
+
accessToken: null,
|
|
504
|
+
refreshToken: null,
|
|
505
|
+
user: null,
|
|
506
|
+
isAuthenticated: false
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
const parsed = JSON.parse(data);
|
|
510
|
+
return {
|
|
511
|
+
accessToken: parsed.accessToken ?? null,
|
|
512
|
+
refreshToken: parsed.refreshToken ?? null,
|
|
513
|
+
user: parsed.user ?? null,
|
|
514
|
+
isAuthenticated: !!parsed.accessToken && !!parsed.user
|
|
515
|
+
};
|
|
516
|
+
} catch {
|
|
517
|
+
return {
|
|
518
|
+
accessToken: null,
|
|
519
|
+
refreshToken: null,
|
|
520
|
+
user: null,
|
|
521
|
+
isAuthenticated: false
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function saveAuthToStorage(state) {
|
|
526
|
+
try {
|
|
527
|
+
const storage = getStorageAdapter();
|
|
528
|
+
const key = getStorageKey();
|
|
529
|
+
if (!state.accessToken) {
|
|
530
|
+
storage.removeItem(key);
|
|
531
|
+
} else {
|
|
532
|
+
storage.setItem(key, JSON.stringify(state));
|
|
533
|
+
}
|
|
534
|
+
} catch {
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
var AuthStore, authStore, authActions, isAuthenticated, currentUser;
|
|
538
|
+
var init_auth_svelte = __esm({
|
|
539
|
+
"src/svelte/stores/auth.svelte.ts"() {
|
|
540
|
+
init_config();
|
|
541
|
+
init_jwt();
|
|
542
|
+
init_api();
|
|
543
|
+
AuthStore = class {
|
|
544
|
+
constructor() {
|
|
545
|
+
this.subscribers = /* @__PURE__ */ new Set();
|
|
546
|
+
this.state = loadAuthFromStorage();
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Subscribe to state changes (Svelte store contract).
|
|
550
|
+
*/
|
|
551
|
+
subscribe(subscriber) {
|
|
552
|
+
this.subscribers.add(subscriber);
|
|
553
|
+
subscriber(this.state);
|
|
554
|
+
return () => this.subscribers.delete(subscriber);
|
|
555
|
+
}
|
|
556
|
+
notify() {
|
|
557
|
+
this.subscribers.forEach((sub) => sub(this.state));
|
|
558
|
+
}
|
|
559
|
+
// Getters for direct access
|
|
560
|
+
get accessToken() {
|
|
561
|
+
return this.state.accessToken;
|
|
562
|
+
}
|
|
563
|
+
get refreshToken() {
|
|
564
|
+
return this.state.refreshToken;
|
|
565
|
+
}
|
|
566
|
+
get user() {
|
|
567
|
+
return this.state.user;
|
|
568
|
+
}
|
|
569
|
+
get isAuthenticated() {
|
|
570
|
+
return this.state.isAuthenticated;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Get the current auth state snapshot.
|
|
574
|
+
*/
|
|
575
|
+
getState() {
|
|
576
|
+
return { ...this.state };
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Set auth data after successful login.
|
|
580
|
+
*/
|
|
581
|
+
setAuth(accessToken, refreshToken, user, sessionToken) {
|
|
582
|
+
const jwtPayload = decodeJWT(accessToken);
|
|
583
|
+
const userWithPermissions = {
|
|
584
|
+
...user,
|
|
585
|
+
permissions: user.permissions || jwtPayload?.permissions || [],
|
|
586
|
+
roles: user.roles || jwtPayload?.roles || (user.role ? [user.role] : [])
|
|
587
|
+
};
|
|
588
|
+
this.state = {
|
|
589
|
+
accessToken,
|
|
590
|
+
refreshToken,
|
|
591
|
+
user: userWithPermissions,
|
|
592
|
+
isAuthenticated: true
|
|
593
|
+
};
|
|
594
|
+
saveAuthToStorage(this.state);
|
|
595
|
+
if (sessionToken && typeof window !== "undefined") {
|
|
596
|
+
getStorageAdapter().setItem("sessionToken", sessionToken);
|
|
597
|
+
}
|
|
598
|
+
if (typeof window !== "undefined") {
|
|
599
|
+
window.dispatchEvent(
|
|
600
|
+
new CustomEvent("auth:login", {
|
|
601
|
+
detail: { user: userWithPermissions }
|
|
602
|
+
})
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
this.notify();
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Update tokens (e.g., after refresh).
|
|
609
|
+
*/
|
|
610
|
+
updateTokens(accessToken, refreshToken) {
|
|
611
|
+
const jwtPayload = decodeJWT(accessToken);
|
|
612
|
+
const updatedUser = this.state.user ? {
|
|
613
|
+
...this.state.user,
|
|
614
|
+
permissions: jwtPayload?.permissions || this.state.user.permissions || [],
|
|
615
|
+
roles: jwtPayload?.roles || this.state.user.roles || (this.state.user.role ? [this.state.user.role] : [])
|
|
616
|
+
} : null;
|
|
617
|
+
this.state = {
|
|
618
|
+
...this.state,
|
|
619
|
+
accessToken,
|
|
620
|
+
refreshToken,
|
|
621
|
+
user: updatedUser
|
|
622
|
+
};
|
|
623
|
+
saveAuthToStorage(this.state);
|
|
624
|
+
if (typeof window !== "undefined") {
|
|
625
|
+
window.dispatchEvent(new CustomEvent("auth:token-refresh"));
|
|
626
|
+
}
|
|
627
|
+
this.notify();
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Update user data (e.g., after profile update).
|
|
631
|
+
*/
|
|
632
|
+
updateUser(user) {
|
|
633
|
+
const jwtPayload = this.state.accessToken ? decodeJWT(this.state.accessToken) : null;
|
|
634
|
+
const updatedUser = {
|
|
635
|
+
...user,
|
|
636
|
+
permissions: user.permissions || jwtPayload?.permissions || [],
|
|
637
|
+
roles: user.roles || jwtPayload?.roles || (user.role ? [user.role] : [])
|
|
638
|
+
};
|
|
639
|
+
this.state = {
|
|
640
|
+
...this.state,
|
|
641
|
+
user: updatedUser
|
|
642
|
+
};
|
|
643
|
+
saveAuthToStorage(this.state);
|
|
644
|
+
if (typeof window !== "undefined") {
|
|
645
|
+
window.dispatchEvent(
|
|
646
|
+
new CustomEvent("auth:profile-update", {
|
|
647
|
+
detail: { user: updatedUser }
|
|
648
|
+
})
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
this.notify();
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Clear auth state (logout).
|
|
655
|
+
*/
|
|
656
|
+
logout() {
|
|
657
|
+
this.state = {
|
|
658
|
+
accessToken: null,
|
|
659
|
+
refreshToken: null,
|
|
660
|
+
user: null,
|
|
661
|
+
isAuthenticated: false
|
|
662
|
+
};
|
|
663
|
+
const storage = getStorageAdapter();
|
|
664
|
+
storage.removeItem(getStorageKey());
|
|
665
|
+
storage.removeItem("sessionToken");
|
|
666
|
+
if (typeof window !== "undefined") {
|
|
667
|
+
window.dispatchEvent(new CustomEvent("auth:logout"));
|
|
668
|
+
}
|
|
669
|
+
if (isInitialized()) {
|
|
670
|
+
getConfig().onLogout?.();
|
|
671
|
+
}
|
|
672
|
+
this.notify();
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Logout with SSO support.
|
|
676
|
+
* Calls the logout API and returns the SSO logout URL if applicable.
|
|
677
|
+
* Clears local state regardless of API response.
|
|
678
|
+
*/
|
|
679
|
+
async logoutWithSSO() {
|
|
680
|
+
try {
|
|
681
|
+
const response = await authApi.logout();
|
|
682
|
+
this.logout();
|
|
683
|
+
if (response?.ssoLogout && response?.logoutUrl) {
|
|
684
|
+
return { ssoLogoutUrl: response.logoutUrl };
|
|
685
|
+
}
|
|
686
|
+
} catch {
|
|
687
|
+
this.logout();
|
|
688
|
+
}
|
|
689
|
+
return {};
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Check if user has a specific permission.
|
|
693
|
+
*/
|
|
694
|
+
hasPermission(permission) {
|
|
695
|
+
return this.state.user?.permissions?.includes(permission) ?? false;
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Check if user has a specific role.
|
|
699
|
+
*/
|
|
700
|
+
hasRole(role) {
|
|
701
|
+
return this.state.user?.roles?.includes(role) ?? false;
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Check if user has any of the specified roles.
|
|
705
|
+
*/
|
|
706
|
+
hasAnyRole(roles) {
|
|
707
|
+
return roles.some((role) => this.state.user?.roles?.includes(role)) ?? false;
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* Check if user has all of the specified roles.
|
|
711
|
+
*/
|
|
712
|
+
hasAllRoles(roles) {
|
|
713
|
+
return roles.every((role) => this.state.user?.roles?.includes(role)) ?? false;
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Check if user has any of the specified permissions.
|
|
717
|
+
*/
|
|
718
|
+
hasAnyPermission(permissions) {
|
|
719
|
+
return permissions.some((perm) => this.state.user?.permissions?.includes(perm)) ?? false;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Check if user has all of the specified permissions.
|
|
723
|
+
*/
|
|
724
|
+
hasAllPermissions(permissions) {
|
|
725
|
+
return permissions.every((perm) => this.state.user?.permissions?.includes(perm)) ?? false;
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Re-hydrate state from storage (useful after config changes).
|
|
729
|
+
*/
|
|
730
|
+
rehydrate() {
|
|
731
|
+
this.state = loadAuthFromStorage();
|
|
732
|
+
this.notify();
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
authStore = new AuthStore();
|
|
736
|
+
authActions = {
|
|
737
|
+
setAuth: (accessToken, refreshToken, user, sessionToken) => authStore.setAuth(accessToken, refreshToken, user, sessionToken),
|
|
738
|
+
updateTokens: (accessToken, refreshToken) => authStore.updateTokens(accessToken, refreshToken),
|
|
739
|
+
updateUser: (user) => authStore.updateUser(user),
|
|
740
|
+
logout: () => authStore.logout(),
|
|
741
|
+
logoutWithSSO: () => authStore.logoutWithSSO(),
|
|
742
|
+
hasPermission: (permission) => authStore.hasPermission(permission),
|
|
743
|
+
hasRole: (role) => authStore.hasRole(role),
|
|
744
|
+
hasAnyRole: (roles) => authStore.hasAnyRole(roles),
|
|
745
|
+
hasAllRoles: (roles) => authStore.hasAllRoles(roles),
|
|
746
|
+
hasAnyPermission: (permissions) => authStore.hasAnyPermission(permissions),
|
|
747
|
+
hasAllPermissions: (permissions) => authStore.hasAllPermissions(permissions),
|
|
748
|
+
rehydrate: () => authStore.rehydrate()
|
|
749
|
+
};
|
|
750
|
+
isAuthenticated = {
|
|
751
|
+
subscribe: (subscriber) => {
|
|
752
|
+
return authStore.subscribe((state) => subscriber(state.isAuthenticated));
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
currentUser = {
|
|
756
|
+
subscribe: (subscriber) => {
|
|
757
|
+
return authStore.subscribe((state) => subscriber(state.user));
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
});
|
|
47
762
|
|
|
48
763
|
// src/core/client.ts
|
|
49
|
-
var isRefreshing = false;
|
|
50
|
-
var refreshSubscribers = [];
|
|
51
764
|
function subscribeTokenRefresh(cb) {
|
|
52
765
|
refreshSubscribers.push(cb);
|
|
53
766
|
}
|
|
@@ -98,6 +811,10 @@ function updateStoredTokens(accessToken, refreshToken) {
|
|
|
98
811
|
parsed.accessToken = accessToken;
|
|
99
812
|
parsed.refreshToken = refreshToken;
|
|
100
813
|
storage.setItem(storageKey, JSON.stringify(parsed));
|
|
814
|
+
Promise.resolve().then(() => (init_auth_svelte(), auth_svelte_exports)).then(({ authStore: authStore2 }) => {
|
|
815
|
+
authStore2.updateTokens(accessToken, refreshToken);
|
|
816
|
+
}).catch(() => {
|
|
817
|
+
});
|
|
101
818
|
config2.onTokenRefresh?.({ accessToken, refreshToken });
|
|
102
819
|
}
|
|
103
820
|
function clearStoredAuth() {
|
|
@@ -209,87 +926,136 @@ async function apiRequest(endpoint, options = {}) {
|
|
|
209
926
|
throw new Error("API request failed");
|
|
210
927
|
}
|
|
211
928
|
}
|
|
212
|
-
var
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
929
|
+
var isRefreshing, refreshSubscribers, api;
|
|
930
|
+
var init_client = __esm({
|
|
931
|
+
"src/core/client.ts"() {
|
|
932
|
+
init_config();
|
|
933
|
+
isRefreshing = false;
|
|
934
|
+
refreshSubscribers = [];
|
|
935
|
+
api = {
|
|
936
|
+
get: (endpoint, authenticated = false, customFetch) => apiRequest(endpoint, { method: "GET", authenticated, customFetch }),
|
|
937
|
+
post: (endpoint, body, authenticated = false, customFetch) => apiRequest(endpoint, {
|
|
938
|
+
method: "POST",
|
|
939
|
+
body,
|
|
940
|
+
authenticated,
|
|
941
|
+
customFetch
|
|
942
|
+
}),
|
|
943
|
+
put: (endpoint, body, authenticated = false, customFetch) => apiRequest(endpoint, {
|
|
944
|
+
method: "PUT",
|
|
945
|
+
body,
|
|
946
|
+
authenticated,
|
|
947
|
+
customFetch
|
|
948
|
+
}),
|
|
949
|
+
patch: (endpoint, body, authenticated = false, customFetch) => apiRequest(endpoint, {
|
|
950
|
+
method: "PATCH",
|
|
951
|
+
body,
|
|
952
|
+
authenticated,
|
|
953
|
+
customFetch
|
|
954
|
+
}),
|
|
955
|
+
delete: (endpoint, authenticated = false, customFetch, body) => apiRequest(endpoint, {
|
|
956
|
+
method: "DELETE",
|
|
957
|
+
body,
|
|
958
|
+
authenticated,
|
|
959
|
+
customFetch
|
|
960
|
+
})
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
});
|
|
239
964
|
|
|
240
|
-
// src/core/
|
|
241
|
-
|
|
965
|
+
// src/core/index.ts
|
|
966
|
+
init_config();
|
|
967
|
+
init_client();
|
|
968
|
+
init_api();
|
|
969
|
+
|
|
970
|
+
// src/core/service.ts
|
|
971
|
+
init_api();
|
|
972
|
+
|
|
973
|
+
// src/core/guards.ts
|
|
974
|
+
function isMfaChallengeResponse(response) {
|
|
975
|
+
return "requiresMFA" in response && response.requiresMFA === true || "mfaRequired" in response && response.mfaRequired === true;
|
|
976
|
+
}
|
|
977
|
+
function isLoginSuccessResponse(response) {
|
|
978
|
+
return "accessToken" in response && "user" in response && !isMfaChallengeResponse(response);
|
|
979
|
+
}
|
|
980
|
+
function getMfaToken(response) {
|
|
981
|
+
return response.mfaToken ?? response.mfaChallengeToken;
|
|
982
|
+
}
|
|
983
|
+
function getAvailableMethods(response) {
|
|
984
|
+
return response.availableMethods ?? ["totp"];
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// src/core/service.ts
|
|
988
|
+
var AuthService = class {
|
|
242
989
|
// ============================================================================
|
|
243
990
|
// Authentication
|
|
244
991
|
// ============================================================================
|
|
245
992
|
/**
|
|
246
993
|
* Login with username and password.
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
994
|
+
* By default, automatically sets the auth state on successful login (unless MFA is required).
|
|
995
|
+
* @param credentials - Username and password
|
|
996
|
+
* @param options - Optional settings for login behavior
|
|
997
|
+
*/
|
|
998
|
+
async login(credentials, options) {
|
|
999
|
+
const response = await authApi.login(credentials);
|
|
1000
|
+
if (options?.autoSetAuth !== false && !isMfaChallengeResponse(response)) {
|
|
1001
|
+
try {
|
|
1002
|
+
const { authStore: authStore2 } = await Promise.resolve().then(() => (init_auth_svelte(), auth_svelte_exports));
|
|
1003
|
+
authStore2.setAuth(
|
|
1004
|
+
response.accessToken,
|
|
1005
|
+
response.refreshToken,
|
|
1006
|
+
response.user,
|
|
1007
|
+
response.sessionToken
|
|
1008
|
+
);
|
|
1009
|
+
} catch {
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
return response;
|
|
1013
|
+
}
|
|
252
1014
|
/**
|
|
253
1015
|
* Logout the current user.
|
|
1016
|
+
* Returns SSO logout URL if applicable for SSO users.
|
|
254
1017
|
*/
|
|
255
1018
|
async logout() {
|
|
256
|
-
await
|
|
257
|
-
}
|
|
1019
|
+
return await authApi.logout();
|
|
1020
|
+
}
|
|
258
1021
|
/**
|
|
259
1022
|
* Register a new user.
|
|
260
1023
|
*/
|
|
261
1024
|
async register(data) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
},
|
|
1025
|
+
return await authApi.register(data);
|
|
1026
|
+
}
|
|
265
1027
|
/**
|
|
266
1028
|
* Request a password reset email.
|
|
267
1029
|
*/
|
|
268
1030
|
async forgotPassword(email) {
|
|
269
|
-
await
|
|
270
|
-
}
|
|
1031
|
+
await authApi.forgotPassword(email);
|
|
1032
|
+
}
|
|
271
1033
|
/**
|
|
272
1034
|
* Reset password with a token.
|
|
273
1035
|
*/
|
|
274
1036
|
async resetPassword(token, newPassword) {
|
|
275
|
-
await
|
|
276
|
-
}
|
|
1037
|
+
await authApi.resetPassword(token, newPassword);
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Change the current user's password.
|
|
1041
|
+
*/
|
|
1042
|
+
async changePassword(currentPassword, newPassword) {
|
|
1043
|
+
await authApi.changePassword({ currentPassword, newPassword });
|
|
1044
|
+
}
|
|
277
1045
|
/**
|
|
278
1046
|
* Refresh the access token.
|
|
279
1047
|
*/
|
|
280
1048
|
async refreshToken(refreshToken) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
},
|
|
1049
|
+
return await authApi.refreshToken(refreshToken);
|
|
1050
|
+
}
|
|
284
1051
|
/**
|
|
285
|
-
* Initiate SSO login
|
|
1052
|
+
* Initiate SSO login (redirects to SSO provider).
|
|
1053
|
+
* @param options.callbackUrl - The URL where the SSO provider should redirect after auth
|
|
1054
|
+
* @param options.redirectUrl - The final URL to redirect to after processing the callback
|
|
286
1055
|
*/
|
|
287
|
-
initiateSSOLogin() {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const authorizeUrl = config2.sso?.authorizeUrl ?? `${config2.baseUrl}/auth/sso/authorize`;
|
|
291
|
-
window.location.href = authorizeUrl;
|
|
292
|
-
},
|
|
1056
|
+
initiateSSOLogin(options) {
|
|
1057
|
+
authApi.initiateSSOLogin(options);
|
|
1058
|
+
}
|
|
293
1059
|
// ============================================================================
|
|
294
1060
|
// Profile
|
|
295
1061
|
// ============================================================================
|
|
@@ -297,40 +1063,26 @@ var authApi = {
|
|
|
297
1063
|
* Get the current user's profile.
|
|
298
1064
|
*/
|
|
299
1065
|
async getProfile(customFetch) {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
},
|
|
1066
|
+
return await authApi.getProfile(customFetch);
|
|
1067
|
+
}
|
|
303
1068
|
/**
|
|
304
1069
|
* Update the current user's profile.
|
|
305
1070
|
*/
|
|
306
1071
|
async updateProfile(data) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
},
|
|
310
|
-
/**
|
|
311
|
-
* Change the current user's password.
|
|
312
|
-
*/
|
|
313
|
-
async changePassword(data) {
|
|
314
|
-
await api.put("/auth/change-password", data, true);
|
|
315
|
-
},
|
|
316
|
-
// ============================================================================
|
|
317
|
-
// Email Verification
|
|
318
|
-
// ============================================================================
|
|
1072
|
+
return await authApi.updateProfile(data);
|
|
1073
|
+
}
|
|
319
1074
|
/**
|
|
320
1075
|
* Resend email verification.
|
|
321
1076
|
*/
|
|
322
1077
|
async resendVerification() {
|
|
323
|
-
await
|
|
324
|
-
}
|
|
1078
|
+
await authApi.resendVerification();
|
|
1079
|
+
}
|
|
325
1080
|
/**
|
|
326
1081
|
* Verify email with a token.
|
|
327
1082
|
*/
|
|
328
1083
|
async verifyEmail(token) {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
});
|
|
332
|
-
return extractData(response);
|
|
333
|
-
},
|
|
1084
|
+
return await authApi.verifyEmail(token);
|
|
1085
|
+
}
|
|
334
1086
|
// ============================================================================
|
|
335
1087
|
// Session Management
|
|
336
1088
|
// ============================================================================
|
|
@@ -338,25 +1090,20 @@ var authApi = {
|
|
|
338
1090
|
* Get all active sessions.
|
|
339
1091
|
*/
|
|
340
1092
|
async getSessions(customFetch) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
true,
|
|
344
|
-
customFetch
|
|
345
|
-
);
|
|
346
|
-
return response;
|
|
347
|
-
},
|
|
1093
|
+
return await authApi.getSessions(customFetch);
|
|
1094
|
+
}
|
|
348
1095
|
/**
|
|
349
1096
|
* Revoke a specific session.
|
|
350
1097
|
*/
|
|
351
1098
|
async revokeSession(sessionId) {
|
|
352
|
-
await
|
|
353
|
-
}
|
|
1099
|
+
await authApi.revokeSession(sessionId);
|
|
1100
|
+
}
|
|
354
1101
|
/**
|
|
355
1102
|
* Revoke all sessions except the current one.
|
|
356
1103
|
*/
|
|
357
1104
|
async revokeAllSessions() {
|
|
358
|
-
await
|
|
359
|
-
}
|
|
1105
|
+
await authApi.revokeAllSessions();
|
|
1106
|
+
}
|
|
360
1107
|
// ============================================================================
|
|
361
1108
|
// API Key Management
|
|
362
1109
|
// ============================================================================
|
|
@@ -364,344 +1111,20 @@ var authApi = {
|
|
|
364
1111
|
* Get all API keys.
|
|
365
1112
|
*/
|
|
366
1113
|
async getApiKeys(customFetch) {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
},
|
|
1114
|
+
return await authApi.getApiKeys(customFetch);
|
|
1115
|
+
}
|
|
370
1116
|
/**
|
|
371
1117
|
* Create a new API key.
|
|
372
1118
|
*/
|
|
373
1119
|
async createApiKey(data) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
},
|
|
1120
|
+
return await authApi.createApiKey(data);
|
|
1121
|
+
}
|
|
377
1122
|
/**
|
|
378
1123
|
* Revoke an API key.
|
|
379
1124
|
*/
|
|
380
1125
|
async revokeApiKey(keyId) {
|
|
381
|
-
await
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Update an API key's name.
|
|
385
|
-
*/
|
|
386
|
-
async updateApiKey(keyId, data) {
|
|
387
|
-
await api.put(`/auth/api-keys/${keyId}`, data, true);
|
|
388
|
-
},
|
|
389
|
-
// ============================================================================
|
|
390
|
-
// MFA Management
|
|
391
|
-
// ============================================================================
|
|
392
|
-
/**
|
|
393
|
-
* Get MFA status for the current user.
|
|
394
|
-
*/
|
|
395
|
-
async getMFAStatus() {
|
|
396
|
-
const response = await api.get("/auth/mfa/status", true);
|
|
397
|
-
return response;
|
|
398
|
-
},
|
|
399
|
-
/**
|
|
400
|
-
* Setup MFA (get QR code and backup codes).
|
|
401
|
-
*/
|
|
402
|
-
async setupMFA() {
|
|
403
|
-
const response = await api.post("/auth/mfa-setup", {}, true);
|
|
404
|
-
return extractData(response);
|
|
405
|
-
},
|
|
406
|
-
/**
|
|
407
|
-
* Verify MFA setup with a code.
|
|
408
|
-
*/
|
|
409
|
-
async verifyMFASetup(code) {
|
|
410
|
-
await api.post("/auth/mfa/verify", { code }, true);
|
|
411
|
-
},
|
|
412
|
-
/**
|
|
413
|
-
* Disable MFA.
|
|
414
|
-
*/
|
|
415
|
-
async disableMFA(password) {
|
|
416
|
-
await api.delete("/auth/mfa", true, void 0, { password });
|
|
417
|
-
},
|
|
418
|
-
/**
|
|
419
|
-
* Regenerate MFA backup codes.
|
|
420
|
-
*/
|
|
421
|
-
async regenerateBackupCodes(password) {
|
|
422
|
-
const response = await api.post(
|
|
423
|
-
"/auth/mfa/regenerate-backup-codes",
|
|
424
|
-
{ password },
|
|
425
|
-
true
|
|
426
|
-
);
|
|
427
|
-
return extractData(response);
|
|
428
|
-
},
|
|
429
|
-
/**
|
|
430
|
-
* Verify MFA challenge during login.
|
|
431
|
-
*/
|
|
432
|
-
async verifyMFAChallenge(data) {
|
|
433
|
-
const config2 = getConfig();
|
|
434
|
-
const fetchFn = config2.fetch ?? fetch;
|
|
435
|
-
const requestBody = {
|
|
436
|
-
code: data.code,
|
|
437
|
-
type: data.method === "backup" ? "backup" : "totp",
|
|
438
|
-
trustDevice: data.trustDevice
|
|
439
|
-
};
|
|
440
|
-
const response = await fetchFn(`${config2.baseUrl}/auth/mfa/challenge`, {
|
|
441
|
-
method: "POST",
|
|
442
|
-
headers: {
|
|
443
|
-
"Content-Type": "application/json",
|
|
444
|
-
Authorization: `Bearer ${data.mfaToken}`
|
|
445
|
-
},
|
|
446
|
-
body: JSON.stringify(requestBody)
|
|
447
|
-
});
|
|
448
|
-
if (!response.ok) {
|
|
449
|
-
const error = await response.json().catch(() => ({ message: "Verification failed" }));
|
|
450
|
-
throw new Error(error.error?.message || error.message || "Invalid verification code");
|
|
451
|
-
}
|
|
452
|
-
const result = await response.json();
|
|
453
|
-
return extractData(result);
|
|
454
|
-
},
|
|
455
|
-
// ============================================================================
|
|
456
|
-
// Device Management
|
|
457
|
-
// ============================================================================
|
|
458
|
-
/**
|
|
459
|
-
* Get all devices.
|
|
460
|
-
*/
|
|
461
|
-
async getDevices(customFetch) {
|
|
462
|
-
const response = await api.get(
|
|
463
|
-
"/auth/devices",
|
|
464
|
-
true,
|
|
465
|
-
customFetch
|
|
466
|
-
);
|
|
467
|
-
return response;
|
|
468
|
-
},
|
|
469
|
-
/**
|
|
470
|
-
* Trust a device.
|
|
471
|
-
*/
|
|
472
|
-
async trustDevice(deviceId) {
|
|
473
|
-
await api.put(`/auth/devices/${deviceId}/trust`, {}, true);
|
|
474
|
-
},
|
|
475
|
-
/**
|
|
476
|
-
* Revoke device trust.
|
|
477
|
-
*/
|
|
478
|
-
async revokeDevice(deviceId) {
|
|
479
|
-
await api.delete(`/auth/devices/${deviceId}/revoke`, true);
|
|
480
|
-
},
|
|
481
|
-
/**
|
|
482
|
-
* Remove a device completely.
|
|
483
|
-
*/
|
|
484
|
-
async removeDevice(deviceId) {
|
|
485
|
-
await api.delete(`/auth/devices/${deviceId}`, true);
|
|
486
|
-
},
|
|
487
|
-
/**
|
|
488
|
-
* Approve a device with a token.
|
|
489
|
-
*/
|
|
490
|
-
async approveDevice(token) {
|
|
491
|
-
const response = await api.post("/auth/device/approve", {
|
|
492
|
-
token
|
|
493
|
-
});
|
|
494
|
-
return extractData(response);
|
|
495
|
-
},
|
|
496
|
-
/**
|
|
497
|
-
* Block a device with a token.
|
|
498
|
-
*/
|
|
499
|
-
async blockDevice(token) {
|
|
500
|
-
const response = await api.post("/auth/device/block", {
|
|
501
|
-
token
|
|
502
|
-
});
|
|
503
|
-
return extractData(response);
|
|
504
|
-
},
|
|
505
|
-
// ============================================================================
|
|
506
|
-
// Preferences
|
|
507
|
-
// ============================================================================
|
|
508
|
-
/**
|
|
509
|
-
* Get user preferences.
|
|
510
|
-
*/
|
|
511
|
-
async getPreferences(customFetch) {
|
|
512
|
-
const response = await api.get(
|
|
513
|
-
"/auth/preferences",
|
|
514
|
-
true,
|
|
515
|
-
customFetch
|
|
516
|
-
);
|
|
517
|
-
if (response && typeof response === "object" && "preferences" in response) {
|
|
518
|
-
return response.preferences;
|
|
519
|
-
}
|
|
520
|
-
return response ?? {};
|
|
521
|
-
},
|
|
522
|
-
/**
|
|
523
|
-
* Update user preferences.
|
|
524
|
-
*/
|
|
525
|
-
async updatePreferences(data) {
|
|
526
|
-
await api.put("/auth/preferences", data, true);
|
|
527
|
-
},
|
|
528
|
-
// ============================================================================
|
|
529
|
-
// SSO / Linked Accounts
|
|
530
|
-
// ============================================================================
|
|
531
|
-
/**
|
|
532
|
-
* Get SSO linked accounts.
|
|
533
|
-
*/
|
|
534
|
-
async getSSOAccounts(customFetch) {
|
|
535
|
-
const response = await api.get(
|
|
536
|
-
"/auth/sso/accounts",
|
|
537
|
-
true,
|
|
538
|
-
customFetch
|
|
539
|
-
);
|
|
540
|
-
if (response && typeof response === "object" && "accounts" in response) {
|
|
541
|
-
return response.accounts;
|
|
542
|
-
}
|
|
543
|
-
return Array.isArray(response) ? response : [];
|
|
544
|
-
},
|
|
545
|
-
/**
|
|
546
|
-
* Unlink an SSO account.
|
|
547
|
-
*/
|
|
548
|
-
async unlinkSSOAccount(provider, password) {
|
|
549
|
-
await api.delete("/auth/sso/unlink", true, void 0, { provider, password });
|
|
550
|
-
},
|
|
551
|
-
/**
|
|
552
|
-
* Link an SSO account (redirects to SSO provider).
|
|
553
|
-
*/
|
|
554
|
-
async linkSSOAccount(provider = "authentik") {
|
|
555
|
-
if (typeof window === "undefined") return;
|
|
556
|
-
const accessToken = getAccessToken();
|
|
557
|
-
if (!accessToken) {
|
|
558
|
-
throw new Error("Not authenticated");
|
|
559
|
-
}
|
|
560
|
-
const config2 = getConfig();
|
|
561
|
-
const params = new URLSearchParams({
|
|
562
|
-
token: accessToken,
|
|
563
|
-
provider
|
|
564
|
-
});
|
|
565
|
-
window.location.href = `${config2.baseUrl}/auth/sso/link?${params.toString()}`;
|
|
566
|
-
},
|
|
567
|
-
// ============================================================================
|
|
568
|
-
// Security Events
|
|
569
|
-
// ============================================================================
|
|
570
|
-
/**
|
|
571
|
-
* Get security event history.
|
|
572
|
-
*/
|
|
573
|
-
async getSecurityEvents(params, customFetch) {
|
|
574
|
-
const queryParams = new URLSearchParams();
|
|
575
|
-
if (params?.page) queryParams.append("page", params.page.toString());
|
|
576
|
-
if (params?.limit) queryParams.append("limit", params.limit.toString());
|
|
577
|
-
if (params?.type) queryParams.append("type", params.type);
|
|
578
|
-
const response = await api.get(`/auth/security/events?${queryParams.toString()}`, true, customFetch);
|
|
579
|
-
return extractData(response);
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
|
-
|
|
583
|
-
// src/core/service.ts
|
|
584
|
-
var AuthService = class {
|
|
585
|
-
// ============================================================================
|
|
586
|
-
// Authentication
|
|
587
|
-
// ============================================================================
|
|
588
|
-
/**
|
|
589
|
-
* Login with username and password.
|
|
590
|
-
*/
|
|
591
|
-
async login(credentials) {
|
|
592
|
-
return await authApi.login(credentials);
|
|
593
|
-
}
|
|
594
|
-
/**
|
|
595
|
-
* Logout the current user.
|
|
596
|
-
*/
|
|
597
|
-
async logout() {
|
|
598
|
-
await authApi.logout();
|
|
599
|
-
}
|
|
600
|
-
/**
|
|
601
|
-
* Register a new user.
|
|
602
|
-
*/
|
|
603
|
-
async register(data) {
|
|
604
|
-
return await authApi.register(data);
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* Request a password reset email.
|
|
608
|
-
*/
|
|
609
|
-
async forgotPassword(email) {
|
|
610
|
-
await authApi.forgotPassword(email);
|
|
611
|
-
}
|
|
612
|
-
/**
|
|
613
|
-
* Reset password with a token.
|
|
614
|
-
*/
|
|
615
|
-
async resetPassword(token, newPassword) {
|
|
616
|
-
await authApi.resetPassword(token, newPassword);
|
|
617
|
-
}
|
|
618
|
-
/**
|
|
619
|
-
* Change the current user's password.
|
|
620
|
-
*/
|
|
621
|
-
async changePassword(currentPassword, newPassword) {
|
|
622
|
-
await authApi.changePassword({ currentPassword, newPassword });
|
|
623
|
-
}
|
|
624
|
-
/**
|
|
625
|
-
* Refresh the access token.
|
|
626
|
-
*/
|
|
627
|
-
async refreshToken(refreshToken) {
|
|
628
|
-
return await authApi.refreshToken(refreshToken);
|
|
629
|
-
}
|
|
630
|
-
/**
|
|
631
|
-
* Initiate SSO login (redirects to SSO provider).
|
|
632
|
-
*/
|
|
633
|
-
initiateSSOLogin() {
|
|
634
|
-
authApi.initiateSSOLogin();
|
|
635
|
-
}
|
|
636
|
-
// ============================================================================
|
|
637
|
-
// Profile
|
|
638
|
-
// ============================================================================
|
|
639
|
-
/**
|
|
640
|
-
* Get the current user's profile.
|
|
641
|
-
*/
|
|
642
|
-
async getProfile(customFetch) {
|
|
643
|
-
return await authApi.getProfile(customFetch);
|
|
644
|
-
}
|
|
645
|
-
/**
|
|
646
|
-
* Update the current user's profile.
|
|
647
|
-
*/
|
|
648
|
-
async updateProfile(data) {
|
|
649
|
-
return await authApi.updateProfile(data);
|
|
650
|
-
}
|
|
651
|
-
/**
|
|
652
|
-
* Resend email verification.
|
|
653
|
-
*/
|
|
654
|
-
async resendVerification() {
|
|
655
|
-
await authApi.resendVerification();
|
|
656
|
-
}
|
|
657
|
-
/**
|
|
658
|
-
* Verify email with a token.
|
|
659
|
-
*/
|
|
660
|
-
async verifyEmail(token) {
|
|
661
|
-
return await authApi.verifyEmail(token);
|
|
662
|
-
}
|
|
663
|
-
// ============================================================================
|
|
664
|
-
// Session Management
|
|
665
|
-
// ============================================================================
|
|
666
|
-
/**
|
|
667
|
-
* Get all active sessions.
|
|
668
|
-
*/
|
|
669
|
-
async getSessions(customFetch) {
|
|
670
|
-
return await authApi.getSessions(customFetch);
|
|
671
|
-
}
|
|
672
|
-
/**
|
|
673
|
-
* Revoke a specific session.
|
|
674
|
-
*/
|
|
675
|
-
async revokeSession(sessionId) {
|
|
676
|
-
await authApi.revokeSession(sessionId);
|
|
677
|
-
}
|
|
678
|
-
/**
|
|
679
|
-
* Revoke all sessions except the current one.
|
|
680
|
-
*/
|
|
681
|
-
async revokeAllSessions() {
|
|
682
|
-
await authApi.revokeAllSessions();
|
|
683
|
-
}
|
|
684
|
-
// ============================================================================
|
|
685
|
-
// API Key Management
|
|
686
|
-
// ============================================================================
|
|
687
|
-
/**
|
|
688
|
-
* Get all API keys.
|
|
689
|
-
*/
|
|
690
|
-
async getApiKeys(customFetch) {
|
|
691
|
-
return await authApi.getApiKeys(customFetch);
|
|
692
|
-
}
|
|
693
|
-
/**
|
|
694
|
-
* Create a new API key.
|
|
695
|
-
*/
|
|
696
|
-
async createApiKey(data) {
|
|
697
|
-
return await authApi.createApiKey(data);
|
|
698
|
-
}
|
|
699
|
-
/**
|
|
700
|
-
* Revoke an API key.
|
|
701
|
-
*/
|
|
702
|
-
async revokeApiKey(keyId) {
|
|
703
|
-
await authApi.revokeApiKey(keyId);
|
|
704
|
-
}
|
|
1126
|
+
await authApi.revokeApiKey(keyId);
|
|
1127
|
+
}
|
|
705
1128
|
/**
|
|
706
1129
|
* Update an API key's name.
|
|
707
1130
|
*/
|
|
@@ -743,9 +1166,25 @@ var AuthService = class {
|
|
|
743
1166
|
}
|
|
744
1167
|
/**
|
|
745
1168
|
* Verify MFA challenge during login.
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
1169
|
+
* By default, automatically sets the auth state on successful verification.
|
|
1170
|
+
* @param data - MFA challenge data including token and code
|
|
1171
|
+
* @param options - Optional settings for verification behavior
|
|
1172
|
+
*/
|
|
1173
|
+
async verifyMFAChallenge(data, options) {
|
|
1174
|
+
const response = await authApi.verifyMFAChallenge(data);
|
|
1175
|
+
if (options?.autoSetAuth !== false) {
|
|
1176
|
+
try {
|
|
1177
|
+
const { authStore: authStore2 } = await Promise.resolve().then(() => (init_auth_svelte(), auth_svelte_exports));
|
|
1178
|
+
authStore2.setAuth(
|
|
1179
|
+
response.accessToken,
|
|
1180
|
+
response.refreshToken,
|
|
1181
|
+
response.user,
|
|
1182
|
+
response.sessionToken
|
|
1183
|
+
);
|
|
1184
|
+
} catch {
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
return response;
|
|
749
1188
|
}
|
|
750
1189
|
// ============================================================================
|
|
751
1190
|
// Device Management
|
|
@@ -834,304 +1273,14 @@ var AuthService = class {
|
|
|
834
1273
|
};
|
|
835
1274
|
var authService = new AuthService();
|
|
836
1275
|
|
|
837
|
-
// src/core/
|
|
838
|
-
|
|
839
|
-
try {
|
|
840
|
-
const parts = token.split(".");
|
|
841
|
-
if (parts.length !== 3) {
|
|
842
|
-
return null;
|
|
843
|
-
}
|
|
844
|
-
const payload = parts[1];
|
|
845
|
-
const decoded = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
|
|
846
|
-
return JSON.parse(decoded);
|
|
847
|
-
} catch {
|
|
848
|
-
return null;
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
function isTokenExpired(token) {
|
|
852
|
-
const payload = decodeJWT(token);
|
|
853
|
-
if (!payload || !payload.exp) {
|
|
854
|
-
return true;
|
|
855
|
-
}
|
|
856
|
-
return payload.exp * 1e3 < Date.now();
|
|
857
|
-
}
|
|
858
|
-
function getTokenRemainingTime(token) {
|
|
859
|
-
const payload = decodeJWT(token);
|
|
860
|
-
if (!payload || !payload.exp) {
|
|
861
|
-
return 0;
|
|
862
|
-
}
|
|
863
|
-
const remainingMs = payload.exp * 1e3 - Date.now();
|
|
864
|
-
return Math.max(0, remainingMs);
|
|
865
|
-
}
|
|
866
|
-
function getTokenExpiration(token) {
|
|
867
|
-
const payload = decodeJWT(token);
|
|
868
|
-
if (!payload || !payload.exp) {
|
|
869
|
-
return null;
|
|
870
|
-
}
|
|
871
|
-
return new Date(payload.exp * 1e3);
|
|
872
|
-
}
|
|
873
|
-
function extractClaims(token, claims) {
|
|
874
|
-
const payload = decodeJWT(token);
|
|
875
|
-
if (!payload) {
|
|
876
|
-
return null;
|
|
877
|
-
}
|
|
878
|
-
const result = {};
|
|
879
|
-
for (const claim of claims) {
|
|
880
|
-
if (claim in payload) {
|
|
881
|
-
result[claim] = payload[claim];
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
return result;
|
|
885
|
-
}
|
|
1276
|
+
// src/core/index.ts
|
|
1277
|
+
init_jwt();
|
|
886
1278
|
|
|
887
|
-
// src/svelte/
|
|
888
|
-
|
|
889
|
-
return isInitialized() ? getConfig().storageKey ?? "classic_auth" : "classic_auth";
|
|
890
|
-
}
|
|
891
|
-
function getStorageAdapter() {
|
|
892
|
-
return isInitialized() ? getStorage() : getDefaultStorage();
|
|
893
|
-
}
|
|
894
|
-
function loadAuthFromStorage() {
|
|
895
|
-
try {
|
|
896
|
-
const storage = getStorageAdapter();
|
|
897
|
-
const data = storage.getItem(getStorageKey());
|
|
898
|
-
if (!data) {
|
|
899
|
-
return {
|
|
900
|
-
accessToken: null,
|
|
901
|
-
refreshToken: null,
|
|
902
|
-
user: null,
|
|
903
|
-
isAuthenticated: false
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
const parsed = JSON.parse(data);
|
|
907
|
-
return {
|
|
908
|
-
accessToken: parsed.accessToken ?? null,
|
|
909
|
-
refreshToken: parsed.refreshToken ?? null,
|
|
910
|
-
user: parsed.user ?? null,
|
|
911
|
-
isAuthenticated: !!parsed.accessToken && !!parsed.user
|
|
912
|
-
};
|
|
913
|
-
} catch {
|
|
914
|
-
return {
|
|
915
|
-
accessToken: null,
|
|
916
|
-
refreshToken: null,
|
|
917
|
-
user: null,
|
|
918
|
-
isAuthenticated: false
|
|
919
|
-
};
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
function saveAuthToStorage(state) {
|
|
923
|
-
try {
|
|
924
|
-
const storage = getStorageAdapter();
|
|
925
|
-
const key = getStorageKey();
|
|
926
|
-
if (!state.accessToken) {
|
|
927
|
-
storage.removeItem(key);
|
|
928
|
-
} else {
|
|
929
|
-
storage.setItem(key, JSON.stringify(state));
|
|
930
|
-
}
|
|
931
|
-
} catch {
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
var AuthStore = class {
|
|
935
|
-
constructor() {
|
|
936
|
-
this.subscribers = /* @__PURE__ */ new Set();
|
|
937
|
-
this.state = loadAuthFromStorage();
|
|
938
|
-
}
|
|
939
|
-
/**
|
|
940
|
-
* Subscribe to state changes (Svelte store contract).
|
|
941
|
-
*/
|
|
942
|
-
subscribe(subscriber) {
|
|
943
|
-
this.subscribers.add(subscriber);
|
|
944
|
-
subscriber(this.state);
|
|
945
|
-
return () => this.subscribers.delete(subscriber);
|
|
946
|
-
}
|
|
947
|
-
notify() {
|
|
948
|
-
this.subscribers.forEach((sub) => sub(this.state));
|
|
949
|
-
}
|
|
950
|
-
// Getters for direct access
|
|
951
|
-
get accessToken() {
|
|
952
|
-
return this.state.accessToken;
|
|
953
|
-
}
|
|
954
|
-
get refreshToken() {
|
|
955
|
-
return this.state.refreshToken;
|
|
956
|
-
}
|
|
957
|
-
get user() {
|
|
958
|
-
return this.state.user;
|
|
959
|
-
}
|
|
960
|
-
get isAuthenticated() {
|
|
961
|
-
return this.state.isAuthenticated;
|
|
962
|
-
}
|
|
963
|
-
/**
|
|
964
|
-
* Get the current auth state snapshot.
|
|
965
|
-
*/
|
|
966
|
-
getState() {
|
|
967
|
-
return { ...this.state };
|
|
968
|
-
}
|
|
969
|
-
/**
|
|
970
|
-
* Set auth data after successful login.
|
|
971
|
-
*/
|
|
972
|
-
setAuth(accessToken, refreshToken, user, sessionToken) {
|
|
973
|
-
const jwtPayload = decodeJWT(accessToken);
|
|
974
|
-
const userWithPermissions = {
|
|
975
|
-
...user,
|
|
976
|
-
permissions: user.permissions || jwtPayload?.permissions || [],
|
|
977
|
-
roles: user.roles || jwtPayload?.roles || (user.role ? [user.role] : [])
|
|
978
|
-
};
|
|
979
|
-
this.state = {
|
|
980
|
-
accessToken,
|
|
981
|
-
refreshToken,
|
|
982
|
-
user: userWithPermissions,
|
|
983
|
-
isAuthenticated: true
|
|
984
|
-
};
|
|
985
|
-
saveAuthToStorage(this.state);
|
|
986
|
-
if (sessionToken && typeof window !== "undefined") {
|
|
987
|
-
getStorageAdapter().setItem("sessionToken", sessionToken);
|
|
988
|
-
}
|
|
989
|
-
if (typeof window !== "undefined") {
|
|
990
|
-
window.dispatchEvent(
|
|
991
|
-
new CustomEvent("auth:login", {
|
|
992
|
-
detail: { user: userWithPermissions }
|
|
993
|
-
})
|
|
994
|
-
);
|
|
995
|
-
}
|
|
996
|
-
this.notify();
|
|
997
|
-
}
|
|
998
|
-
/**
|
|
999
|
-
* Update tokens (e.g., after refresh).
|
|
1000
|
-
*/
|
|
1001
|
-
updateTokens(accessToken, refreshToken) {
|
|
1002
|
-
const jwtPayload = decodeJWT(accessToken);
|
|
1003
|
-
const updatedUser = this.state.user ? {
|
|
1004
|
-
...this.state.user,
|
|
1005
|
-
permissions: jwtPayload?.permissions || this.state.user.permissions || [],
|
|
1006
|
-
roles: jwtPayload?.roles || this.state.user.roles || (this.state.user.role ? [this.state.user.role] : [])
|
|
1007
|
-
} : null;
|
|
1008
|
-
this.state = {
|
|
1009
|
-
...this.state,
|
|
1010
|
-
accessToken,
|
|
1011
|
-
refreshToken,
|
|
1012
|
-
user: updatedUser
|
|
1013
|
-
};
|
|
1014
|
-
saveAuthToStorage(this.state);
|
|
1015
|
-
if (typeof window !== "undefined") {
|
|
1016
|
-
window.dispatchEvent(new CustomEvent("auth:token-refresh"));
|
|
1017
|
-
}
|
|
1018
|
-
this.notify();
|
|
1019
|
-
}
|
|
1020
|
-
/**
|
|
1021
|
-
* Update user data (e.g., after profile update).
|
|
1022
|
-
*/
|
|
1023
|
-
updateUser(user) {
|
|
1024
|
-
const jwtPayload = this.state.accessToken ? decodeJWT(this.state.accessToken) : null;
|
|
1025
|
-
const updatedUser = {
|
|
1026
|
-
...user,
|
|
1027
|
-
permissions: user.permissions || jwtPayload?.permissions || [],
|
|
1028
|
-
roles: user.roles || jwtPayload?.roles || (user.role ? [user.role] : [])
|
|
1029
|
-
};
|
|
1030
|
-
this.state = {
|
|
1031
|
-
...this.state,
|
|
1032
|
-
user: updatedUser
|
|
1033
|
-
};
|
|
1034
|
-
saveAuthToStorage(this.state);
|
|
1035
|
-
if (typeof window !== "undefined") {
|
|
1036
|
-
window.dispatchEvent(
|
|
1037
|
-
new CustomEvent("auth:profile-update", {
|
|
1038
|
-
detail: { user: updatedUser }
|
|
1039
|
-
})
|
|
1040
|
-
);
|
|
1041
|
-
}
|
|
1042
|
-
this.notify();
|
|
1043
|
-
}
|
|
1044
|
-
/**
|
|
1045
|
-
* Clear auth state (logout).
|
|
1046
|
-
*/
|
|
1047
|
-
logout() {
|
|
1048
|
-
this.state = {
|
|
1049
|
-
accessToken: null,
|
|
1050
|
-
refreshToken: null,
|
|
1051
|
-
user: null,
|
|
1052
|
-
isAuthenticated: false
|
|
1053
|
-
};
|
|
1054
|
-
const storage = getStorageAdapter();
|
|
1055
|
-
storage.removeItem(getStorageKey());
|
|
1056
|
-
storage.removeItem("sessionToken");
|
|
1057
|
-
if (typeof window !== "undefined") {
|
|
1058
|
-
window.dispatchEvent(new CustomEvent("auth:logout"));
|
|
1059
|
-
}
|
|
1060
|
-
if (isInitialized()) {
|
|
1061
|
-
getConfig().onLogout?.();
|
|
1062
|
-
}
|
|
1063
|
-
this.notify();
|
|
1064
|
-
}
|
|
1065
|
-
/**
|
|
1066
|
-
* Check if user has a specific permission.
|
|
1067
|
-
*/
|
|
1068
|
-
hasPermission(permission) {
|
|
1069
|
-
return this.state.user?.permissions?.includes(permission) ?? false;
|
|
1070
|
-
}
|
|
1071
|
-
/**
|
|
1072
|
-
* Check if user has a specific role.
|
|
1073
|
-
*/
|
|
1074
|
-
hasRole(role) {
|
|
1075
|
-
return this.state.user?.roles?.includes(role) ?? false;
|
|
1076
|
-
}
|
|
1077
|
-
/**
|
|
1078
|
-
* Check if user has any of the specified roles.
|
|
1079
|
-
*/
|
|
1080
|
-
hasAnyRole(roles) {
|
|
1081
|
-
return roles.some((role) => this.state.user?.roles?.includes(role)) ?? false;
|
|
1082
|
-
}
|
|
1083
|
-
/**
|
|
1084
|
-
* Check if user has all of the specified roles.
|
|
1085
|
-
*/
|
|
1086
|
-
hasAllRoles(roles) {
|
|
1087
|
-
return roles.every((role) => this.state.user?.roles?.includes(role)) ?? false;
|
|
1088
|
-
}
|
|
1089
|
-
/**
|
|
1090
|
-
* Check if user has any of the specified permissions.
|
|
1091
|
-
*/
|
|
1092
|
-
hasAnyPermission(permissions) {
|
|
1093
|
-
return permissions.some((perm) => this.state.user?.permissions?.includes(perm)) ?? false;
|
|
1094
|
-
}
|
|
1095
|
-
/**
|
|
1096
|
-
* Check if user has all of the specified permissions.
|
|
1097
|
-
*/
|
|
1098
|
-
hasAllPermissions(permissions) {
|
|
1099
|
-
return permissions.every((perm) => this.state.user?.permissions?.includes(perm)) ?? false;
|
|
1100
|
-
}
|
|
1101
|
-
/**
|
|
1102
|
-
* Re-hydrate state from storage (useful after config changes).
|
|
1103
|
-
*/
|
|
1104
|
-
rehydrate() {
|
|
1105
|
-
this.state = loadAuthFromStorage();
|
|
1106
|
-
this.notify();
|
|
1107
|
-
}
|
|
1108
|
-
};
|
|
1109
|
-
var authStore = new AuthStore();
|
|
1110
|
-
var authActions = {
|
|
1111
|
-
setAuth: (accessToken, refreshToken, user, sessionToken) => authStore.setAuth(accessToken, refreshToken, user, sessionToken),
|
|
1112
|
-
updateTokens: (accessToken, refreshToken) => authStore.updateTokens(accessToken, refreshToken),
|
|
1113
|
-
updateUser: (user) => authStore.updateUser(user),
|
|
1114
|
-
logout: () => authStore.logout(),
|
|
1115
|
-
hasPermission: (permission) => authStore.hasPermission(permission),
|
|
1116
|
-
hasRole: (role) => authStore.hasRole(role),
|
|
1117
|
-
hasAnyRole: (roles) => authStore.hasAnyRole(roles),
|
|
1118
|
-
hasAllRoles: (roles) => authStore.hasAllRoles(roles),
|
|
1119
|
-
hasAnyPermission: (permissions) => authStore.hasAnyPermission(permissions),
|
|
1120
|
-
hasAllPermissions: (permissions) => authStore.hasAllPermissions(permissions),
|
|
1121
|
-
rehydrate: () => authStore.rehydrate()
|
|
1122
|
-
};
|
|
1123
|
-
var isAuthenticated = {
|
|
1124
|
-
subscribe: (subscriber) => {
|
|
1125
|
-
return authStore.subscribe((state) => subscriber(state.isAuthenticated));
|
|
1126
|
-
}
|
|
1127
|
-
};
|
|
1128
|
-
var currentUser = {
|
|
1129
|
-
subscribe: (subscriber) => {
|
|
1130
|
-
return authStore.subscribe((state) => subscriber(state.user));
|
|
1131
|
-
}
|
|
1132
|
-
};
|
|
1279
|
+
// src/svelte/index.ts
|
|
1280
|
+
init_auth_svelte();
|
|
1133
1281
|
|
|
1134
1282
|
// src/svelte/guards/auth-guard.ts
|
|
1283
|
+
init_auth_svelte();
|
|
1135
1284
|
function checkAuth(options = {}) {
|
|
1136
1285
|
const { roles, permissions, requireAllRoles, requireAllPermissions } = options;
|
|
1137
1286
|
if (!authStore.isAuthenticated) {
|
|
@@ -1194,4 +1343,4 @@ function protectedLoad(options, loadFn) {
|
|
|
1194
1343
|
};
|
|
1195
1344
|
}
|
|
1196
1345
|
|
|
1197
|
-
export { AuthService, api, apiRequest, authActions, authApi, authService, authStore, checkAuth, clearStoredAuth, createAuthGuard, currentUser, decodeJWT, extractClaims, extractData, getAccessToken, getConfig, getDefaultStorage, getFetch, getRefreshToken, getSessionToken, getStorage, getTokenExpiration, getTokenRemainingTime, initAuth, isAuthenticated, isInitialized, isTokenExpired, protectedLoad, requireAuth, requirePermission, requireRole, resetConfig, updateStoredTokens };
|
|
1346
|
+
export { AuthService, api, apiRequest, authActions, authApi, authService, authStore, checkAuth, clearStoredAuth, createAuthGuard, currentUser, decodeJWT, extractClaims, extractData, getAccessToken, getAvailableMethods, getConfig, getDefaultStorage, getFetch, getMfaToken, getRefreshToken, getSessionToken, getStorage, getTokenExpiration, getTokenRemainingTime, initAuth, isAuthenticated, isInitialized, isLoginSuccessResponse, isMfaChallengeResponse, isTokenExpired, protectedLoad, requireAuth, requirePermission, requireRole, resetConfig, updateStoredTokens };
|