@nauth-toolkit/client 0.1.89 → 0.1.90
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/index.cjs +756 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +1245 -18
- package/dist/index.d.ts +1245 -18
- package/dist/index.mjs +754 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -136,11 +136,45 @@ var defaultEndpoints = {
|
|
|
136
136
|
auditHistory: "/audit/history",
|
|
137
137
|
updateProfile: "/profile"
|
|
138
138
|
};
|
|
139
|
+
var defaultAdminEndpoints = {
|
|
140
|
+
signup: "/signup",
|
|
141
|
+
signupSocial: "/signup-social",
|
|
142
|
+
getUsers: "/users",
|
|
143
|
+
getUser: "/users/:sub",
|
|
144
|
+
deleteUser: "/users/:sub",
|
|
145
|
+
disableUser: "/users/:sub/disable",
|
|
146
|
+
enableUser: "/users/:sub/enable",
|
|
147
|
+
forcePasswordChange: "/users/:sub/force-password-change",
|
|
148
|
+
setPassword: "/set-password",
|
|
149
|
+
resetPasswordInitiate: "/reset-password/initiate",
|
|
150
|
+
getUserSessions: "/users/:sub/sessions",
|
|
151
|
+
logoutAll: "/users/:sub/logout-all",
|
|
152
|
+
getMfaStatus: "/users/:sub/mfa/status",
|
|
153
|
+
setPreferredMfaMethod: "/mfa/preferred-method",
|
|
154
|
+
removeMfaDevices: "/mfa/remove-devices",
|
|
155
|
+
setMfaExemption: "/mfa/exemption",
|
|
156
|
+
getAuditHistory: "/audit/history"
|
|
157
|
+
};
|
|
139
158
|
var resolveConfig = (config, defaultAdapter) => {
|
|
140
159
|
const resolvedEndpoints = {
|
|
141
160
|
...defaultEndpoints,
|
|
142
161
|
...config.endpoints ?? {}
|
|
143
162
|
};
|
|
163
|
+
let resolvedAdmin;
|
|
164
|
+
if (config.admin) {
|
|
165
|
+
const resolvedAdminEndpoints = {
|
|
166
|
+
...defaultAdminEndpoints,
|
|
167
|
+
...config.admin.endpoints ?? {}
|
|
168
|
+
};
|
|
169
|
+
resolvedAdmin = {
|
|
170
|
+
pathPrefix: config.admin.pathPrefix ?? "/admin",
|
|
171
|
+
endpoints: resolvedAdminEndpoints,
|
|
172
|
+
headers: {
|
|
173
|
+
...config.headers,
|
|
174
|
+
...config.admin.headers ?? {}
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
144
178
|
return {
|
|
145
179
|
...config,
|
|
146
180
|
csrf: {
|
|
@@ -155,7 +189,8 @@ var resolveConfig = (config, defaultAdapter) => {
|
|
|
155
189
|
timeout: config.timeout ?? 3e4,
|
|
156
190
|
endpoints: resolvedEndpoints,
|
|
157
191
|
storage: config.storage,
|
|
158
|
-
httpAdapter: config.httpAdapter ?? defaultAdapter
|
|
192
|
+
httpAdapter: config.httpAdapter ?? defaultAdapter,
|
|
193
|
+
admin: resolvedAdmin
|
|
159
194
|
};
|
|
160
195
|
};
|
|
161
196
|
|
|
@@ -528,8 +563,9 @@ var FetchAdapter = class {
|
|
|
528
563
|
// src/core/challenge-router.ts
|
|
529
564
|
var OAUTH_STATE_KEY = "nauth_oauth_state";
|
|
530
565
|
var ChallengeRouter = class {
|
|
531
|
-
constructor(config) {
|
|
566
|
+
constructor(config, oauthStorage) {
|
|
532
567
|
this.config = config;
|
|
568
|
+
this.oauthStorage = oauthStorage;
|
|
533
569
|
}
|
|
534
570
|
/**
|
|
535
571
|
* Handle auth response - either call callback or auto-navigate.
|
|
@@ -545,10 +581,39 @@ var ChallengeRouter = class {
|
|
|
545
581
|
if (response.challengeName) {
|
|
546
582
|
await this.navigateToChallenge(response);
|
|
547
583
|
} else {
|
|
548
|
-
const queryParams = await this.getStoredOauthState();
|
|
549
|
-
await this.navigateToSuccess(queryParams);
|
|
584
|
+
const queryParams = context.appState ? { appState: context.appState } : await this.getStoredOauthState();
|
|
585
|
+
await this.navigateToSuccess(queryParams, context);
|
|
550
586
|
}
|
|
551
587
|
}
|
|
588
|
+
/**
|
|
589
|
+
* Resolve the configured success URL based on context and explicit override keys.
|
|
590
|
+
*
|
|
591
|
+
* IMPORTANT:
|
|
592
|
+
* - `null` explicitly disables auto-navigation (caller should rely on framework events / custom routing).
|
|
593
|
+
* - `undefined` / missing keys fall back to other configured values or defaults.
|
|
594
|
+
* - Falls back to legacy `redirects.success` when new keys are not set.
|
|
595
|
+
*
|
|
596
|
+
* @param context - Auth response context
|
|
597
|
+
* @returns URL string, or null when auto-navigation is disabled
|
|
598
|
+
*/
|
|
599
|
+
resolveSuccessUrl(context) {
|
|
600
|
+
const redirects = this.config.redirects;
|
|
601
|
+
if (!redirects) {
|
|
602
|
+
return "/";
|
|
603
|
+
}
|
|
604
|
+
const isSignup = context?.source === "signup";
|
|
605
|
+
if (isSignup) {
|
|
606
|
+
if (redirects.signupSuccess === null) return null;
|
|
607
|
+
if (typeof redirects.signupSuccess === "string") return redirects.signupSuccess;
|
|
608
|
+
}
|
|
609
|
+
if (!isSignup) {
|
|
610
|
+
if (redirects.loginSuccess === null) return null;
|
|
611
|
+
if (typeof redirects.loginSuccess === "string") return redirects.loginSuccess;
|
|
612
|
+
}
|
|
613
|
+
if (redirects.success === null) return null;
|
|
614
|
+
if (typeof redirects.success === "string") return redirects.success;
|
|
615
|
+
return "/";
|
|
616
|
+
}
|
|
552
617
|
/**
|
|
553
618
|
* Navigate to appropriate challenge route.
|
|
554
619
|
*
|
|
@@ -562,14 +627,19 @@ var ChallengeRouter = class {
|
|
|
562
627
|
* Navigate to success URL.
|
|
563
628
|
*
|
|
564
629
|
* @param queryParams - Optional query parameters to append to the success URL
|
|
630
|
+
* @param context - Optional auth context for selecting the success route
|
|
565
631
|
*
|
|
566
632
|
* @example
|
|
567
633
|
* ```typescript
|
|
568
634
|
* await router.navigateToSuccess({ appState: 'invite-code-123' });
|
|
569
635
|
* ```
|
|
570
636
|
*/
|
|
571
|
-
async navigateToSuccess(queryParams) {
|
|
572
|
-
|
|
637
|
+
async navigateToSuccess(queryParams, context) {
|
|
638
|
+
const resolved = this.resolveSuccessUrl(context);
|
|
639
|
+
if (resolved === null) {
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
let url = resolved;
|
|
573
643
|
if (queryParams && Object.keys(queryParams).length > 0) {
|
|
574
644
|
const searchParams = new URLSearchParams();
|
|
575
645
|
Object.entries(queryParams).forEach(([key, value]) => {
|
|
@@ -583,15 +653,18 @@ var ChallengeRouter = class {
|
|
|
583
653
|
await this.navigate(url);
|
|
584
654
|
}
|
|
585
655
|
/**
|
|
586
|
-
* Retrieve stored OAuth appState from
|
|
656
|
+
* Retrieve stored OAuth appState from sessionStorage.
|
|
657
|
+
*
|
|
658
|
+
* NOTE: This method does NOT clear the storage. Only the public getLastOauthState() API clears it.
|
|
659
|
+
* This allows the SDK to read appState for auto-navigation while still making it available to
|
|
660
|
+
* consumers via the public API.
|
|
587
661
|
*
|
|
588
662
|
* @returns Query params object with appState if present, undefined otherwise
|
|
589
663
|
*/
|
|
590
664
|
async getStoredOauthState() {
|
|
591
665
|
try {
|
|
592
|
-
const stored = await this.
|
|
666
|
+
const stored = await this.oauthStorage.getItem(OAUTH_STATE_KEY);
|
|
593
667
|
if (stored) {
|
|
594
|
-
await this.config.storage.removeItem(OAUTH_STATE_KEY);
|
|
595
668
|
return { appState: stored };
|
|
596
669
|
}
|
|
597
670
|
} catch {
|
|
@@ -604,7 +677,12 @@ var ChallengeRouter = class {
|
|
|
604
677
|
* @param type - Type of error (oauth or session)
|
|
605
678
|
*/
|
|
606
679
|
async navigateToError(type) {
|
|
607
|
-
const
|
|
680
|
+
const redirects = this.config.redirects;
|
|
681
|
+
const raw = type === "oauth" ? redirects?.oauthError : redirects?.sessionExpired;
|
|
682
|
+
if (raw === null) {
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
const url = raw ?? "/login";
|
|
608
686
|
await this.navigate(url);
|
|
609
687
|
}
|
|
610
688
|
/**
|
|
@@ -709,13 +787,625 @@ var ChallengeRouter = class {
|
|
|
709
787
|
}
|
|
710
788
|
};
|
|
711
789
|
|
|
790
|
+
// src/core/admin-operations.ts
|
|
791
|
+
var hasWindow = () => typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
|
|
792
|
+
var AdminOperations = class {
|
|
793
|
+
/**
|
|
794
|
+
* Create admin operations instance.
|
|
795
|
+
*
|
|
796
|
+
* @param config - Resolved client configuration
|
|
797
|
+
*/
|
|
798
|
+
constructor(config) {
|
|
799
|
+
__publicField(this, "config");
|
|
800
|
+
__publicField(this, "adminEndpoints");
|
|
801
|
+
__publicField(this, "adminPathPrefix");
|
|
802
|
+
__publicField(this, "adminHeaders");
|
|
803
|
+
if (!config.admin) {
|
|
804
|
+
throw new Error("Admin operations require admin configuration");
|
|
805
|
+
}
|
|
806
|
+
this.config = config;
|
|
807
|
+
this.adminEndpoints = config.admin.endpoints;
|
|
808
|
+
this.adminPathPrefix = config.admin.pathPrefix;
|
|
809
|
+
this.adminHeaders = config.admin.headers;
|
|
810
|
+
}
|
|
811
|
+
// ============================================================================
|
|
812
|
+
// User Management
|
|
813
|
+
// ============================================================================
|
|
814
|
+
/**
|
|
815
|
+
* Create a new user (admin operation)
|
|
816
|
+
*
|
|
817
|
+
* Allows creating users with:
|
|
818
|
+
* - Pre-verified email/phone
|
|
819
|
+
* - Auto-generated passwords
|
|
820
|
+
* - Force password change flag
|
|
821
|
+
*
|
|
822
|
+
* @param request - User creation request
|
|
823
|
+
* @returns Created user and optional generated password
|
|
824
|
+
* @throws {NAuthClientError} If creation fails
|
|
825
|
+
*
|
|
826
|
+
* @example
|
|
827
|
+
* ```typescript
|
|
828
|
+
* const result = await client.admin.createUser({
|
|
829
|
+
* email: 'user@example.com',
|
|
830
|
+
* password: 'SecurePass123!',
|
|
831
|
+
* isEmailVerified: true,
|
|
832
|
+
* });
|
|
833
|
+
*
|
|
834
|
+
* // With auto-generated password
|
|
835
|
+
* const result = await client.admin.createUser({
|
|
836
|
+
* email: 'user@example.com',
|
|
837
|
+
* generatePassword: true,
|
|
838
|
+
* mustChangePassword: true,
|
|
839
|
+
* });
|
|
840
|
+
* console.log('Generated password:', result.generatedPassword);
|
|
841
|
+
* ```
|
|
842
|
+
*/
|
|
843
|
+
async createUser(request) {
|
|
844
|
+
const path = this.buildAdminUrl(this.adminEndpoints.signup);
|
|
845
|
+
return this.post(path, request);
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Import social user (admin operation)
|
|
849
|
+
*
|
|
850
|
+
* Imports existing social users from external platforms (e.g., Cognito, Auth0)
|
|
851
|
+
* with social account linkage.
|
|
852
|
+
*
|
|
853
|
+
* @param request - Social user import request
|
|
854
|
+
* @returns Created user and social account info
|
|
855
|
+
* @throws {NAuthClientError} If import fails
|
|
856
|
+
*
|
|
857
|
+
* @example
|
|
858
|
+
* ```typescript
|
|
859
|
+
* const result = await client.admin.importSocialUser({
|
|
860
|
+
* email: 'user@example.com',
|
|
861
|
+
* provider: 'google',
|
|
862
|
+
* providerId: 'google_12345',
|
|
863
|
+
* providerEmail: 'user@gmail.com',
|
|
864
|
+
* });
|
|
865
|
+
* ```
|
|
866
|
+
*/
|
|
867
|
+
async importSocialUser(request) {
|
|
868
|
+
const path = this.buildAdminUrl(this.adminEndpoints.signupSocial);
|
|
869
|
+
return this.post(path, request);
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Get users with filters and pagination
|
|
873
|
+
*
|
|
874
|
+
* @param params - Filter and pagination params
|
|
875
|
+
* @returns Paginated user list
|
|
876
|
+
* @throws {NAuthClientError} If request fails
|
|
877
|
+
*
|
|
878
|
+
* @example
|
|
879
|
+
* ```typescript
|
|
880
|
+
* const result = await client.admin.getUsers({
|
|
881
|
+
* page: 1,
|
|
882
|
+
* limit: 20,
|
|
883
|
+
* isEmailVerified: true,
|
|
884
|
+
* mfaEnabled: false,
|
|
885
|
+
* sortBy: 'createdAt',
|
|
886
|
+
* sortOrder: 'DESC',
|
|
887
|
+
* });
|
|
888
|
+
* ```
|
|
889
|
+
*/
|
|
890
|
+
async getUsers(params = {}) {
|
|
891
|
+
const path = this.buildAdminUrl(this.adminEndpoints.getUsers);
|
|
892
|
+
const queryString = this.buildQueryString(params);
|
|
893
|
+
return this.get(`${path}${queryString}`);
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Get user by sub (UUID)
|
|
897
|
+
*
|
|
898
|
+
* @param sub - User UUID
|
|
899
|
+
* @returns User object
|
|
900
|
+
* @throws {NAuthClientError} If user not found
|
|
901
|
+
*
|
|
902
|
+
* @example
|
|
903
|
+
* ```typescript
|
|
904
|
+
* const user = await client.admin.getUser('a21b654c-2746-4168-acee-c175083a65cd');
|
|
905
|
+
* ```
|
|
906
|
+
*/
|
|
907
|
+
async getUser(sub) {
|
|
908
|
+
const path = this.buildAdminUrl(this.adminEndpoints.getUser, { sub });
|
|
909
|
+
return this.get(path);
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* Delete user with cascade cleanup
|
|
913
|
+
*
|
|
914
|
+
* @param sub - User UUID
|
|
915
|
+
* @returns Deletion confirmation with cascade counts
|
|
916
|
+
* @throws {NAuthClientError} If deletion fails
|
|
917
|
+
*
|
|
918
|
+
* @example
|
|
919
|
+
* ```typescript
|
|
920
|
+
* const result = await client.admin.deleteUser('user-uuid');
|
|
921
|
+
* console.log('Deleted records:', result.deletedRecords);
|
|
922
|
+
* ```
|
|
923
|
+
*/
|
|
924
|
+
async deleteUser(sub) {
|
|
925
|
+
const path = this.buildAdminUrl(this.adminEndpoints.deleteUser, { sub });
|
|
926
|
+
return this.delete(path);
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Disable user account (permanent lock)
|
|
930
|
+
*
|
|
931
|
+
* @param sub - User UUID
|
|
932
|
+
* @param reason - Optional reason for disabling
|
|
933
|
+
* @returns Disable confirmation with revoked session count
|
|
934
|
+
* @throws {NAuthClientError} If operation fails
|
|
935
|
+
*
|
|
936
|
+
* @example
|
|
937
|
+
* ```typescript
|
|
938
|
+
* const result = await client.admin.disableUser(
|
|
939
|
+
* 'user-uuid',
|
|
940
|
+
* 'Account compromised'
|
|
941
|
+
* );
|
|
942
|
+
* console.log('Revoked sessions:', result.revokedSessions);
|
|
943
|
+
* ```
|
|
944
|
+
*/
|
|
945
|
+
async disableUser(sub, reason) {
|
|
946
|
+
const path = this.buildAdminUrl(this.adminEndpoints.disableUser, { sub });
|
|
947
|
+
return this.post(path, { reason });
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Enable (unlock) user account
|
|
951
|
+
*
|
|
952
|
+
* @param sub - User UUID
|
|
953
|
+
* @returns Enable confirmation with updated user
|
|
954
|
+
* @throws {NAuthClientError} If operation fails
|
|
955
|
+
*
|
|
956
|
+
* @example
|
|
957
|
+
* ```typescript
|
|
958
|
+
* const result = await client.admin.enableUser('user-uuid');
|
|
959
|
+
* console.log('User enabled:', result.user);
|
|
960
|
+
* ```
|
|
961
|
+
*/
|
|
962
|
+
async enableUser(sub) {
|
|
963
|
+
const path = this.buildAdminUrl(this.adminEndpoints.enableUser, { sub });
|
|
964
|
+
return this.post(path, {});
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* Force password change on next login
|
|
968
|
+
*
|
|
969
|
+
* @param sub - User UUID
|
|
970
|
+
* @returns Success confirmation
|
|
971
|
+
* @throws {NAuthClientError} If operation fails
|
|
972
|
+
*
|
|
973
|
+
* @example
|
|
974
|
+
* ```typescript
|
|
975
|
+
* await client.admin.forcePasswordChange('user-uuid');
|
|
976
|
+
* ```
|
|
977
|
+
*/
|
|
978
|
+
async forcePasswordChange(sub) {
|
|
979
|
+
const path = this.buildAdminUrl(this.adminEndpoints.forcePasswordChange, { sub });
|
|
980
|
+
return this.post(path, {});
|
|
981
|
+
}
|
|
982
|
+
// ============================================================================
|
|
983
|
+
// Password Management
|
|
984
|
+
// ============================================================================
|
|
985
|
+
/**
|
|
986
|
+
* Set password for any user (admin operation)
|
|
987
|
+
*
|
|
988
|
+
* @param identifier - User email, username, or phone
|
|
989
|
+
* @param newPassword - New password
|
|
990
|
+
* @returns Success confirmation
|
|
991
|
+
* @throws {NAuthClientError} If operation fails
|
|
992
|
+
*
|
|
993
|
+
* @example
|
|
994
|
+
* ```typescript
|
|
995
|
+
* await client.admin.setPassword('user@example.com', 'NewSecurePass123!');
|
|
996
|
+
* ```
|
|
997
|
+
*/
|
|
998
|
+
async setPassword(identifier, newPassword) {
|
|
999
|
+
const path = this.buildAdminUrl(this.adminEndpoints.setPassword);
|
|
1000
|
+
return this.post(path, { identifier, newPassword });
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Initiate password reset workflow (sends code/link to user)
|
|
1004
|
+
*
|
|
1005
|
+
* @param request - Password reset request
|
|
1006
|
+
* @returns Reset confirmation with delivery details
|
|
1007
|
+
* @throws {NAuthClientError} If operation fails
|
|
1008
|
+
*
|
|
1009
|
+
* @example
|
|
1010
|
+
* ```typescript
|
|
1011
|
+
* const result = await client.admin.initiatePasswordReset({
|
|
1012
|
+
* sub: 'user-uuid',
|
|
1013
|
+
* deliveryMethod: 'email',
|
|
1014
|
+
* baseUrl: 'https://myapp.com/reset-password',
|
|
1015
|
+
* reason: 'User requested password reset',
|
|
1016
|
+
* });
|
|
1017
|
+
* console.log('Code sent to:', result.destination);
|
|
1018
|
+
* ```
|
|
1019
|
+
*/
|
|
1020
|
+
async initiatePasswordReset(request) {
|
|
1021
|
+
const path = this.buildAdminUrl(this.adminEndpoints.resetPasswordInitiate);
|
|
1022
|
+
return this.post(path, request);
|
|
1023
|
+
}
|
|
1024
|
+
// ============================================================================
|
|
1025
|
+
// Session Management
|
|
1026
|
+
// ============================================================================
|
|
1027
|
+
/**
|
|
1028
|
+
* Get all sessions for a user
|
|
1029
|
+
*
|
|
1030
|
+
* @param sub - User UUID
|
|
1031
|
+
* @returns User sessions
|
|
1032
|
+
* @throws {NAuthClientError} If request fails
|
|
1033
|
+
*
|
|
1034
|
+
* @example
|
|
1035
|
+
* ```typescript
|
|
1036
|
+
* const result = await client.admin.getUserSessions('user-uuid');
|
|
1037
|
+
* console.log('Active sessions:', result.sessions);
|
|
1038
|
+
* ```
|
|
1039
|
+
*/
|
|
1040
|
+
async getUserSessions(sub) {
|
|
1041
|
+
const path = this.buildAdminUrl(this.adminEndpoints.getUserSessions, { sub });
|
|
1042
|
+
return this.get(path);
|
|
1043
|
+
}
|
|
1044
|
+
/**
|
|
1045
|
+
* Logout all sessions for a user (admin-initiated)
|
|
1046
|
+
*
|
|
1047
|
+
* @param sub - User UUID
|
|
1048
|
+
* @param forgetDevices - If true, also revokes all trusted devices
|
|
1049
|
+
* @returns Number of sessions revoked
|
|
1050
|
+
* @throws {NAuthClientError} If operation fails
|
|
1051
|
+
*
|
|
1052
|
+
* @example
|
|
1053
|
+
* ```typescript
|
|
1054
|
+
* const result = await client.admin.logoutAllSessions('user-uuid', true);
|
|
1055
|
+
* console.log(`Revoked ${result.revokedCount} sessions`);
|
|
1056
|
+
* ```
|
|
1057
|
+
*/
|
|
1058
|
+
async logoutAllSessions(sub, forgetDevices = false) {
|
|
1059
|
+
const path = this.buildAdminUrl(this.adminEndpoints.logoutAll, { sub });
|
|
1060
|
+
return this.post(path, { forgetDevices });
|
|
1061
|
+
}
|
|
1062
|
+
// ============================================================================
|
|
1063
|
+
// MFA Management
|
|
1064
|
+
// ============================================================================
|
|
1065
|
+
/**
|
|
1066
|
+
* Get MFA status for a user
|
|
1067
|
+
*
|
|
1068
|
+
* @param sub - User UUID
|
|
1069
|
+
* @returns MFA status
|
|
1070
|
+
* @throws {NAuthClientError} If request fails
|
|
1071
|
+
*
|
|
1072
|
+
* @example
|
|
1073
|
+
* ```typescript
|
|
1074
|
+
* const status = await client.admin.getMfaStatus('user-uuid');
|
|
1075
|
+
* console.log('MFA enabled:', status.enabled);
|
|
1076
|
+
* ```
|
|
1077
|
+
*/
|
|
1078
|
+
async getMfaStatus(sub) {
|
|
1079
|
+
const path = this.buildAdminUrl(this.adminEndpoints.getMfaStatus, { sub });
|
|
1080
|
+
return this.get(path);
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Set preferred MFA method for a user
|
|
1084
|
+
*
|
|
1085
|
+
* @param sub - User UUID
|
|
1086
|
+
* @param method - MFA method to set as preferred
|
|
1087
|
+
* @returns Success message
|
|
1088
|
+
* @throws {NAuthClientError} If operation fails
|
|
1089
|
+
*
|
|
1090
|
+
* @example
|
|
1091
|
+
* ```typescript
|
|
1092
|
+
* await client.admin.setPreferredMfaMethod('user-uuid', 'totp');
|
|
1093
|
+
* ```
|
|
1094
|
+
*/
|
|
1095
|
+
async setPreferredMfaMethod(sub, method) {
|
|
1096
|
+
const path = this.buildAdminUrl(this.adminEndpoints.setPreferredMfaMethod);
|
|
1097
|
+
return this.post(path, { sub, method });
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Remove MFA devices for a user
|
|
1101
|
+
*
|
|
1102
|
+
* @param sub - User UUID
|
|
1103
|
+
* @param method - MFA method to remove
|
|
1104
|
+
* @returns Success message
|
|
1105
|
+
* @throws {NAuthClientError} If operation fails
|
|
1106
|
+
*
|
|
1107
|
+
* @example
|
|
1108
|
+
* ```typescript
|
|
1109
|
+
* await client.admin.removeMfaDevices('user-uuid', 'sms');
|
|
1110
|
+
* ```
|
|
1111
|
+
*/
|
|
1112
|
+
async removeMfaDevices(sub, method) {
|
|
1113
|
+
const path = this.buildAdminUrl(this.adminEndpoints.removeMfaDevices);
|
|
1114
|
+
return this.post(path, { sub, method });
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Grant or revoke MFA exemption for a user
|
|
1118
|
+
*
|
|
1119
|
+
* @param sub - User UUID
|
|
1120
|
+
* @param exempt - True to exempt from MFA, false to require
|
|
1121
|
+
* @param reason - Optional reason for exemption
|
|
1122
|
+
* @returns Success message
|
|
1123
|
+
* @throws {NAuthClientError} If operation fails
|
|
1124
|
+
*
|
|
1125
|
+
* @example
|
|
1126
|
+
* ```typescript
|
|
1127
|
+
* await client.admin.setMfaExemption('user-uuid', true, 'Service account');
|
|
1128
|
+
* ```
|
|
1129
|
+
*/
|
|
1130
|
+
async setMfaExemption(sub, exempt, reason) {
|
|
1131
|
+
const path = this.buildAdminUrl(this.adminEndpoints.setMfaExemption);
|
|
1132
|
+
return this.post(path, { sub, exempt, reason });
|
|
1133
|
+
}
|
|
1134
|
+
// ============================================================================
|
|
1135
|
+
// Audit
|
|
1136
|
+
// ============================================================================
|
|
1137
|
+
/**
|
|
1138
|
+
* Get audit history for a user
|
|
1139
|
+
*
|
|
1140
|
+
* @param params - Audit history request params
|
|
1141
|
+
* @returns Paginated audit events
|
|
1142
|
+
* @throws {NAuthClientError} If request fails
|
|
1143
|
+
*
|
|
1144
|
+
* @example
|
|
1145
|
+
* ```typescript
|
|
1146
|
+
* const history = await client.admin.getAuditHistory({
|
|
1147
|
+
* sub: 'user-uuid',
|
|
1148
|
+
* page: 1,
|
|
1149
|
+
* limit: 50,
|
|
1150
|
+
* eventType: 'LOGIN_SUCCESS',
|
|
1151
|
+
* });
|
|
1152
|
+
* ```
|
|
1153
|
+
*/
|
|
1154
|
+
async getAuditHistory(params) {
|
|
1155
|
+
const path = this.buildAdminUrl(this.adminEndpoints.getAuditHistory);
|
|
1156
|
+
const queryString = this.buildQueryString(params);
|
|
1157
|
+
return this.get(`${path}${queryString}`);
|
|
1158
|
+
}
|
|
1159
|
+
// ============================================================================
|
|
1160
|
+
// Private Helper Methods
|
|
1161
|
+
// ============================================================================
|
|
1162
|
+
/**
|
|
1163
|
+
* Build admin endpoint URL with path parameter replacement
|
|
1164
|
+
*
|
|
1165
|
+
* Path construction order:
|
|
1166
|
+
* 1. Start with endpoint: '/users/:sub'
|
|
1167
|
+
* 2. Replace params: '/users/uuid-123'
|
|
1168
|
+
* 3. Apply adminPathPrefix: '/admin/users/uuid-123'
|
|
1169
|
+
* 4. Apply authPathPrefix if exists: '/auth/admin/users/uuid-123'
|
|
1170
|
+
* 5. Combine with baseUrl: 'https://api.example.com/auth/admin/users/uuid-123'
|
|
1171
|
+
*
|
|
1172
|
+
* @param endpointPath - Endpoint path (may contain :sub, :provider, etc.)
|
|
1173
|
+
* @param pathParams - Path parameters to replace
|
|
1174
|
+
* @returns Full URL
|
|
1175
|
+
* @private
|
|
1176
|
+
*/
|
|
1177
|
+
buildAdminUrl(endpointPath, pathParams) {
|
|
1178
|
+
let path = endpointPath;
|
|
1179
|
+
if (pathParams) {
|
|
1180
|
+
Object.entries(pathParams).forEach(([key, value]) => {
|
|
1181
|
+
path = path.replace(`:${key}`, encodeURIComponent(value));
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
const prefix = this.adminPathPrefix.startsWith("/") ? this.adminPathPrefix : `/${this.adminPathPrefix}`;
|
|
1185
|
+
path = `${prefix}${path.startsWith("/") ? "" : "/"}${path}`;
|
|
1186
|
+
if (this.config.authPathPrefix) {
|
|
1187
|
+
const authPrefix = this.config.authPathPrefix.startsWith("/") ? this.config.authPathPrefix : `/${this.config.authPathPrefix}`;
|
|
1188
|
+
path = `${authPrefix}${path}`;
|
|
1189
|
+
}
|
|
1190
|
+
const normalizedBase = this.config.baseUrl.endsWith("/") ? this.config.baseUrl.slice(0, -1) : this.config.baseUrl;
|
|
1191
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
1192
|
+
return `${normalizedBase}${normalizedPath}`;
|
|
1193
|
+
}
|
|
1194
|
+
/**
|
|
1195
|
+
* Build query string from params object
|
|
1196
|
+
*
|
|
1197
|
+
* Handles:
|
|
1198
|
+
* - Simple values (string, number, boolean)
|
|
1199
|
+
* - Arrays (multiple values for same key)
|
|
1200
|
+
* - Nested objects (e.g., createdAt[operator], createdAt[value])
|
|
1201
|
+
* - Dates (converted to ISO string)
|
|
1202
|
+
*
|
|
1203
|
+
* @param params - Query parameters
|
|
1204
|
+
* @returns Query string (e.g., '?page=1&limit=20')
|
|
1205
|
+
* @private
|
|
1206
|
+
*/
|
|
1207
|
+
buildQueryString(params) {
|
|
1208
|
+
const searchParams = new URLSearchParams();
|
|
1209
|
+
for (const [key, rawValue] of Object.entries(params)) {
|
|
1210
|
+
if (rawValue === void 0 || rawValue === null) {
|
|
1211
|
+
continue;
|
|
1212
|
+
}
|
|
1213
|
+
if (Array.isArray(rawValue)) {
|
|
1214
|
+
for (const item of rawValue) {
|
|
1215
|
+
searchParams.append(key, String(item));
|
|
1216
|
+
}
|
|
1217
|
+
continue;
|
|
1218
|
+
}
|
|
1219
|
+
if (typeof rawValue === "object" && rawValue !== null && !(rawValue instanceof Date)) {
|
|
1220
|
+
const nestedObj = rawValue;
|
|
1221
|
+
for (const [nestedKey, nestedValue] of Object.entries(nestedObj)) {
|
|
1222
|
+
const nestedParamKey = `${key}[${nestedKey}]`;
|
|
1223
|
+
const valueToAppend = nestedValue instanceof Date ? nestedValue.toISOString() : String(nestedValue);
|
|
1224
|
+
searchParams.append(nestedParamKey, valueToAppend);
|
|
1225
|
+
}
|
|
1226
|
+
continue;
|
|
1227
|
+
}
|
|
1228
|
+
if (rawValue instanceof Date) {
|
|
1229
|
+
searchParams.append(key, rawValue.toISOString());
|
|
1230
|
+
continue;
|
|
1231
|
+
}
|
|
1232
|
+
searchParams.append(key, String(rawValue));
|
|
1233
|
+
}
|
|
1234
|
+
const query = searchParams.toString();
|
|
1235
|
+
return query ? `?${query}` : "";
|
|
1236
|
+
}
|
|
1237
|
+
/**
|
|
1238
|
+
* Build request headers for authentication
|
|
1239
|
+
*
|
|
1240
|
+
* @param auth - Whether to include authentication headers
|
|
1241
|
+
* @param method - HTTP method
|
|
1242
|
+
* @returns Headers object
|
|
1243
|
+
* @private
|
|
1244
|
+
*/
|
|
1245
|
+
async buildHeaders(auth, method = "GET") {
|
|
1246
|
+
const headers = {
|
|
1247
|
+
...this.config.headers,
|
|
1248
|
+
...this.adminHeaders
|
|
1249
|
+
};
|
|
1250
|
+
if (method !== "GET") {
|
|
1251
|
+
headers["Content-Type"] = "application/json";
|
|
1252
|
+
}
|
|
1253
|
+
if (auth && this.config.tokenDelivery === "json") {
|
|
1254
|
+
try {
|
|
1255
|
+
const ACCESS_TOKEN_KEY2 = "nauth_access_token";
|
|
1256
|
+
const token = await this.config.storage.getItem(ACCESS_TOKEN_KEY2);
|
|
1257
|
+
if (token) {
|
|
1258
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
1259
|
+
}
|
|
1260
|
+
} catch {
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
if (this.config.tokenDelivery === "json") {
|
|
1264
|
+
try {
|
|
1265
|
+
const deviceToken = await this.config.storage.getItem(this.config.deviceTrust.storageKey);
|
|
1266
|
+
if (deviceToken) {
|
|
1267
|
+
headers[this.config.deviceTrust.headerName] = deviceToken;
|
|
1268
|
+
}
|
|
1269
|
+
} catch {
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
const mutatingMethods = [
|
|
1273
|
+
"POST",
|
|
1274
|
+
"PUT",
|
|
1275
|
+
"PATCH",
|
|
1276
|
+
"DELETE"
|
|
1277
|
+
];
|
|
1278
|
+
if (this.config.tokenDelivery === "cookies" && hasWindow() && mutatingMethods.includes(method)) {
|
|
1279
|
+
const csrfToken = this.getCsrfToken();
|
|
1280
|
+
if (csrfToken) {
|
|
1281
|
+
headers[this.config.csrf.headerName] = csrfToken;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
return headers;
|
|
1285
|
+
}
|
|
1286
|
+
/**
|
|
1287
|
+
* Get CSRF token from cookie (browser only)
|
|
1288
|
+
*
|
|
1289
|
+
* @returns CSRF token or null
|
|
1290
|
+
* @private
|
|
1291
|
+
*/
|
|
1292
|
+
getCsrfToken() {
|
|
1293
|
+
if (!hasWindow() || typeof document === "undefined") return null;
|
|
1294
|
+
const match = document.cookie.match(
|
|
1295
|
+
new RegExp(`(^| )${this.config.csrf.cookieName}=([^;]+)`)
|
|
1296
|
+
);
|
|
1297
|
+
return match ? decodeURIComponent(match[2]) : null;
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Execute GET request
|
|
1301
|
+
*
|
|
1302
|
+
* @param path - Full URL path
|
|
1303
|
+
* @returns Response data
|
|
1304
|
+
* @private
|
|
1305
|
+
*/
|
|
1306
|
+
async get(path) {
|
|
1307
|
+
const headers = await this.buildHeaders(true, "GET");
|
|
1308
|
+
const credentials = this.config.tokenDelivery === "cookies" ? "include" : "omit";
|
|
1309
|
+
try {
|
|
1310
|
+
const response = await this.config.httpAdapter.request({
|
|
1311
|
+
method: "GET",
|
|
1312
|
+
url: path,
|
|
1313
|
+
headers,
|
|
1314
|
+
credentials
|
|
1315
|
+
});
|
|
1316
|
+
return response.data;
|
|
1317
|
+
} catch (error) {
|
|
1318
|
+
throw this.handleError(error);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Execute POST request
|
|
1323
|
+
*
|
|
1324
|
+
* @param path - Full URL path
|
|
1325
|
+
* @param body - Request body
|
|
1326
|
+
* @returns Response data
|
|
1327
|
+
* @private
|
|
1328
|
+
*/
|
|
1329
|
+
async post(path, body) {
|
|
1330
|
+
const headers = await this.buildHeaders(true, "POST");
|
|
1331
|
+
const credentials = this.config.tokenDelivery === "cookies" ? "include" : "omit";
|
|
1332
|
+
try {
|
|
1333
|
+
const response = await this.config.httpAdapter.request({
|
|
1334
|
+
method: "POST",
|
|
1335
|
+
url: path,
|
|
1336
|
+
headers,
|
|
1337
|
+
body,
|
|
1338
|
+
credentials
|
|
1339
|
+
});
|
|
1340
|
+
return response.data;
|
|
1341
|
+
} catch (error) {
|
|
1342
|
+
throw this.handleError(error);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
/**
|
|
1346
|
+
* Execute DELETE request
|
|
1347
|
+
*
|
|
1348
|
+
* @param path - Full URL path
|
|
1349
|
+
* @returns Response data
|
|
1350
|
+
* @private
|
|
1351
|
+
*/
|
|
1352
|
+
async delete(path) {
|
|
1353
|
+
const headers = await this.buildHeaders(true, "DELETE");
|
|
1354
|
+
const credentials = this.config.tokenDelivery === "cookies" ? "include" : "omit";
|
|
1355
|
+
try {
|
|
1356
|
+
const response = await this.config.httpAdapter.request({
|
|
1357
|
+
method: "DELETE",
|
|
1358
|
+
url: path,
|
|
1359
|
+
headers,
|
|
1360
|
+
credentials
|
|
1361
|
+
});
|
|
1362
|
+
return response.data;
|
|
1363
|
+
} catch (error) {
|
|
1364
|
+
throw this.handleError(error);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Handle HTTP errors and convert to NAuthClientError
|
|
1369
|
+
*
|
|
1370
|
+
* @param error - Error from HTTP adapter
|
|
1371
|
+
* @returns NAuthClientError
|
|
1372
|
+
* @private
|
|
1373
|
+
*/
|
|
1374
|
+
handleError(error) {
|
|
1375
|
+
if (error instanceof NAuthClientError) {
|
|
1376
|
+
return error;
|
|
1377
|
+
}
|
|
1378
|
+
if (error && typeof error === "object" && "response" in error) {
|
|
1379
|
+
const httpError = error;
|
|
1380
|
+
const status = httpError.response?.status ?? 500;
|
|
1381
|
+
const errorData = typeof httpError.response?.data === "object" && httpError.response.data !== null ? httpError.response.data : {};
|
|
1382
|
+
const code = typeof errorData["code"] === "string" ? errorData["code"] : "INTERNAL_ERROR" /* INTERNAL_ERROR */;
|
|
1383
|
+
const message = typeof errorData["message"] === "string" ? errorData["message"] : `Request failed with status ${status}`;
|
|
1384
|
+
return new NAuthClientError(code, message, {
|
|
1385
|
+
statusCode: status,
|
|
1386
|
+
details: errorData
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
return new NAuthClientError(
|
|
1390
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
1391
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1394
|
+
};
|
|
1395
|
+
|
|
712
1396
|
// src/core/client.ts
|
|
713
1397
|
var USER_KEY2 = "nauth_user";
|
|
714
1398
|
var CHALLENGE_KEY2 = "nauth_challenge_session";
|
|
715
1399
|
var OAUTH_STATE_KEY2 = "nauth_oauth_state";
|
|
716
|
-
var
|
|
1400
|
+
var hasWindow2 = () => typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
|
|
1401
|
+
var getOauthStorage = (mainStorage) => {
|
|
1402
|
+
if (hasWindow2() && typeof window.sessionStorage !== "undefined") {
|
|
1403
|
+
return new BrowserStorage(window.sessionStorage);
|
|
1404
|
+
}
|
|
1405
|
+
return mainStorage;
|
|
1406
|
+
};
|
|
717
1407
|
var defaultStorage = () => {
|
|
718
|
-
if (
|
|
1408
|
+
if (hasWindow2() && typeof window.localStorage !== "undefined") {
|
|
719
1409
|
return new BrowserStorage();
|
|
720
1410
|
}
|
|
721
1411
|
return new InMemoryStorage();
|
|
@@ -731,7 +1421,34 @@ var NAuthClient = class {
|
|
|
731
1421
|
__publicField(this, "tokenManager");
|
|
732
1422
|
__publicField(this, "eventEmitter");
|
|
733
1423
|
__publicField(this, "challengeRouter");
|
|
1424
|
+
__publicField(this, "oauthStorage");
|
|
734
1425
|
__publicField(this, "currentUser", null);
|
|
1426
|
+
/**
|
|
1427
|
+
* Admin operations (available if admin config provided).
|
|
1428
|
+
*
|
|
1429
|
+
* Provides admin-level user management methods:
|
|
1430
|
+
* - User CRUD operations
|
|
1431
|
+
* - Password management
|
|
1432
|
+
* - Session management
|
|
1433
|
+
* - MFA management
|
|
1434
|
+
* - Audit history
|
|
1435
|
+
*
|
|
1436
|
+
* @example
|
|
1437
|
+
* ```typescript
|
|
1438
|
+
* const client = new NAuthClient({
|
|
1439
|
+
* baseUrl: 'https://api.example.com/auth',
|
|
1440
|
+
* tokenDelivery: 'cookies',
|
|
1441
|
+
* admin: {
|
|
1442
|
+
* pathPrefix: '/admin',
|
|
1443
|
+
* },
|
|
1444
|
+
* });
|
|
1445
|
+
*
|
|
1446
|
+
* // Use admin operations
|
|
1447
|
+
* const users = await client.admin.getUsers({ page: 1 });
|
|
1448
|
+
* await client.admin.deleteUser('user-uuid');
|
|
1449
|
+
* ```
|
|
1450
|
+
*/
|
|
1451
|
+
__publicField(this, "admin");
|
|
735
1452
|
/**
|
|
736
1453
|
* Handle cross-tab storage updates.
|
|
737
1454
|
*/
|
|
@@ -749,8 +1466,12 @@ var NAuthClient = class {
|
|
|
749
1466
|
this.config = resolveConfig({ ...userConfig, storage }, defaultAdapter);
|
|
750
1467
|
this.tokenManager = new TokenManager(storage);
|
|
751
1468
|
this.eventEmitter = new EventEmitter();
|
|
752
|
-
this.
|
|
753
|
-
|
|
1469
|
+
this.oauthStorage = getOauthStorage(storage);
|
|
1470
|
+
this.challengeRouter = new ChallengeRouter(this.config, this.oauthStorage);
|
|
1471
|
+
if (this.config.admin) {
|
|
1472
|
+
this.admin = new AdminOperations(this.config);
|
|
1473
|
+
}
|
|
1474
|
+
if (hasWindow2()) {
|
|
754
1475
|
window.addEventListener("storage", this.handleStorageEvent);
|
|
755
1476
|
}
|
|
756
1477
|
}
|
|
@@ -758,7 +1479,7 @@ var NAuthClient = class {
|
|
|
758
1479
|
* Clean up resources.
|
|
759
1480
|
*/
|
|
760
1481
|
dispose() {
|
|
761
|
-
if (
|
|
1482
|
+
if (hasWindow2()) {
|
|
762
1483
|
window.removeEventListener("storage", this.handleStorageEvent);
|
|
763
1484
|
}
|
|
764
1485
|
}
|
|
@@ -1206,11 +1927,12 @@ var NAuthClient = class {
|
|
|
1206
1927
|
*/
|
|
1207
1928
|
async loginWithSocial(provider, options) {
|
|
1208
1929
|
this.eventEmitter.emit({ type: "oauth:started", data: { provider }, timestamp: Date.now() });
|
|
1209
|
-
if (
|
|
1930
|
+
if (hasWindow2()) {
|
|
1210
1931
|
const startPath = this.config.endpoints.socialRedirectStart.replace(":provider", provider);
|
|
1211
1932
|
const fullUrl = this.buildUrl(startPath);
|
|
1212
1933
|
const startUrl = new URL(fullUrl);
|
|
1213
|
-
const
|
|
1934
|
+
const redirects = this.config.redirects;
|
|
1935
|
+
const returnTo = options?.returnTo ?? redirects?.loginSuccess ?? redirects?.success ?? "/";
|
|
1214
1936
|
startUrl.searchParams.set("returnTo", returnTo);
|
|
1215
1937
|
if (options?.action === "link") {
|
|
1216
1938
|
startUrl.searchParams.set("action", "link");
|
|
@@ -1237,7 +1959,11 @@ var NAuthClient = class {
|
|
|
1237
1959
|
}
|
|
1238
1960
|
const result = await this.post(this.config.endpoints.socialExchange, { exchangeToken: token });
|
|
1239
1961
|
await this.handleAuthResponse(result);
|
|
1240
|
-
await this.
|
|
1962
|
+
const appState = await this.oauthStorage.getItem(OAUTH_STATE_KEY2);
|
|
1963
|
+
await this.challengeRouter.handleAuthResponse(result, {
|
|
1964
|
+
source: "social",
|
|
1965
|
+
appState: appState ?? void 0
|
|
1966
|
+
});
|
|
1241
1967
|
return result;
|
|
1242
1968
|
}
|
|
1243
1969
|
/**
|
|
@@ -1523,7 +2249,7 @@ var NAuthClient = class {
|
|
|
1523
2249
|
}
|
|
1524
2250
|
}
|
|
1525
2251
|
const mutatingMethods = ["POST", "PUT", "PATCH", "DELETE"];
|
|
1526
|
-
if (this.config.tokenDelivery === "cookies" &&
|
|
2252
|
+
if (this.config.tokenDelivery === "cookies" && hasWindow2() && mutatingMethods.includes(method)) {
|
|
1527
2253
|
const csrfToken = this.getCsrfToken();
|
|
1528
2254
|
if (csrfToken) {
|
|
1529
2255
|
headers[this.config.csrf.headerName] = csrfToken;
|
|
@@ -1536,7 +2262,7 @@ var NAuthClient = class {
|
|
|
1536
2262
|
* @private
|
|
1537
2263
|
*/
|
|
1538
2264
|
getCsrfToken() {
|
|
1539
|
-
if (!
|
|
2265
|
+
if (!hasWindow2() || typeof document === "undefined") return null;
|
|
1540
2266
|
const match = document.cookie.match(new RegExp(`(^| )${this.config.csrf.cookieName}=([^;]+)`));
|
|
1541
2267
|
return match ? decodeURIComponent(match[2]) : null;
|
|
1542
2268
|
}
|
|
@@ -1628,6 +2354,8 @@ var NAuthClient = class {
|
|
|
1628
2354
|
* when appState is present in the callback URL. The stored state can
|
|
1629
2355
|
* be retrieved using getLastOauthState().
|
|
1630
2356
|
*
|
|
2357
|
+
* Stores in sessionStorage (ephemeral) for better security.
|
|
2358
|
+
*
|
|
1631
2359
|
* @param appState - OAuth appState value from callback URL
|
|
1632
2360
|
*
|
|
1633
2361
|
* @example
|
|
@@ -1637,7 +2365,7 @@ var NAuthClient = class {
|
|
|
1637
2365
|
*/
|
|
1638
2366
|
async storeOauthState(appState) {
|
|
1639
2367
|
if (appState && appState.trim() !== "") {
|
|
1640
|
-
await this.
|
|
2368
|
+
await this.oauthStorage.setItem(OAUTH_STATE_KEY2, appState);
|
|
1641
2369
|
}
|
|
1642
2370
|
}
|
|
1643
2371
|
/**
|
|
@@ -1648,6 +2376,7 @@ var NAuthClient = class {
|
|
|
1648
2376
|
* applying invite codes, or tracking referral information.
|
|
1649
2377
|
*
|
|
1650
2378
|
* The state is automatically cleared after retrieval to prevent reuse.
|
|
2379
|
+
* Stored in sessionStorage (ephemeral) for better security.
|
|
1651
2380
|
*
|
|
1652
2381
|
* @returns The stored appState, or null if none exists
|
|
1653
2382
|
*
|
|
@@ -1661,9 +2390,9 @@ var NAuthClient = class {
|
|
|
1661
2390
|
* ```
|
|
1662
2391
|
*/
|
|
1663
2392
|
async getLastOauthState() {
|
|
1664
|
-
const stored = await this.
|
|
2393
|
+
const stored = await this.oauthStorage.getItem(OAUTH_STATE_KEY2);
|
|
1665
2394
|
if (stored) {
|
|
1666
|
-
await this.
|
|
2395
|
+
await this.oauthStorage.removeItem(OAUTH_STATE_KEY2);
|
|
1667
2396
|
return stored;
|
|
1668
2397
|
}
|
|
1669
2398
|
return null;
|
|
@@ -1712,6 +2441,7 @@ function isOTPChallenge(challenge) {
|
|
|
1712
2441
|
return challengeName === "VERIFY_EMAIL" /* VERIFY_EMAIL */ || challengeName === "VERIFY_PHONE" /* VERIFY_PHONE */ || challengeName === "MFA_REQUIRED" /* MFA_REQUIRED */;
|
|
1713
2442
|
}
|
|
1714
2443
|
export {
|
|
2444
|
+
AdminOperations,
|
|
1715
2445
|
AuthAuditEventType,
|
|
1716
2446
|
AuthChallenge,
|
|
1717
2447
|
BrowserStorage,
|
|
@@ -1722,6 +2452,7 @@ export {
|
|
|
1722
2452
|
NAuthClient,
|
|
1723
2453
|
NAuthClientError,
|
|
1724
2454
|
NAuthErrorCode,
|
|
2455
|
+
defaultAdminEndpoints,
|
|
1725
2456
|
defaultEndpoints,
|
|
1726
2457
|
getChallengeInstructions,
|
|
1727
2458
|
getMFAMethod,
|