@nauth-toolkit/client 0.1.18 → 0.1.22
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/dist/angular/index.cjs +381 -166
- package/dist/angular/index.cjs.map +1 -1
- package/dist/angular/index.d.mts +331 -127
- package/dist/angular/index.d.ts +331 -127
- package/dist/angular/index.mjs +380 -165
- package/dist/angular/index.mjs.map +1 -1
- package/dist/index.cjs +60 -110
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +65 -72
- package/dist/index.d.ts +65 -72
- package/dist/index.mjs +60 -110
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -165,12 +165,12 @@ var defaultEndpoints = {
|
|
|
165
165
|
mfaPreferred: "/mfa/preferred-method",
|
|
166
166
|
mfaBackupCodes: "/mfa/backup-codes/generate",
|
|
167
167
|
mfaExemption: "/mfa/exemption",
|
|
168
|
-
socialAuthUrl: "/social/auth-url",
|
|
169
|
-
socialCallback: "/social/callback",
|
|
170
168
|
socialLinked: "/social/linked",
|
|
171
169
|
socialLink: "/social/link",
|
|
172
170
|
socialUnlink: "/social/unlink",
|
|
173
171
|
socialVerify: "/social/:provider/verify",
|
|
172
|
+
socialRedirectStart: "/social/:provider/redirect",
|
|
173
|
+
socialExchange: "/social/exchange",
|
|
174
174
|
trustDevice: "/trust-device",
|
|
175
175
|
isTrustedDevice: "/is-trusted-device",
|
|
176
176
|
auditHistory: "/audit/history",
|
|
@@ -406,6 +406,9 @@ var BrowserStorage = class {
|
|
|
406
406
|
async removeItem(key) {
|
|
407
407
|
this.storage.removeItem(key);
|
|
408
408
|
}
|
|
409
|
+
async clear() {
|
|
410
|
+
this.storage.clear();
|
|
411
|
+
}
|
|
409
412
|
};
|
|
410
413
|
|
|
411
414
|
// src/storage/memory.ts
|
|
@@ -422,6 +425,9 @@ var InMemoryStorage = class {
|
|
|
422
425
|
async removeItem(key) {
|
|
423
426
|
this.store.delete(key);
|
|
424
427
|
}
|
|
428
|
+
async clear() {
|
|
429
|
+
this.store.clear();
|
|
430
|
+
}
|
|
425
431
|
};
|
|
426
432
|
|
|
427
433
|
// src/core/events.ts
|
|
@@ -542,9 +548,9 @@ var FetchAdapter = class {
|
|
|
542
548
|
});
|
|
543
549
|
if (!response.ok) {
|
|
544
550
|
const errorData = typeof data === "object" && data !== null ? data : {};
|
|
545
|
-
const code = typeof errorData["code"] === "string" ? errorData
|
|
546
|
-
const message = typeof errorData["message"] === "string" ? errorData
|
|
547
|
-
const timestamp = typeof errorData["timestamp"] === "string" ? errorData
|
|
551
|
+
const code = typeof errorData["code"] === "string" ? errorData["code"] : "INTERNAL_ERROR" /* INTERNAL_ERROR */;
|
|
552
|
+
const message = typeof errorData["message"] === "string" ? errorData["message"] : `Request failed with status ${status}`;
|
|
553
|
+
const timestamp = typeof errorData["timestamp"] === "string" ? errorData["timestamp"] : void 0;
|
|
548
554
|
const details = errorData["details"];
|
|
549
555
|
throw new NAuthClientError(code, message, {
|
|
550
556
|
statusCode: status,
|
|
@@ -856,7 +862,9 @@ var NAuthClient = class {
|
|
|
856
862
|
*/
|
|
857
863
|
async confirmForgotPassword(identifier, code, newPassword) {
|
|
858
864
|
const payload = { identifier, code, newPassword };
|
|
859
|
-
|
|
865
|
+
const result = await this.post(this.config.endpoints.confirmForgotPassword, payload);
|
|
866
|
+
await this.clearAuthState(false);
|
|
867
|
+
return result;
|
|
860
868
|
}
|
|
861
869
|
/**
|
|
862
870
|
* Request password change (must change on next login).
|
|
@@ -966,126 +974,57 @@ var NAuthClient = class {
|
|
|
966
974
|
// Social Authentication
|
|
967
975
|
// ============================================================================
|
|
968
976
|
/**
|
|
969
|
-
* Start social OAuth flow
|
|
977
|
+
* Start redirect-first social OAuth flow (web).
|
|
970
978
|
*
|
|
971
|
-
*
|
|
972
|
-
*
|
|
979
|
+
* This performs a browser navigation to:
|
|
980
|
+
* `GET {baseUrl}/social/:provider/redirect?returnTo=...&appState=...`
|
|
981
|
+
*
|
|
982
|
+
* The backend:
|
|
983
|
+
* - generates and stores CSRF state (cluster-safe)
|
|
984
|
+
* - redirects the user to the provider
|
|
985
|
+
* - completes OAuth on callback and sets cookies (or issues an exchange token)
|
|
986
|
+
* - redirects back to `returnTo` with `appState` (and `exchangeToken` for json/hybrid)
|
|
973
987
|
*
|
|
974
988
|
* @param provider - OAuth provider ('google', 'apple', 'facebook')
|
|
975
|
-
* @param options - Optional
|
|
989
|
+
* @param options - Optional redirect options
|
|
976
990
|
*
|
|
977
991
|
* @example
|
|
978
992
|
* ```typescript
|
|
979
|
-
*
|
|
980
|
-
* await client.loginWithSocial('google');
|
|
981
|
-
*
|
|
982
|
-
* // With custom redirect URI
|
|
983
|
-
* await client.loginWithSocial('apple', {
|
|
984
|
-
* redirectUri: 'https://example.com/auth/callback'
|
|
985
|
-
* });
|
|
993
|
+
* await client.loginWithSocial('google', { returnTo: '/auth/callback', appState: '12345' });
|
|
986
994
|
* ```
|
|
987
995
|
*/
|
|
988
|
-
async loginWithSocial(provider,
|
|
996
|
+
async loginWithSocial(provider, options) {
|
|
989
997
|
this.eventEmitter.emit({ type: "oauth:started", data: { provider }, timestamp: Date.now() });
|
|
990
|
-
const { url } = await this.getSocialAuthUrl({ provider });
|
|
991
998
|
if (hasWindow()) {
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
* Returns null if not an OAuth callback (no provider/code params).
|
|
1000
|
-
*
|
|
1001
|
-
* The SDK validates the state token, completes authentication via backend,
|
|
1002
|
-
* and emits appropriate events.
|
|
1003
|
-
*
|
|
1004
|
-
* @param urlOrParams - Optional URL string or URLSearchParams (auto-detects from window.location if not provided)
|
|
1005
|
-
* @returns AuthResponse if OAuth callback detected, null otherwise
|
|
1006
|
-
*
|
|
1007
|
-
* @example
|
|
1008
|
-
* ```typescript
|
|
1009
|
-
* // Auto-detect on app init
|
|
1010
|
-
* const response = await client.handleOAuthCallback();
|
|
1011
|
-
* if (response) {
|
|
1012
|
-
* if (response.challengeName) {
|
|
1013
|
-
* router.navigate(['/challenge', response.challengeName]);
|
|
1014
|
-
* } else {
|
|
1015
|
-
* router.navigate(['/']); // Navigate to your app's home route
|
|
1016
|
-
* }
|
|
1017
|
-
* }
|
|
1018
|
-
*
|
|
1019
|
-
* // In callback route
|
|
1020
|
-
* const response = await client.handleOAuthCallback(window.location.search);
|
|
1021
|
-
* ```
|
|
1022
|
-
*/
|
|
1023
|
-
async handleOAuthCallback(urlOrParams) {
|
|
1024
|
-
let params;
|
|
1025
|
-
if (urlOrParams instanceof URLSearchParams) {
|
|
1026
|
-
params = urlOrParams;
|
|
1027
|
-
} else if (typeof urlOrParams === "string") {
|
|
1028
|
-
params = new URLSearchParams(urlOrParams);
|
|
1029
|
-
} else if (hasWindow()) {
|
|
1030
|
-
params = new URLSearchParams(window.location.search);
|
|
1031
|
-
} else {
|
|
1032
|
-
return null;
|
|
1033
|
-
}
|
|
1034
|
-
const provider = params.get("provider");
|
|
1035
|
-
const code = params.get("code");
|
|
1036
|
-
const state = params.get("state");
|
|
1037
|
-
const error = params.get("error");
|
|
1038
|
-
if (!provider || !code && !error) {
|
|
1039
|
-
return null;
|
|
1040
|
-
}
|
|
1041
|
-
this.eventEmitter.emit({ type: "oauth:callback", data: { provider }, timestamp: Date.now() });
|
|
1042
|
-
try {
|
|
1043
|
-
if (error) {
|
|
1044
|
-
const authError = new NAuthClientError(
|
|
1045
|
-
"SOCIAL_TOKEN_INVALID" /* SOCIAL_TOKEN_INVALID */,
|
|
1046
|
-
params.get("error_description") || error,
|
|
1047
|
-
{ details: { error, provider } }
|
|
1048
|
-
);
|
|
1049
|
-
this.eventEmitter.emit({ type: "oauth:error", data: authError, timestamp: Date.now() });
|
|
1050
|
-
throw authError;
|
|
999
|
+
const startPath = this.config.endpoints.socialRedirectStart.replace(":provider", provider);
|
|
1000
|
+
const base = this.config.baseUrl.replace(/\/$/, "");
|
|
1001
|
+
const startUrl = new URL(`${base}${startPath}`);
|
|
1002
|
+
const returnTo = options?.returnTo ?? this.config.redirects?.success ?? "/";
|
|
1003
|
+
startUrl.searchParams.set("returnTo", returnTo);
|
|
1004
|
+
if (options?.action === "link") {
|
|
1005
|
+
startUrl.searchParams.set("action", "link");
|
|
1051
1006
|
}
|
|
1052
|
-
if (
|
|
1053
|
-
|
|
1007
|
+
if (typeof options?.appState === "string" && options.appState.trim() !== "") {
|
|
1008
|
+
startUrl.searchParams.set("appState", options.appState);
|
|
1054
1009
|
}
|
|
1055
|
-
|
|
1056
|
-
provider,
|
|
1057
|
-
code,
|
|
1058
|
-
state
|
|
1059
|
-
});
|
|
1060
|
-
if (response.challengeName) {
|
|
1061
|
-
this.eventEmitter.emit({ type: "auth:challenge", data: response, timestamp: Date.now() });
|
|
1062
|
-
} else {
|
|
1063
|
-
this.eventEmitter.emit({ type: "auth:success", data: response, timestamp: Date.now() });
|
|
1064
|
-
}
|
|
1065
|
-
this.eventEmitter.emit({ type: "oauth:completed", data: response, timestamp: Date.now() });
|
|
1066
|
-
return response;
|
|
1067
|
-
} catch (error2) {
|
|
1068
|
-
const authError = error2 instanceof NAuthClientError ? error2 : new NAuthClientError(
|
|
1069
|
-
"SOCIAL_TOKEN_INVALID" /* SOCIAL_TOKEN_INVALID */,
|
|
1070
|
-
error2.message || "OAuth callback failed"
|
|
1071
|
-
);
|
|
1072
|
-
this.eventEmitter.emit({ type: "oauth:error", data: authError, timestamp: Date.now() });
|
|
1073
|
-
throw authError;
|
|
1010
|
+
window.location.href = startUrl.toString();
|
|
1074
1011
|
}
|
|
1075
1012
|
}
|
|
1076
1013
|
/**
|
|
1077
|
-
*
|
|
1014
|
+
* Exchange an `exchangeToken` (from redirect callback URL) into an AuthResponse.
|
|
1078
1015
|
*
|
|
1079
|
-
*
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
/**
|
|
1085
|
-
* Handle social callback.
|
|
1016
|
+
* Used for `tokenDelivery: 'json'` or hybrid flows where the backend redirects back
|
|
1017
|
+
* with `exchangeToken` instead of setting cookies.
|
|
1018
|
+
*
|
|
1019
|
+
* @param exchangeToken - One-time exchange token from the callback URL
|
|
1020
|
+
* @returns AuthResponse
|
|
1086
1021
|
*/
|
|
1087
|
-
async
|
|
1088
|
-
const
|
|
1022
|
+
async exchangeSocialRedirect(exchangeToken) {
|
|
1023
|
+
const token = exchangeToken?.trim();
|
|
1024
|
+
if (!token) {
|
|
1025
|
+
throw new NAuthClientError("CHALLENGE_INVALID" /* CHALLENGE_INVALID */, "Missing exchangeToken");
|
|
1026
|
+
}
|
|
1027
|
+
const result = await this.post(this.config.endpoints.socialExchange, { exchangeToken: token });
|
|
1089
1028
|
await this.handleAuthResponse(result);
|
|
1090
1029
|
return result;
|
|
1091
1030
|
}
|
|
@@ -1274,7 +1213,9 @@ var NAuthClient = class {
|
|
|
1274
1213
|
await this.setDeviceToken(response.deviceToken);
|
|
1275
1214
|
}
|
|
1276
1215
|
if (response.user) {
|
|
1277
|
-
|
|
1216
|
+
const user = response.user;
|
|
1217
|
+
user.sessionAuthMethod = response.authMethod ?? null;
|
|
1218
|
+
await this.setUser(user);
|
|
1278
1219
|
}
|
|
1279
1220
|
await this.clearChallenge();
|
|
1280
1221
|
}
|
|
@@ -1346,6 +1287,15 @@ var NAuthClient = class {
|
|
|
1346
1287
|
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1347
1288
|
}
|
|
1348
1289
|
}
|
|
1290
|
+
if (this.config.tokenDelivery === "json") {
|
|
1291
|
+
try {
|
|
1292
|
+
const deviceToken = await this.config.storage.getItem(this.config.deviceTrust.storageKey);
|
|
1293
|
+
if (deviceToken) {
|
|
1294
|
+
headers[this.config.deviceTrust.headerName] = deviceToken;
|
|
1295
|
+
}
|
|
1296
|
+
} catch {
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1349
1299
|
if (this.config.tokenDelivery === "cookies" && hasWindow()) {
|
|
1350
1300
|
const csrfToken = this.getCsrfToken();
|
|
1351
1301
|
if (csrfToken) {
|