@bagelink/auth 1.4.182 → 1.4.184
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 +66 -18
- package/dist/index.d.cts +18 -106
- package/dist/index.d.mts +18 -106
- package/dist/index.d.ts +18 -106
- package/dist/index.mjs +66 -17
- package/package.json +1 -1
- package/src/api.ts +1 -0
- package/src/sso.ts +94 -19
- package/src/types.ts +1 -0
- package/src/utils.ts +12 -0
package/dist/index.cjs
CHANGED
|
@@ -46,6 +46,17 @@ class EventEmitter {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
function queryParams() {
|
|
50
|
+
if (typeof window === "undefined" || !window.location?.search) {
|
|
51
|
+
return {};
|
|
52
|
+
}
|
|
53
|
+
const params = new URLSearchParams(window.location.search);
|
|
54
|
+
const result = {};
|
|
55
|
+
params.forEach((value, key) => {
|
|
56
|
+
result[key] = value;
|
|
57
|
+
});
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
49
60
|
|
|
50
61
|
class AuthApi {
|
|
51
62
|
api;
|
|
@@ -129,7 +140,8 @@ class AuthApi {
|
|
|
129
140
|
*/
|
|
130
141
|
async linkSSOProvider(data) {
|
|
131
142
|
return this.api.post(`/authentication/sso/${data.provider}/link`, {
|
|
132
|
-
code: data.code
|
|
143
|
+
code: data.code,
|
|
144
|
+
state: data.state
|
|
133
145
|
});
|
|
134
146
|
}
|
|
135
147
|
/**
|
|
@@ -463,11 +475,20 @@ function createSSOProvider(config) {
|
|
|
463
475
|
state
|
|
464
476
|
});
|
|
465
477
|
},
|
|
466
|
-
async link(code) {
|
|
478
|
+
async link(code, state) {
|
|
467
479
|
const auth = getAuthApi();
|
|
480
|
+
if (typeof sessionStorage !== "undefined" && state) {
|
|
481
|
+
const storedState = sessionStorage.getItem(getStateKey());
|
|
482
|
+
sessionStorage.removeItem(getStateKey());
|
|
483
|
+
sessionStorage.removeItem(`oauth_provider:${state}`);
|
|
484
|
+
if (storedState && storedState !== state) {
|
|
485
|
+
throw new StateMismatchError();
|
|
486
|
+
}
|
|
487
|
+
}
|
|
468
488
|
await auth.linkSSOProvider({
|
|
469
489
|
provider: config.id,
|
|
470
|
-
code
|
|
490
|
+
code,
|
|
491
|
+
state
|
|
471
492
|
});
|
|
472
493
|
},
|
|
473
494
|
async unlink() {
|
|
@@ -490,7 +511,7 @@ function createSSOProvider(config) {
|
|
|
490
511
|
// Default, can be overridden per provider
|
|
491
512
|
};
|
|
492
513
|
}
|
|
493
|
-
const
|
|
514
|
+
const ssoProviders = {
|
|
494
515
|
/**
|
|
495
516
|
* Google OAuth Provider
|
|
496
517
|
* https://developers.google.com/identity/protocols/oauth2
|
|
@@ -590,31 +611,59 @@ const sso = {
|
|
|
590
611
|
}
|
|
591
612
|
})
|
|
592
613
|
};
|
|
593
|
-
const
|
|
614
|
+
const sso = {
|
|
615
|
+
// All provider instances
|
|
616
|
+
...ssoProviders,
|
|
617
|
+
/**
|
|
618
|
+
* Handle OAuth callback from URL automatically
|
|
619
|
+
* Detects provider from state and completes login
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* // On /auth/callback page
|
|
623
|
+
* const result = await sso.handleCallback()
|
|
624
|
+
*/
|
|
625
|
+
handleCallback: handleOAuthCallback,
|
|
626
|
+
/**
|
|
627
|
+
* Handle OAuth link callback from URL automatically
|
|
628
|
+
* Detects provider from state and completes linking
|
|
629
|
+
*
|
|
630
|
+
* @example
|
|
631
|
+
* // On /settings/link-callback page
|
|
632
|
+
* await sso.handleLinkCallback()
|
|
633
|
+
*/
|
|
634
|
+
handleLinkCallback: handleOAuthLinkCallback
|
|
635
|
+
};
|
|
636
|
+
const ssoProvidersList = Object.values(ssoProviders);
|
|
594
637
|
function getSSOProvider(provider) {
|
|
595
|
-
return
|
|
638
|
+
return ssoProviders[provider];
|
|
596
639
|
}
|
|
597
640
|
function getAllSSOProviders() {
|
|
598
|
-
return
|
|
641
|
+
return ssoProvidersList;
|
|
599
642
|
}
|
|
600
643
|
function isSupportedProvider(provider) {
|
|
601
|
-
return provider in
|
|
644
|
+
return provider in ssoProviders;
|
|
602
645
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
646
|
+
function handleOAuthCallback() {
|
|
647
|
+
const { code, state } = queryParams();
|
|
648
|
+
if (!code || !state) {
|
|
649
|
+
return Promise.resolve(null);
|
|
606
650
|
}
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
651
|
+
const provider = sessionStorage.getItem(`oauth_provider:${state}`);
|
|
652
|
+
if (!provider || !isSupportedProvider(provider)) {
|
|
653
|
+
throw new Error("Unable to determine OAuth provider. State may have expired.");
|
|
654
|
+
}
|
|
655
|
+
return ssoProviders[provider].callback(code, state);
|
|
656
|
+
}
|
|
657
|
+
function handleOAuthLinkCallback() {
|
|
658
|
+
const { code, state } = queryParams();
|
|
610
659
|
if (!code || !state) {
|
|
611
|
-
|
|
660
|
+
throw new Error("Missing code or state parameter");
|
|
612
661
|
}
|
|
613
662
|
const provider = sessionStorage.getItem(`oauth_provider:${state}`);
|
|
614
663
|
if (!provider || !isSupportedProvider(provider)) {
|
|
615
664
|
throw new Error("Unable to determine OAuth provider. State may have expired.");
|
|
616
665
|
}
|
|
617
|
-
return
|
|
666
|
+
return ssoProviders[provider].link(code, state);
|
|
618
667
|
}
|
|
619
668
|
|
|
620
669
|
var AuthState = /* @__PURE__ */ ((AuthState2) => {
|
|
@@ -954,10 +1003,9 @@ exports.StateMismatchError = StateMismatchError;
|
|
|
954
1003
|
exports.accountToUser = accountToUser;
|
|
955
1004
|
exports.getAllSSOProviders = getAllSSOProviders;
|
|
956
1005
|
exports.getSSOProvider = getSSOProvider;
|
|
957
|
-
exports.handleOAuthCallback = handleOAuthCallback;
|
|
958
1006
|
exports.initAuth = initAuth;
|
|
959
1007
|
exports.isSupportedProvider = isSupportedProvider;
|
|
960
1008
|
exports.setAuthContext = setAuthContext;
|
|
961
1009
|
exports.sso = sso;
|
|
962
|
-
exports.
|
|
1010
|
+
exports.ssoProvidersList = ssoProvidersList;
|
|
963
1011
|
exports.useAuth = useAuth;
|
package/dist/index.d.cts
CHANGED
|
@@ -197,6 +197,7 @@ interface SSOCallbackRequest {
|
|
|
197
197
|
interface SSOLinkRequest {
|
|
198
198
|
provider: SSOProvider;
|
|
199
199
|
code: string;
|
|
200
|
+
state: string;
|
|
200
201
|
}
|
|
201
202
|
interface SSOUnlinkRequest {
|
|
202
203
|
provider: SSOProvider;
|
|
@@ -459,8 +460,9 @@ interface SSOProviderInstance extends SSOProviderConfig {
|
|
|
459
460
|
callback: (code: string, state?: string) => Promise<AuthenticationResponse>;
|
|
460
461
|
/**
|
|
461
462
|
* Link this provider to the current logged-in user
|
|
463
|
+
* Call this after OAuth redirect completes on link callback page
|
|
462
464
|
*/
|
|
463
|
-
link: (code: string) => Promise<void>;
|
|
465
|
+
link: (code: string, state?: string) => Promise<void>;
|
|
464
466
|
/**
|
|
465
467
|
* Unlink this provider from the current user
|
|
466
468
|
*/
|
|
@@ -476,86 +478,26 @@ interface SSOProviderInstance extends SSOProviderConfig {
|
|
|
476
478
|
supportsPopup?: boolean;
|
|
477
479
|
}
|
|
478
480
|
/**
|
|
479
|
-
* SSO
|
|
481
|
+
* SSO object type with providers and helper methods
|
|
480
482
|
*/
|
|
481
|
-
|
|
482
|
-
/**
|
|
483
|
-
* Google OAuth Provider
|
|
484
|
-
* https://developers.google.com/identity/protocols/oauth2
|
|
485
|
-
*/
|
|
483
|
+
interface SSOObject {
|
|
486
484
|
google: SSOProviderInstance;
|
|
487
|
-
/**
|
|
488
|
-
* Microsoft OAuth Provider (Azure AD / Microsoft Entra ID)
|
|
489
|
-
* https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
|
|
490
|
-
*/
|
|
491
485
|
microsoft: SSOProviderInstance;
|
|
492
|
-
/**
|
|
493
|
-
* GitHub OAuth Provider
|
|
494
|
-
* https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps
|
|
495
|
-
*/
|
|
496
486
|
github: SSOProviderInstance;
|
|
497
|
-
/**
|
|
498
|
-
* Okta OAuth Provider
|
|
499
|
-
* https://developer.okta.com/docs/guides/implement-grant-type/authcode/main/
|
|
500
|
-
*/
|
|
501
487
|
okta: SSOProviderInstance;
|
|
502
|
-
|
|
503
|
-
* Apple Sign In Provider
|
|
504
|
-
* https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api
|
|
505
|
-
* Note: Apple works best with redirect flow on web
|
|
506
|
-
*/
|
|
507
|
-
apple: {
|
|
508
|
-
supportsPopup: boolean;
|
|
509
|
-
popup(options?: OAuthFlowOptions): Promise<any>;
|
|
510
|
-
/**
|
|
511
|
-
* Initiate OAuth flow with redirect (most common)
|
|
512
|
-
* User is redirected to provider's authorization page
|
|
513
|
-
*/
|
|
514
|
-
redirect: (options?: OAuthFlowOptions) => Promise<void>;
|
|
515
|
-
/**
|
|
516
|
-
* Complete OAuth flow after callback
|
|
517
|
-
* Call this on your callback page
|
|
518
|
-
*/
|
|
519
|
-
callback: (code: string, state?: string) => Promise<AuthenticationResponse>;
|
|
520
|
-
/**
|
|
521
|
-
* Link this provider to the current logged-in user
|
|
522
|
-
*/
|
|
523
|
-
link: (code: string) => Promise<void>;
|
|
524
|
-
/**
|
|
525
|
-
* Unlink this provider from the current user
|
|
526
|
-
*/
|
|
527
|
-
unlink: () => Promise<void>;
|
|
528
|
-
/**
|
|
529
|
-
* Get authorization URL without redirecting
|
|
530
|
-
*/
|
|
531
|
-
getAuthUrl: (options?: OAuthFlowOptions) => Promise<string>;
|
|
532
|
-
/** Provider identifier */
|
|
533
|
-
id: SSOProvider;
|
|
534
|
-
/** Display name */
|
|
535
|
-
name: string;
|
|
536
|
-
/** Brand color (hex) */
|
|
537
|
-
color: string;
|
|
538
|
-
/** Icon identifier (for UI libraries) */
|
|
539
|
-
icon: string;
|
|
540
|
-
/** Default OAuth scopes */
|
|
541
|
-
defaultScopes: string[];
|
|
542
|
-
/** Provider-specific metadata */
|
|
543
|
-
metadata?: {
|
|
544
|
-
authDomain?: string;
|
|
545
|
-
buttonText?: string;
|
|
546
|
-
[key: string]: any;
|
|
547
|
-
};
|
|
548
|
-
};
|
|
549
|
-
/**
|
|
550
|
-
* Facebook OAuth Provider
|
|
551
|
-
* https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow
|
|
552
|
-
*/
|
|
488
|
+
apple: SSOProviderInstance;
|
|
553
489
|
facebook: SSOProviderInstance;
|
|
554
|
-
|
|
490
|
+
handleCallback: () => Promise<AuthenticationResponse | null>;
|
|
491
|
+
handleLinkCallback: () => Promise<void>;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* SSO object with providers and global helper methods
|
|
495
|
+
*/
|
|
496
|
+
declare const sso: SSOObject;
|
|
555
497
|
/**
|
|
556
|
-
* Array of all SSO
|
|
498
|
+
* Array of all SSO provider instances
|
|
557
499
|
*/
|
|
558
|
-
declare const
|
|
500
|
+
declare const ssoProvidersList: readonly SSOProviderInstance[];
|
|
559
501
|
/**
|
|
560
502
|
* Get SSO provider instance by ID
|
|
561
503
|
*/
|
|
@@ -568,11 +510,6 @@ declare function getAllSSOProviders(): readonly SSOProviderInstance[];
|
|
|
568
510
|
* Check if a provider is supported
|
|
569
511
|
*/
|
|
570
512
|
declare function isSupportedProvider(provider: string): provider is SSOProvider;
|
|
571
|
-
/**
|
|
572
|
-
* Handle OAuth callback from URL
|
|
573
|
-
* Call this on your callback page to automatically detect and process the callback
|
|
574
|
-
*/
|
|
575
|
-
declare function handleOAuthCallback(): Promise<AuthenticationResponse | null>;
|
|
576
513
|
|
|
577
514
|
declare function initAuth({ baseURL, }: {
|
|
578
515
|
baseURL: string;
|
|
@@ -643,32 +580,7 @@ declare function useAuth(): {
|
|
|
643
580
|
metadata?: Record<string, any> | undefined;
|
|
644
581
|
} | undefined;
|
|
645
582
|
} | null>;
|
|
646
|
-
sso:
|
|
647
|
-
google: SSOProviderInstance;
|
|
648
|
-
microsoft: SSOProviderInstance;
|
|
649
|
-
github: SSOProviderInstance;
|
|
650
|
-
okta: SSOProviderInstance;
|
|
651
|
-
apple: {
|
|
652
|
-
supportsPopup: boolean;
|
|
653
|
-
popup(options?: OAuthFlowOptions): Promise<any>;
|
|
654
|
-
redirect: (options?: OAuthFlowOptions) => Promise<void>;
|
|
655
|
-
callback: (code: string, state?: string) => Promise<AuthenticationResponse>;
|
|
656
|
-
link: (code: string) => Promise<void>;
|
|
657
|
-
unlink: () => Promise<void>;
|
|
658
|
-
getAuthUrl: (options?: OAuthFlowOptions) => Promise<string>;
|
|
659
|
-
id: SSOProvider;
|
|
660
|
-
name: string;
|
|
661
|
-
color: string;
|
|
662
|
-
icon: string;
|
|
663
|
-
defaultScopes: string[];
|
|
664
|
-
metadata?: {
|
|
665
|
-
authDomain?: string;
|
|
666
|
-
buttonText?: string;
|
|
667
|
-
[key: string]: any;
|
|
668
|
-
};
|
|
669
|
-
};
|
|
670
|
-
facebook: SSOProviderInstance;
|
|
671
|
-
};
|
|
583
|
+
sso: SSOObject;
|
|
672
584
|
getFullName: () => string;
|
|
673
585
|
getIsLoggedIn: () => boolean;
|
|
674
586
|
getEmail: () => string;
|
|
@@ -704,5 +616,5 @@ declare function useAuth(): {
|
|
|
704
616
|
revokeAllSessions: (accountId?: string) => Promise<void>;
|
|
705
617
|
};
|
|
706
618
|
|
|
707
|
-
export { AuthApi, AuthState, PopupBlockedError, PopupClosedError, PopupTimeoutError, SSOError, StateMismatchError, accountToUser, getAllSSOProviders, getSSOProvider,
|
|
708
|
-
export type { AccountInfo, ActivateAccountResponse, AuthEventHandler, AuthEventMap, AuthMethodInfo, AuthStatusResponse, AuthenticationAccount, AuthenticationAccountType, AuthenticationMethodType, AuthenticationResponse, AvailableMethodsResponse, ChangePasswordRequest, ChangePasswordResponse, CleanupSessionsResponse, DeactivateAccountResponse, DeleteAccountResponse, DeleteAllSessionsResponse, DeleteMeResponse, DeleteSessionResponse, EntityInfo, ForgotPasswordRequest, ForgotPasswordResponse, GetAccountResponse, GetMeResponse, GetMethodsResponse, GetSessionsResponse, LoginResponse, LogoutResponse, MessageResponse, NewUser, OAuthFlowOptions, OTPMetadata, PasswordLoginRequest, PersonInfo, PopupResult, RefreshSessionResponse, RegisterRequest, RegisterResponse, ResetPasswordRequest, ResetPasswordResponse, SSOCallbackRequest, SSOCallbackResponse, SSOInitiateRequest, SSOInitiateResponse, SSOLinkRequest, SSOLinkResponse, SSOMetadata, SSOProvider, SSOProviderConfig, SSOProviderInstance, SSOUnlinkRequest, SSOUnlinkResponse, SendVerificationRequest, SendVerificationResponse, SessionInfo, SessionListResponse, UpdateAccountRequest, UpdateAccountResponse, UpdateMeResponse, UpdatePasswordForm, User, VerifyEmailRequest, VerifyEmailResponse, VerifyResetTokenResponse };
|
|
619
|
+
export { AuthApi, AuthState, PopupBlockedError, PopupClosedError, PopupTimeoutError, SSOError, StateMismatchError, accountToUser, getAllSSOProviders, getSSOProvider, initAuth, isSupportedProvider, setAuthContext, sso, ssoProvidersList, useAuth };
|
|
620
|
+
export type { AccountInfo, ActivateAccountResponse, AuthEventHandler, AuthEventMap, AuthMethodInfo, AuthStatusResponse, AuthenticationAccount, AuthenticationAccountType, AuthenticationMethodType, AuthenticationResponse, AvailableMethodsResponse, ChangePasswordRequest, ChangePasswordResponse, CleanupSessionsResponse, DeactivateAccountResponse, DeleteAccountResponse, DeleteAllSessionsResponse, DeleteMeResponse, DeleteSessionResponse, EntityInfo, ForgotPasswordRequest, ForgotPasswordResponse, GetAccountResponse, GetMeResponse, GetMethodsResponse, GetSessionsResponse, LoginResponse, LogoutResponse, MessageResponse, NewUser, OAuthFlowOptions, OTPMetadata, PasswordLoginRequest, PersonInfo, PopupResult, RefreshSessionResponse, RegisterRequest, RegisterResponse, ResetPasswordRequest, ResetPasswordResponse, SSOCallbackRequest, SSOCallbackResponse, SSOInitiateRequest, SSOInitiateResponse, SSOLinkRequest, SSOLinkResponse, SSOMetadata, SSOObject, SSOProvider, SSOProviderConfig, SSOProviderInstance, SSOUnlinkRequest, SSOUnlinkResponse, SendVerificationRequest, SendVerificationResponse, SessionInfo, SessionListResponse, UpdateAccountRequest, UpdateAccountResponse, UpdateMeResponse, UpdatePasswordForm, User, VerifyEmailRequest, VerifyEmailResponse, VerifyResetTokenResponse };
|
package/dist/index.d.mts
CHANGED
|
@@ -197,6 +197,7 @@ interface SSOCallbackRequest {
|
|
|
197
197
|
interface SSOLinkRequest {
|
|
198
198
|
provider: SSOProvider;
|
|
199
199
|
code: string;
|
|
200
|
+
state: string;
|
|
200
201
|
}
|
|
201
202
|
interface SSOUnlinkRequest {
|
|
202
203
|
provider: SSOProvider;
|
|
@@ -459,8 +460,9 @@ interface SSOProviderInstance extends SSOProviderConfig {
|
|
|
459
460
|
callback: (code: string, state?: string) => Promise<AuthenticationResponse>;
|
|
460
461
|
/**
|
|
461
462
|
* Link this provider to the current logged-in user
|
|
463
|
+
* Call this after OAuth redirect completes on link callback page
|
|
462
464
|
*/
|
|
463
|
-
link: (code: string) => Promise<void>;
|
|
465
|
+
link: (code: string, state?: string) => Promise<void>;
|
|
464
466
|
/**
|
|
465
467
|
* Unlink this provider from the current user
|
|
466
468
|
*/
|
|
@@ -476,86 +478,26 @@ interface SSOProviderInstance extends SSOProviderConfig {
|
|
|
476
478
|
supportsPopup?: boolean;
|
|
477
479
|
}
|
|
478
480
|
/**
|
|
479
|
-
* SSO
|
|
481
|
+
* SSO object type with providers and helper methods
|
|
480
482
|
*/
|
|
481
|
-
|
|
482
|
-
/**
|
|
483
|
-
* Google OAuth Provider
|
|
484
|
-
* https://developers.google.com/identity/protocols/oauth2
|
|
485
|
-
*/
|
|
483
|
+
interface SSOObject {
|
|
486
484
|
google: SSOProviderInstance;
|
|
487
|
-
/**
|
|
488
|
-
* Microsoft OAuth Provider (Azure AD / Microsoft Entra ID)
|
|
489
|
-
* https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
|
|
490
|
-
*/
|
|
491
485
|
microsoft: SSOProviderInstance;
|
|
492
|
-
/**
|
|
493
|
-
* GitHub OAuth Provider
|
|
494
|
-
* https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps
|
|
495
|
-
*/
|
|
496
486
|
github: SSOProviderInstance;
|
|
497
|
-
/**
|
|
498
|
-
* Okta OAuth Provider
|
|
499
|
-
* https://developer.okta.com/docs/guides/implement-grant-type/authcode/main/
|
|
500
|
-
*/
|
|
501
487
|
okta: SSOProviderInstance;
|
|
502
|
-
|
|
503
|
-
* Apple Sign In Provider
|
|
504
|
-
* https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api
|
|
505
|
-
* Note: Apple works best with redirect flow on web
|
|
506
|
-
*/
|
|
507
|
-
apple: {
|
|
508
|
-
supportsPopup: boolean;
|
|
509
|
-
popup(options?: OAuthFlowOptions): Promise<any>;
|
|
510
|
-
/**
|
|
511
|
-
* Initiate OAuth flow with redirect (most common)
|
|
512
|
-
* User is redirected to provider's authorization page
|
|
513
|
-
*/
|
|
514
|
-
redirect: (options?: OAuthFlowOptions) => Promise<void>;
|
|
515
|
-
/**
|
|
516
|
-
* Complete OAuth flow after callback
|
|
517
|
-
* Call this on your callback page
|
|
518
|
-
*/
|
|
519
|
-
callback: (code: string, state?: string) => Promise<AuthenticationResponse>;
|
|
520
|
-
/**
|
|
521
|
-
* Link this provider to the current logged-in user
|
|
522
|
-
*/
|
|
523
|
-
link: (code: string) => Promise<void>;
|
|
524
|
-
/**
|
|
525
|
-
* Unlink this provider from the current user
|
|
526
|
-
*/
|
|
527
|
-
unlink: () => Promise<void>;
|
|
528
|
-
/**
|
|
529
|
-
* Get authorization URL without redirecting
|
|
530
|
-
*/
|
|
531
|
-
getAuthUrl: (options?: OAuthFlowOptions) => Promise<string>;
|
|
532
|
-
/** Provider identifier */
|
|
533
|
-
id: SSOProvider;
|
|
534
|
-
/** Display name */
|
|
535
|
-
name: string;
|
|
536
|
-
/** Brand color (hex) */
|
|
537
|
-
color: string;
|
|
538
|
-
/** Icon identifier (for UI libraries) */
|
|
539
|
-
icon: string;
|
|
540
|
-
/** Default OAuth scopes */
|
|
541
|
-
defaultScopes: string[];
|
|
542
|
-
/** Provider-specific metadata */
|
|
543
|
-
metadata?: {
|
|
544
|
-
authDomain?: string;
|
|
545
|
-
buttonText?: string;
|
|
546
|
-
[key: string]: any;
|
|
547
|
-
};
|
|
548
|
-
};
|
|
549
|
-
/**
|
|
550
|
-
* Facebook OAuth Provider
|
|
551
|
-
* https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow
|
|
552
|
-
*/
|
|
488
|
+
apple: SSOProviderInstance;
|
|
553
489
|
facebook: SSOProviderInstance;
|
|
554
|
-
|
|
490
|
+
handleCallback: () => Promise<AuthenticationResponse | null>;
|
|
491
|
+
handleLinkCallback: () => Promise<void>;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* SSO object with providers and global helper methods
|
|
495
|
+
*/
|
|
496
|
+
declare const sso: SSOObject;
|
|
555
497
|
/**
|
|
556
|
-
* Array of all SSO
|
|
498
|
+
* Array of all SSO provider instances
|
|
557
499
|
*/
|
|
558
|
-
declare const
|
|
500
|
+
declare const ssoProvidersList: readonly SSOProviderInstance[];
|
|
559
501
|
/**
|
|
560
502
|
* Get SSO provider instance by ID
|
|
561
503
|
*/
|
|
@@ -568,11 +510,6 @@ declare function getAllSSOProviders(): readonly SSOProviderInstance[];
|
|
|
568
510
|
* Check if a provider is supported
|
|
569
511
|
*/
|
|
570
512
|
declare function isSupportedProvider(provider: string): provider is SSOProvider;
|
|
571
|
-
/**
|
|
572
|
-
* Handle OAuth callback from URL
|
|
573
|
-
* Call this on your callback page to automatically detect and process the callback
|
|
574
|
-
*/
|
|
575
|
-
declare function handleOAuthCallback(): Promise<AuthenticationResponse | null>;
|
|
576
513
|
|
|
577
514
|
declare function initAuth({ baseURL, }: {
|
|
578
515
|
baseURL: string;
|
|
@@ -643,32 +580,7 @@ declare function useAuth(): {
|
|
|
643
580
|
metadata?: Record<string, any> | undefined;
|
|
644
581
|
} | undefined;
|
|
645
582
|
} | null>;
|
|
646
|
-
sso:
|
|
647
|
-
google: SSOProviderInstance;
|
|
648
|
-
microsoft: SSOProviderInstance;
|
|
649
|
-
github: SSOProviderInstance;
|
|
650
|
-
okta: SSOProviderInstance;
|
|
651
|
-
apple: {
|
|
652
|
-
supportsPopup: boolean;
|
|
653
|
-
popup(options?: OAuthFlowOptions): Promise<any>;
|
|
654
|
-
redirect: (options?: OAuthFlowOptions) => Promise<void>;
|
|
655
|
-
callback: (code: string, state?: string) => Promise<AuthenticationResponse>;
|
|
656
|
-
link: (code: string) => Promise<void>;
|
|
657
|
-
unlink: () => Promise<void>;
|
|
658
|
-
getAuthUrl: (options?: OAuthFlowOptions) => Promise<string>;
|
|
659
|
-
id: SSOProvider;
|
|
660
|
-
name: string;
|
|
661
|
-
color: string;
|
|
662
|
-
icon: string;
|
|
663
|
-
defaultScopes: string[];
|
|
664
|
-
metadata?: {
|
|
665
|
-
authDomain?: string;
|
|
666
|
-
buttonText?: string;
|
|
667
|
-
[key: string]: any;
|
|
668
|
-
};
|
|
669
|
-
};
|
|
670
|
-
facebook: SSOProviderInstance;
|
|
671
|
-
};
|
|
583
|
+
sso: SSOObject;
|
|
672
584
|
getFullName: () => string;
|
|
673
585
|
getIsLoggedIn: () => boolean;
|
|
674
586
|
getEmail: () => string;
|
|
@@ -704,5 +616,5 @@ declare function useAuth(): {
|
|
|
704
616
|
revokeAllSessions: (accountId?: string) => Promise<void>;
|
|
705
617
|
};
|
|
706
618
|
|
|
707
|
-
export { AuthApi, AuthState, PopupBlockedError, PopupClosedError, PopupTimeoutError, SSOError, StateMismatchError, accountToUser, getAllSSOProviders, getSSOProvider,
|
|
708
|
-
export type { AccountInfo, ActivateAccountResponse, AuthEventHandler, AuthEventMap, AuthMethodInfo, AuthStatusResponse, AuthenticationAccount, AuthenticationAccountType, AuthenticationMethodType, AuthenticationResponse, AvailableMethodsResponse, ChangePasswordRequest, ChangePasswordResponse, CleanupSessionsResponse, DeactivateAccountResponse, DeleteAccountResponse, DeleteAllSessionsResponse, DeleteMeResponse, DeleteSessionResponse, EntityInfo, ForgotPasswordRequest, ForgotPasswordResponse, GetAccountResponse, GetMeResponse, GetMethodsResponse, GetSessionsResponse, LoginResponse, LogoutResponse, MessageResponse, NewUser, OAuthFlowOptions, OTPMetadata, PasswordLoginRequest, PersonInfo, PopupResult, RefreshSessionResponse, RegisterRequest, RegisterResponse, ResetPasswordRequest, ResetPasswordResponse, SSOCallbackRequest, SSOCallbackResponse, SSOInitiateRequest, SSOInitiateResponse, SSOLinkRequest, SSOLinkResponse, SSOMetadata, SSOProvider, SSOProviderConfig, SSOProviderInstance, SSOUnlinkRequest, SSOUnlinkResponse, SendVerificationRequest, SendVerificationResponse, SessionInfo, SessionListResponse, UpdateAccountRequest, UpdateAccountResponse, UpdateMeResponse, UpdatePasswordForm, User, VerifyEmailRequest, VerifyEmailResponse, VerifyResetTokenResponse };
|
|
619
|
+
export { AuthApi, AuthState, PopupBlockedError, PopupClosedError, PopupTimeoutError, SSOError, StateMismatchError, accountToUser, getAllSSOProviders, getSSOProvider, initAuth, isSupportedProvider, setAuthContext, sso, ssoProvidersList, useAuth };
|
|
620
|
+
export type { AccountInfo, ActivateAccountResponse, AuthEventHandler, AuthEventMap, AuthMethodInfo, AuthStatusResponse, AuthenticationAccount, AuthenticationAccountType, AuthenticationMethodType, AuthenticationResponse, AvailableMethodsResponse, ChangePasswordRequest, ChangePasswordResponse, CleanupSessionsResponse, DeactivateAccountResponse, DeleteAccountResponse, DeleteAllSessionsResponse, DeleteMeResponse, DeleteSessionResponse, EntityInfo, ForgotPasswordRequest, ForgotPasswordResponse, GetAccountResponse, GetMeResponse, GetMethodsResponse, GetSessionsResponse, LoginResponse, LogoutResponse, MessageResponse, NewUser, OAuthFlowOptions, OTPMetadata, PasswordLoginRequest, PersonInfo, PopupResult, RefreshSessionResponse, RegisterRequest, RegisterResponse, ResetPasswordRequest, ResetPasswordResponse, SSOCallbackRequest, SSOCallbackResponse, SSOInitiateRequest, SSOInitiateResponse, SSOLinkRequest, SSOLinkResponse, SSOMetadata, SSOObject, SSOProvider, SSOProviderConfig, SSOProviderInstance, SSOUnlinkRequest, SSOUnlinkResponse, SendVerificationRequest, SendVerificationResponse, SessionInfo, SessionListResponse, UpdateAccountRequest, UpdateAccountResponse, UpdateMeResponse, UpdatePasswordForm, User, VerifyEmailRequest, VerifyEmailResponse, VerifyResetTokenResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -197,6 +197,7 @@ interface SSOCallbackRequest {
|
|
|
197
197
|
interface SSOLinkRequest {
|
|
198
198
|
provider: SSOProvider;
|
|
199
199
|
code: string;
|
|
200
|
+
state: string;
|
|
200
201
|
}
|
|
201
202
|
interface SSOUnlinkRequest {
|
|
202
203
|
provider: SSOProvider;
|
|
@@ -459,8 +460,9 @@ interface SSOProviderInstance extends SSOProviderConfig {
|
|
|
459
460
|
callback: (code: string, state?: string) => Promise<AuthenticationResponse>;
|
|
460
461
|
/**
|
|
461
462
|
* Link this provider to the current logged-in user
|
|
463
|
+
* Call this after OAuth redirect completes on link callback page
|
|
462
464
|
*/
|
|
463
|
-
link: (code: string) => Promise<void>;
|
|
465
|
+
link: (code: string, state?: string) => Promise<void>;
|
|
464
466
|
/**
|
|
465
467
|
* Unlink this provider from the current user
|
|
466
468
|
*/
|
|
@@ -476,86 +478,26 @@ interface SSOProviderInstance extends SSOProviderConfig {
|
|
|
476
478
|
supportsPopup?: boolean;
|
|
477
479
|
}
|
|
478
480
|
/**
|
|
479
|
-
* SSO
|
|
481
|
+
* SSO object type with providers and helper methods
|
|
480
482
|
*/
|
|
481
|
-
|
|
482
|
-
/**
|
|
483
|
-
* Google OAuth Provider
|
|
484
|
-
* https://developers.google.com/identity/protocols/oauth2
|
|
485
|
-
*/
|
|
483
|
+
interface SSOObject {
|
|
486
484
|
google: SSOProviderInstance;
|
|
487
|
-
/**
|
|
488
|
-
* Microsoft OAuth Provider (Azure AD / Microsoft Entra ID)
|
|
489
|
-
* https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
|
|
490
|
-
*/
|
|
491
485
|
microsoft: SSOProviderInstance;
|
|
492
|
-
/**
|
|
493
|
-
* GitHub OAuth Provider
|
|
494
|
-
* https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps
|
|
495
|
-
*/
|
|
496
486
|
github: SSOProviderInstance;
|
|
497
|
-
/**
|
|
498
|
-
* Okta OAuth Provider
|
|
499
|
-
* https://developer.okta.com/docs/guides/implement-grant-type/authcode/main/
|
|
500
|
-
*/
|
|
501
487
|
okta: SSOProviderInstance;
|
|
502
|
-
|
|
503
|
-
* Apple Sign In Provider
|
|
504
|
-
* https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api
|
|
505
|
-
* Note: Apple works best with redirect flow on web
|
|
506
|
-
*/
|
|
507
|
-
apple: {
|
|
508
|
-
supportsPopup: boolean;
|
|
509
|
-
popup(options?: OAuthFlowOptions): Promise<any>;
|
|
510
|
-
/**
|
|
511
|
-
* Initiate OAuth flow with redirect (most common)
|
|
512
|
-
* User is redirected to provider's authorization page
|
|
513
|
-
*/
|
|
514
|
-
redirect: (options?: OAuthFlowOptions) => Promise<void>;
|
|
515
|
-
/**
|
|
516
|
-
* Complete OAuth flow after callback
|
|
517
|
-
* Call this on your callback page
|
|
518
|
-
*/
|
|
519
|
-
callback: (code: string, state?: string) => Promise<AuthenticationResponse>;
|
|
520
|
-
/**
|
|
521
|
-
* Link this provider to the current logged-in user
|
|
522
|
-
*/
|
|
523
|
-
link: (code: string) => Promise<void>;
|
|
524
|
-
/**
|
|
525
|
-
* Unlink this provider from the current user
|
|
526
|
-
*/
|
|
527
|
-
unlink: () => Promise<void>;
|
|
528
|
-
/**
|
|
529
|
-
* Get authorization URL without redirecting
|
|
530
|
-
*/
|
|
531
|
-
getAuthUrl: (options?: OAuthFlowOptions) => Promise<string>;
|
|
532
|
-
/** Provider identifier */
|
|
533
|
-
id: SSOProvider;
|
|
534
|
-
/** Display name */
|
|
535
|
-
name: string;
|
|
536
|
-
/** Brand color (hex) */
|
|
537
|
-
color: string;
|
|
538
|
-
/** Icon identifier (for UI libraries) */
|
|
539
|
-
icon: string;
|
|
540
|
-
/** Default OAuth scopes */
|
|
541
|
-
defaultScopes: string[];
|
|
542
|
-
/** Provider-specific metadata */
|
|
543
|
-
metadata?: {
|
|
544
|
-
authDomain?: string;
|
|
545
|
-
buttonText?: string;
|
|
546
|
-
[key: string]: any;
|
|
547
|
-
};
|
|
548
|
-
};
|
|
549
|
-
/**
|
|
550
|
-
* Facebook OAuth Provider
|
|
551
|
-
* https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow
|
|
552
|
-
*/
|
|
488
|
+
apple: SSOProviderInstance;
|
|
553
489
|
facebook: SSOProviderInstance;
|
|
554
|
-
|
|
490
|
+
handleCallback: () => Promise<AuthenticationResponse | null>;
|
|
491
|
+
handleLinkCallback: () => Promise<void>;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* SSO object with providers and global helper methods
|
|
495
|
+
*/
|
|
496
|
+
declare const sso: SSOObject;
|
|
555
497
|
/**
|
|
556
|
-
* Array of all SSO
|
|
498
|
+
* Array of all SSO provider instances
|
|
557
499
|
*/
|
|
558
|
-
declare const
|
|
500
|
+
declare const ssoProvidersList: readonly SSOProviderInstance[];
|
|
559
501
|
/**
|
|
560
502
|
* Get SSO provider instance by ID
|
|
561
503
|
*/
|
|
@@ -568,11 +510,6 @@ declare function getAllSSOProviders(): readonly SSOProviderInstance[];
|
|
|
568
510
|
* Check if a provider is supported
|
|
569
511
|
*/
|
|
570
512
|
declare function isSupportedProvider(provider: string): provider is SSOProvider;
|
|
571
|
-
/**
|
|
572
|
-
* Handle OAuth callback from URL
|
|
573
|
-
* Call this on your callback page to automatically detect and process the callback
|
|
574
|
-
*/
|
|
575
|
-
declare function handleOAuthCallback(): Promise<AuthenticationResponse | null>;
|
|
576
513
|
|
|
577
514
|
declare function initAuth({ baseURL, }: {
|
|
578
515
|
baseURL: string;
|
|
@@ -643,32 +580,7 @@ declare function useAuth(): {
|
|
|
643
580
|
metadata?: Record<string, any> | undefined;
|
|
644
581
|
} | undefined;
|
|
645
582
|
} | null>;
|
|
646
|
-
sso:
|
|
647
|
-
google: SSOProviderInstance;
|
|
648
|
-
microsoft: SSOProviderInstance;
|
|
649
|
-
github: SSOProviderInstance;
|
|
650
|
-
okta: SSOProviderInstance;
|
|
651
|
-
apple: {
|
|
652
|
-
supportsPopup: boolean;
|
|
653
|
-
popup(options?: OAuthFlowOptions): Promise<any>;
|
|
654
|
-
redirect: (options?: OAuthFlowOptions) => Promise<void>;
|
|
655
|
-
callback: (code: string, state?: string) => Promise<AuthenticationResponse>;
|
|
656
|
-
link: (code: string) => Promise<void>;
|
|
657
|
-
unlink: () => Promise<void>;
|
|
658
|
-
getAuthUrl: (options?: OAuthFlowOptions) => Promise<string>;
|
|
659
|
-
id: SSOProvider;
|
|
660
|
-
name: string;
|
|
661
|
-
color: string;
|
|
662
|
-
icon: string;
|
|
663
|
-
defaultScopes: string[];
|
|
664
|
-
metadata?: {
|
|
665
|
-
authDomain?: string;
|
|
666
|
-
buttonText?: string;
|
|
667
|
-
[key: string]: any;
|
|
668
|
-
};
|
|
669
|
-
};
|
|
670
|
-
facebook: SSOProviderInstance;
|
|
671
|
-
};
|
|
583
|
+
sso: SSOObject;
|
|
672
584
|
getFullName: () => string;
|
|
673
585
|
getIsLoggedIn: () => boolean;
|
|
674
586
|
getEmail: () => string;
|
|
@@ -704,5 +616,5 @@ declare function useAuth(): {
|
|
|
704
616
|
revokeAllSessions: (accountId?: string) => Promise<void>;
|
|
705
617
|
};
|
|
706
618
|
|
|
707
|
-
export { AuthApi, AuthState, PopupBlockedError, PopupClosedError, PopupTimeoutError, SSOError, StateMismatchError, accountToUser, getAllSSOProviders, getSSOProvider,
|
|
708
|
-
export type { AccountInfo, ActivateAccountResponse, AuthEventHandler, AuthEventMap, AuthMethodInfo, AuthStatusResponse, AuthenticationAccount, AuthenticationAccountType, AuthenticationMethodType, AuthenticationResponse, AvailableMethodsResponse, ChangePasswordRequest, ChangePasswordResponse, CleanupSessionsResponse, DeactivateAccountResponse, DeleteAccountResponse, DeleteAllSessionsResponse, DeleteMeResponse, DeleteSessionResponse, EntityInfo, ForgotPasswordRequest, ForgotPasswordResponse, GetAccountResponse, GetMeResponse, GetMethodsResponse, GetSessionsResponse, LoginResponse, LogoutResponse, MessageResponse, NewUser, OAuthFlowOptions, OTPMetadata, PasswordLoginRequest, PersonInfo, PopupResult, RefreshSessionResponse, RegisterRequest, RegisterResponse, ResetPasswordRequest, ResetPasswordResponse, SSOCallbackRequest, SSOCallbackResponse, SSOInitiateRequest, SSOInitiateResponse, SSOLinkRequest, SSOLinkResponse, SSOMetadata, SSOProvider, SSOProviderConfig, SSOProviderInstance, SSOUnlinkRequest, SSOUnlinkResponse, SendVerificationRequest, SendVerificationResponse, SessionInfo, SessionListResponse, UpdateAccountRequest, UpdateAccountResponse, UpdateMeResponse, UpdatePasswordForm, User, VerifyEmailRequest, VerifyEmailResponse, VerifyResetTokenResponse };
|
|
619
|
+
export { AuthApi, AuthState, PopupBlockedError, PopupClosedError, PopupTimeoutError, SSOError, StateMismatchError, accountToUser, getAllSSOProviders, getSSOProvider, initAuth, isSupportedProvider, setAuthContext, sso, ssoProvidersList, useAuth };
|
|
620
|
+
export type { AccountInfo, ActivateAccountResponse, AuthEventHandler, AuthEventMap, AuthMethodInfo, AuthStatusResponse, AuthenticationAccount, AuthenticationAccountType, AuthenticationMethodType, AuthenticationResponse, AvailableMethodsResponse, ChangePasswordRequest, ChangePasswordResponse, CleanupSessionsResponse, DeactivateAccountResponse, DeleteAccountResponse, DeleteAllSessionsResponse, DeleteMeResponse, DeleteSessionResponse, EntityInfo, ForgotPasswordRequest, ForgotPasswordResponse, GetAccountResponse, GetMeResponse, GetMethodsResponse, GetSessionsResponse, LoginResponse, LogoutResponse, MessageResponse, NewUser, OAuthFlowOptions, OTPMetadata, PasswordLoginRequest, PersonInfo, PopupResult, RefreshSessionResponse, RegisterRequest, RegisterResponse, ResetPasswordRequest, ResetPasswordResponse, SSOCallbackRequest, SSOCallbackResponse, SSOInitiateRequest, SSOInitiateResponse, SSOLinkRequest, SSOLinkResponse, SSOMetadata, SSOObject, SSOProvider, SSOProviderConfig, SSOProviderInstance, SSOUnlinkRequest, SSOUnlinkResponse, SendVerificationRequest, SendVerificationResponse, SessionInfo, SessionListResponse, UpdateAccountRequest, UpdateAccountResponse, UpdateMeResponse, UpdatePasswordForm, User, VerifyEmailRequest, VerifyEmailResponse, VerifyResetTokenResponse };
|
package/dist/index.mjs
CHANGED
|
@@ -40,6 +40,17 @@ class EventEmitter {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
function queryParams() {
|
|
44
|
+
if (typeof window === "undefined" || !window.location?.search) {
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
const params = new URLSearchParams(window.location.search);
|
|
48
|
+
const result = {};
|
|
49
|
+
params.forEach((value, key) => {
|
|
50
|
+
result[key] = value;
|
|
51
|
+
});
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
43
54
|
|
|
44
55
|
class AuthApi {
|
|
45
56
|
api;
|
|
@@ -123,7 +134,8 @@ class AuthApi {
|
|
|
123
134
|
*/
|
|
124
135
|
async linkSSOProvider(data) {
|
|
125
136
|
return this.api.post(`/authentication/sso/${data.provider}/link`, {
|
|
126
|
-
code: data.code
|
|
137
|
+
code: data.code,
|
|
138
|
+
state: data.state
|
|
127
139
|
});
|
|
128
140
|
}
|
|
129
141
|
/**
|
|
@@ -457,11 +469,20 @@ function createSSOProvider(config) {
|
|
|
457
469
|
state
|
|
458
470
|
});
|
|
459
471
|
},
|
|
460
|
-
async link(code) {
|
|
472
|
+
async link(code, state) {
|
|
461
473
|
const auth = getAuthApi();
|
|
474
|
+
if (typeof sessionStorage !== "undefined" && state) {
|
|
475
|
+
const storedState = sessionStorage.getItem(getStateKey());
|
|
476
|
+
sessionStorage.removeItem(getStateKey());
|
|
477
|
+
sessionStorage.removeItem(`oauth_provider:${state}`);
|
|
478
|
+
if (storedState && storedState !== state) {
|
|
479
|
+
throw new StateMismatchError();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
462
482
|
await auth.linkSSOProvider({
|
|
463
483
|
provider: config.id,
|
|
464
|
-
code
|
|
484
|
+
code,
|
|
485
|
+
state
|
|
465
486
|
});
|
|
466
487
|
},
|
|
467
488
|
async unlink() {
|
|
@@ -484,7 +505,7 @@ function createSSOProvider(config) {
|
|
|
484
505
|
// Default, can be overridden per provider
|
|
485
506
|
};
|
|
486
507
|
}
|
|
487
|
-
const
|
|
508
|
+
const ssoProviders = {
|
|
488
509
|
/**
|
|
489
510
|
* Google OAuth Provider
|
|
490
511
|
* https://developers.google.com/identity/protocols/oauth2
|
|
@@ -584,31 +605,59 @@ const sso = {
|
|
|
584
605
|
}
|
|
585
606
|
})
|
|
586
607
|
};
|
|
587
|
-
const
|
|
608
|
+
const sso = {
|
|
609
|
+
// All provider instances
|
|
610
|
+
...ssoProviders,
|
|
611
|
+
/**
|
|
612
|
+
* Handle OAuth callback from URL automatically
|
|
613
|
+
* Detects provider from state and completes login
|
|
614
|
+
*
|
|
615
|
+
* @example
|
|
616
|
+
* // On /auth/callback page
|
|
617
|
+
* const result = await sso.handleCallback()
|
|
618
|
+
*/
|
|
619
|
+
handleCallback: handleOAuthCallback,
|
|
620
|
+
/**
|
|
621
|
+
* Handle OAuth link callback from URL automatically
|
|
622
|
+
* Detects provider from state and completes linking
|
|
623
|
+
*
|
|
624
|
+
* @example
|
|
625
|
+
* // On /settings/link-callback page
|
|
626
|
+
* await sso.handleLinkCallback()
|
|
627
|
+
*/
|
|
628
|
+
handleLinkCallback: handleOAuthLinkCallback
|
|
629
|
+
};
|
|
630
|
+
const ssoProvidersList = Object.values(ssoProviders);
|
|
588
631
|
function getSSOProvider(provider) {
|
|
589
|
-
return
|
|
632
|
+
return ssoProviders[provider];
|
|
590
633
|
}
|
|
591
634
|
function getAllSSOProviders() {
|
|
592
|
-
return
|
|
635
|
+
return ssoProvidersList;
|
|
593
636
|
}
|
|
594
637
|
function isSupportedProvider(provider) {
|
|
595
|
-
return provider in
|
|
638
|
+
return provider in ssoProviders;
|
|
596
639
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
640
|
+
function handleOAuthCallback() {
|
|
641
|
+
const { code, state } = queryParams();
|
|
642
|
+
if (!code || !state) {
|
|
643
|
+
return Promise.resolve(null);
|
|
600
644
|
}
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
645
|
+
const provider = sessionStorage.getItem(`oauth_provider:${state}`);
|
|
646
|
+
if (!provider || !isSupportedProvider(provider)) {
|
|
647
|
+
throw new Error("Unable to determine OAuth provider. State may have expired.");
|
|
648
|
+
}
|
|
649
|
+
return ssoProviders[provider].callback(code, state);
|
|
650
|
+
}
|
|
651
|
+
function handleOAuthLinkCallback() {
|
|
652
|
+
const { code, state } = queryParams();
|
|
604
653
|
if (!code || !state) {
|
|
605
|
-
|
|
654
|
+
throw new Error("Missing code or state parameter");
|
|
606
655
|
}
|
|
607
656
|
const provider = sessionStorage.getItem(`oauth_provider:${state}`);
|
|
608
657
|
if (!provider || !isSupportedProvider(provider)) {
|
|
609
658
|
throw new Error("Unable to determine OAuth provider. State may have expired.");
|
|
610
659
|
}
|
|
611
|
-
return
|
|
660
|
+
return ssoProviders[provider].link(code, state);
|
|
612
661
|
}
|
|
613
662
|
|
|
614
663
|
var AuthState = /* @__PURE__ */ ((AuthState2) => {
|
|
@@ -938,4 +987,4 @@ function useAuth() {
|
|
|
938
987
|
};
|
|
939
988
|
}
|
|
940
989
|
|
|
941
|
-
export { AuthApi, AuthState, PopupBlockedError, PopupClosedError, PopupTimeoutError, SSOError, StateMismatchError, accountToUser, getAllSSOProviders, getSSOProvider,
|
|
990
|
+
export { AuthApi, AuthState, PopupBlockedError, PopupClosedError, PopupTimeoutError, SSOError, StateMismatchError, accountToUser, getAllSSOProviders, getSSOProvider, initAuth, isSupportedProvider, setAuthContext, sso, ssoProvidersList, useAuth };
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
package/src/sso.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SSOProvider, AuthenticationResponse } from './types'
|
|
2
|
+
import { queryParams } from './utils'
|
|
2
3
|
|
|
3
4
|
// Global reference to auth API - will be set by setAuthContext
|
|
4
5
|
let authApiRef: any = null
|
|
@@ -135,8 +136,9 @@ export interface SSOProviderInstance extends SSOProviderConfig {
|
|
|
135
136
|
|
|
136
137
|
/**
|
|
137
138
|
* Link this provider to the current logged-in user
|
|
139
|
+
* Call this after OAuth redirect completes on link callback page
|
|
138
140
|
*/
|
|
139
|
-
link: (code: string) => Promise<void>
|
|
141
|
+
link: (code: string, state?: string) => Promise<void>
|
|
140
142
|
|
|
141
143
|
/**
|
|
142
144
|
* Unlink this provider from the current user
|
|
@@ -155,6 +157,23 @@ export interface SSOProviderInstance extends SSOProviderConfig {
|
|
|
155
157
|
supportsPopup?: boolean
|
|
156
158
|
}
|
|
157
159
|
|
|
160
|
+
/**
|
|
161
|
+
* SSO object type with providers and helper methods
|
|
162
|
+
*/
|
|
163
|
+
export interface SSOObject {
|
|
164
|
+
// Provider instances
|
|
165
|
+
google: SSOProviderInstance
|
|
166
|
+
microsoft: SSOProviderInstance
|
|
167
|
+
github: SSOProviderInstance
|
|
168
|
+
okta: SSOProviderInstance
|
|
169
|
+
apple: SSOProviderInstance
|
|
170
|
+
facebook: SSOProviderInstance
|
|
171
|
+
|
|
172
|
+
// Global helper methods
|
|
173
|
+
handleCallback: () => Promise<AuthenticationResponse | null>
|
|
174
|
+
handleLinkCallback: () => Promise<void>
|
|
175
|
+
}
|
|
176
|
+
|
|
158
177
|
/**
|
|
159
178
|
* Helper to generate random state for CSRF protection
|
|
160
179
|
* Uses 32 bytes (64 hex chars) for enhanced security
|
|
@@ -372,11 +391,25 @@ function createSSOProvider(config: SSOProviderConfig): SSOProviderInstance {
|
|
|
372
391
|
})
|
|
373
392
|
},
|
|
374
393
|
|
|
375
|
-
async link(code: string) {
|
|
394
|
+
async link(code: string, state?: string) {
|
|
376
395
|
const auth = getAuthApi()
|
|
396
|
+
|
|
397
|
+
// Verify state if it was stored (per-provider key)
|
|
398
|
+
if (typeof sessionStorage !== 'undefined' && state) {
|
|
399
|
+
const storedState = sessionStorage.getItem(getStateKey())
|
|
400
|
+
sessionStorage.removeItem(getStateKey())
|
|
401
|
+
// Clean up provider mapping
|
|
402
|
+
sessionStorage.removeItem(`oauth_provider:${state}`)
|
|
403
|
+
|
|
404
|
+
if (storedState && storedState !== state) {
|
|
405
|
+
throw new StateMismatchError()
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
377
409
|
await auth.linkSSOProvider({
|
|
378
410
|
provider: config.id,
|
|
379
411
|
code,
|
|
412
|
+
state,
|
|
380
413
|
})
|
|
381
414
|
},
|
|
382
415
|
|
|
@@ -404,9 +437,9 @@ function createSSOProvider(config: SSOProviderConfig): SSOProviderInstance {
|
|
|
404
437
|
}
|
|
405
438
|
|
|
406
439
|
/**
|
|
407
|
-
* SSO Provider Implementations
|
|
440
|
+
* SSO Provider Implementations with global helpers
|
|
408
441
|
*/
|
|
409
|
-
|
|
442
|
+
const ssoProviders = {
|
|
410
443
|
/**
|
|
411
444
|
* Google OAuth Provider
|
|
412
445
|
* https://developers.google.com/identity/protocols/oauth2
|
|
@@ -512,54 +545,96 @@ export const sso = {
|
|
|
512
545
|
}
|
|
513
546
|
|
|
514
547
|
/**
|
|
515
|
-
*
|
|
548
|
+
* SSO object with providers and global helper methods
|
|
516
549
|
*/
|
|
517
|
-
export const
|
|
550
|
+
export const sso: SSOObject = {
|
|
551
|
+
// All provider instances
|
|
552
|
+
...ssoProviders,
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Handle OAuth callback from URL automatically
|
|
556
|
+
* Detects provider from state and completes login
|
|
557
|
+
*
|
|
558
|
+
* @example
|
|
559
|
+
* // On /auth/callback page
|
|
560
|
+
* const result = await sso.handleCallback()
|
|
561
|
+
*/
|
|
562
|
+
handleCallback: handleOAuthCallback,
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Handle OAuth link callback from URL automatically
|
|
566
|
+
* Detects provider from state and completes linking
|
|
567
|
+
*
|
|
568
|
+
* @example
|
|
569
|
+
* // On /settings/link-callback page
|
|
570
|
+
* await sso.handleLinkCallback()
|
|
571
|
+
*/
|
|
572
|
+
handleLinkCallback: handleOAuthLinkCallback,
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Array of all SSO provider instances
|
|
577
|
+
*/
|
|
578
|
+
export const ssoProvidersList = Object.values(ssoProviders) as readonly SSOProviderInstance[]
|
|
518
579
|
|
|
519
580
|
/**
|
|
520
581
|
* Get SSO provider instance by ID
|
|
521
582
|
*/
|
|
522
583
|
export function getSSOProvider(provider: SSOProvider): SSOProviderInstance | undefined {
|
|
523
|
-
return
|
|
584
|
+
return ssoProviders[provider]
|
|
524
585
|
}
|
|
525
586
|
|
|
526
587
|
/**
|
|
527
588
|
* Get all available SSO providers
|
|
528
589
|
*/
|
|
529
590
|
export function getAllSSOProviders(): readonly SSOProviderInstance[] {
|
|
530
|
-
return
|
|
591
|
+
return ssoProvidersList
|
|
531
592
|
}
|
|
532
593
|
|
|
533
594
|
/**
|
|
534
595
|
* Check if a provider is supported
|
|
535
596
|
*/
|
|
536
597
|
export function isSupportedProvider(provider: string): provider is SSOProvider {
|
|
537
|
-
return provider in
|
|
598
|
+
return provider in ssoProviders
|
|
538
599
|
}
|
|
539
600
|
|
|
540
601
|
/**
|
|
541
602
|
* Handle OAuth callback from URL
|
|
542
|
-
*
|
|
603
|
+
* Internal helper - use sso.handleCallback() instead
|
|
543
604
|
*/
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
605
|
+
function handleOAuthCallback(): Promise<AuthenticationResponse | null> {
|
|
606
|
+
const { code, state } = queryParams()
|
|
607
|
+
if (!code || !state) {
|
|
608
|
+
return Promise.resolve(null)
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Get the provider from sessionStorage (stored during redirect/popup)
|
|
612
|
+
const provider = sessionStorage.getItem(`oauth_provider:${state}`) as SSOProvider | null
|
|
613
|
+
|
|
614
|
+
if (!provider || !isSupportedProvider(provider)) {
|
|
615
|
+
throw new Error('Unable to determine OAuth provider. State may have expired.')
|
|
547
616
|
}
|
|
548
617
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
618
|
+
return ssoProviders[provider].callback(code, state)
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Handle OAuth link callback from URL
|
|
623
|
+
* Internal helper - use sso.handleLinkCallback() instead
|
|
624
|
+
*/
|
|
625
|
+
function handleOAuthLinkCallback(): Promise<void> {
|
|
626
|
+
const { code, state } = queryParams()
|
|
552
627
|
|
|
553
628
|
if (!code || !state) {
|
|
554
|
-
|
|
629
|
+
throw new Error('Missing code or state parameter')
|
|
555
630
|
}
|
|
556
631
|
|
|
557
|
-
// Get the provider from sessionStorage (stored during redirect
|
|
632
|
+
// Get the provider from sessionStorage (stored during redirect)
|
|
558
633
|
const provider = sessionStorage.getItem(`oauth_provider:${state}`) as SSOProvider | null
|
|
559
634
|
|
|
560
635
|
if (!provider || !isSupportedProvider(provider)) {
|
|
561
636
|
throw new Error('Unable to determine OAuth provider. State may have expired.')
|
|
562
637
|
}
|
|
563
638
|
|
|
564
|
-
return
|
|
639
|
+
return ssoProviders[provider].link(code, state)
|
|
565
640
|
}
|
package/src/types.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -44,3 +44,15 @@ export class EventEmitter {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
export function queryParams(): Record<string, string> {
|
|
49
|
+
if (typeof window === 'undefined' || !window.location?.search) {
|
|
50
|
+
return {}
|
|
51
|
+
}
|
|
52
|
+
const params = new URLSearchParams(window.location.search)
|
|
53
|
+
const result: Record<string, string> = {}
|
|
54
|
+
params.forEach((value, key) => {
|
|
55
|
+
result[key] = value
|
|
56
|
+
})
|
|
57
|
+
return result
|
|
58
|
+
}
|