@capgo/capacitor-social-login 1.2.6 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,31 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ export class BaseSocialLogin extends WebPlugin {
3
+ constructor() {
4
+ super();
5
+ }
6
+ parseJwt(token) {
7
+ const base64Url = token.split('.')[1];
8
+ const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
9
+ const jsonPayload = decodeURIComponent(atob(base64)
10
+ .split('')
11
+ .map((c) => {
12
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
13
+ })
14
+ .join(''));
15
+ return JSON.parse(jsonPayload);
16
+ }
17
+ async loadScript(src) {
18
+ return new Promise((resolve, reject) => {
19
+ const script = document.createElement('script');
20
+ script.src = src;
21
+ script.async = true;
22
+ script.onload = () => {
23
+ resolve();
24
+ };
25
+ script.onerror = reject;
26
+ document.body.appendChild(script);
27
+ });
28
+ }
29
+ }
30
+ BaseSocialLogin.OAUTH_STATE_KEY = 'social_login_oauth_pending';
31
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,OAAO,eAAgB,SAAQ,SAAS;IAG5C;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAES,QAAQ,CAAC,KAAa;QAC9B,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC/D,MAAM,WAAW,GAAG,kBAAkB,CACpC,IAAI,CAAC,MAAM,CAAC;aACT,KAAK,CAAC,EAAE,CAAC;aACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,OAAO,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC,CAAC;aACD,IAAI,CAAC,EAAE,CAAC,CACZ,CAAC;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC;IAES,KAAK,CAAC,UAAU,CAAC,GAAW;QACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAChD,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC;YACjB,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;YACpB,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE;gBACnB,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;YACF,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC;YACxB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC;;AA/ByB,+BAAe,GAAG,4BAA4B,CAAC","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nexport class BaseSocialLogin extends WebPlugin {\n protected static readonly OAUTH_STATE_KEY = 'social_login_oauth_pending';\n\n constructor() {\n super();\n }\n\n protected parseJwt(token: string): any {\n const base64Url = token.split('.')[1];\n const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');\n const jsonPayload = decodeURIComponent(\n atob(base64)\n .split('')\n .map((c) => {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);\n })\n .join(''),\n );\n return JSON.parse(jsonPayload);\n }\n\n protected async loadScript(src: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = src;\n script.async = true;\n script.onload = () => {\n resolve();\n };\n script.onerror = reject;\n document.body.appendChild(script);\n });\n }\n}\n"]}
@@ -18,7 +18,7 @@ export interface InitializeOptions {
18
18
  */
19
19
  iOSClientId?: string;
20
20
  /**
21
- * The app's server client ID, found and created in the Google Developers Console.
21
+ * The app's server client ID, required for offline mode, found and created in the Google Developers Console.
22
22
  * For iOS.
23
23
  * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com
24
24
  * @since 3.1.0
@@ -32,11 +32,16 @@ export interface InitializeOptions {
32
32
  */
33
33
  webClientId?: string;
34
34
  /**
35
- * The login mode, can be online or offline.
35
+ * The login mode, can be online or offline. In offline mode, the user will be able to login without an internet connection. It requires iOSServerClientId to be set.
36
36
  * @example offline
37
37
  * @since 3.1.0
38
38
  */
39
39
  mode?: 'online' | 'offline';
40
+ /**
41
+ * Filter visible accounts by hosted domain
42
+ * @description filter visible accounts by hosted domain
43
+ */
44
+ hostedDomain?: string;
40
45
  };
41
46
  apple?: {
42
47
  /**
@@ -87,11 +92,17 @@ export interface GoogleLoginOptions {
87
92
  */
88
93
  forceRefreshToken?: boolean;
89
94
  /**
90
- * Disable one-tap login (web only)
91
- * @description disable one-tap login
95
+ * Force account selection prompt (iOS)
96
+ * @description forces the account selection prompt to appear on iOS
92
97
  * @default false
93
98
  */
94
- disableOneTap?: boolean;
99
+ forcePrompt?: boolean;
100
+ /**
101
+ * Style
102
+ * @description style
103
+ * @default 'standard'
104
+ */
105
+ style?: 'bottom' | 'standard';
95
106
  }
96
107
  export interface GoogleLoginResponseOnline {
97
108
  accessToken: AccessToken | null;
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface InitializeOptions {\n facebook?: {\n /**\n * Facebook App ID, provided by Facebook for web, in mobile it's set in the native files\n */\n appId: string;\n /**\n * Facebook Client Token, provided by Facebook for web, in mobile it's set in the native files\n */\n clientToken: string;\n };\n\n google?: {\n /**\n * The app's client ID, found and created in the Google Developers Console.\n * For iOS.\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n iOSClientId?: string;\n /**\n * The app's server client ID, found and created in the Google Developers Console.\n * For iOS.\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n iOSServerClientId?: string;\n /**\n * The app's web client ID, found and created in the Google Developers Console.\n * For Android (and web in the future).\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n webClientId?: string;\n /**\n * The login mode, can be online or offline.\n * @example offline\n * @since 3.1.0\n */\n mode?: 'online' | 'offline';\n };\n apple?: {\n /**\n * Apple Client ID, provided by Apple for web and Android\n */\n clientId?: string;\n /**\n * Apple Redirect URL, should be your backend url that is configured in your apple app, only for android\n */\n redirectUrl?: string;\n };\n}\n\nexport interface FacebookLoginOptions {\n /**\n * Permissions\n * @description select permissions to login with\n */\n permissions: string[];\n /**\n * Is Limited Login\n * @description use limited login for Facebook IOS\n * @default false\n */\n limitedLogin?: boolean;\n /**\n * Nonce\n * @description A custom nonce to use for the login request\n */\n nonce?: string;\n}\n\nexport interface GoogleLoginOptions {\n /**\n * Specifies the scopes required for accessing Google APIs\n * The default is defined in the configuration.\n * @example [\"profile\", \"email\"]\n * @see [Google OAuth2 Scopes](https://developers.google.com/identity/protocols/oauth2/scopes)\n */\n scopes?: string[];\n /**\n * Nonce\n * @description nonce\n */\n nonce?: string;\n /**\n * Force refresh token (only for Android)\n * @description force refresh token\n * @default false\n */\n forceRefreshToken?: boolean;\n /**\n * Disable one-tap login (web only)\n * @description disable one-tap login\n * @default false\n */\n disableOneTap?: boolean;\n}\n\nexport interface GoogleLoginResponseOnline {\n accessToken: AccessToken | null;\n idToken: string | null;\n profile: {\n email: string | null;\n familyName: string | null;\n givenName: string | null;\n id: string | null;\n name: string | null;\n imageUrl: string | null;\n };\n responseType: 'online';\n}\n\nexport interface GoogleLoginResponseOffline {\n serverAuthCode: string;\n responseType: 'offline';\n}\n\nexport type GoogleLoginResponse = GoogleLoginResponseOnline | GoogleLoginResponseOffline;\n\nexport interface AppleProviderOptions {\n /**\n * Scopes\n * @description An array of scopes to request during login\n * @example [\"name\", \"email\"]\n * default: [\"name\", \"email\"]\n */\n scopes?: string[];\n /**\n * Nonce\n * @description nonce\n */\n nonce?: string;\n /**\n * State\n * @description state\n */\n state?: string;\n}\n\nexport interface AppleProviderResponse {\n accessToken: AccessToken | null;\n idToken: string | null;\n profile: {\n user: string;\n email: string | null;\n givenName: string | null;\n familyName: string | null;\n };\n}\n\nexport type LoginOptions =\n | {\n provider: 'facebook';\n options: FacebookLoginOptions;\n }\n | {\n provider: 'google';\n options: GoogleLoginOptions;\n }\n | {\n provider: 'apple';\n options: AppleProviderOptions;\n };\n\nexport type LoginResult =\n | {\n provider: 'facebook';\n result: FacebookLoginResponse;\n }\n | {\n provider: 'google';\n result: GoogleLoginResponse;\n }\n | {\n provider: 'apple';\n result: AppleProviderResponse;\n };\n\nexport interface AccessToken {\n applicationId?: string;\n declinedPermissions?: string[];\n expires?: string;\n isExpired?: boolean;\n lastRefresh?: string;\n permissions?: string[];\n token: string;\n refreshToken?: string;\n userId?: string;\n}\n\nexport interface FacebookLoginResponse {\n accessToken: AccessToken | null;\n idToken: string | null;\n profile: {\n userID: string;\n email: string | null;\n friendIDs: string[];\n birthday: string | null;\n ageRange: { min?: number; max?: number } | null;\n gender: string | null;\n location: { id: string; name: string } | null;\n hometown: { id: string; name: string } | null;\n profileURL: string | null;\n name: string | null;\n imageURL: string | null;\n };\n}\n\nexport interface AuthorizationCode {\n /**\n * Jwt\n * @description A JSON web token\n */\n jwt?: string;\n /**\n * Access Token\n * @description An access token\n */\n accessToken?: string;\n}\n\nexport interface AuthorizationCodeOptions {\n /**\n * Provider\n * @description Provider for the authorization code\n */\n provider: 'apple' | 'google' | 'facebook';\n}\n\nexport interface isLoggedInOptions {\n /**\n * Provider\n * @description Provider for the isLoggedIn\n */\n provider: 'apple' | 'google' | 'facebook';\n}\n\n// Add a helper type to map providers to their response types\nexport type ProviderResponseMap = {\n facebook: FacebookLoginResponse;\n google: GoogleLoginResponse;\n apple: AppleProviderResponse;\n};\n\nexport interface SocialLoginPlugin {\n /**\n * Initialize the plugin\n * @description initialize the plugin with the required options\n */\n initialize(options: InitializeOptions): Promise<void>;\n /**\n * Login with the selected provider\n * @description login with the selected provider\n */\n login<T extends LoginOptions['provider']>(\n options: Extract<LoginOptions, { provider: T }>,\n ): Promise<{ provider: T; result: ProviderResponseMap[T] }>;\n /**\n * Logout\n * @description logout the user\n */\n logout(options: { provider: 'apple' | 'google' | 'facebook' }): Promise<void>;\n /**\n * IsLoggedIn\n * @description logout the user\n */\n isLoggedIn(options: isLoggedInOptions): Promise<{ isLoggedIn: boolean }>;\n\n /**\n * Get the current access token\n * @description get the current access token\n */\n getAuthorizationCode(options: AuthorizationCodeOptions): Promise<AuthorizationCode>;\n /**\n * Refresh the access token\n * @description refresh the access token\n */\n refresh(options: LoginOptions): Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface InitializeOptions {\n facebook?: {\n /**\n * Facebook App ID, provided by Facebook for web, in mobile it's set in the native files\n */\n appId: string;\n /**\n * Facebook Client Token, provided by Facebook for web, in mobile it's set in the native files\n */\n clientToken: string;\n };\n\n google?: {\n /**\n * The app's client ID, found and created in the Google Developers Console.\n * For iOS.\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n iOSClientId?: string;\n /**\n * The app's server client ID, required for offline mode, found and created in the Google Developers Console.\n * For iOS.\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n iOSServerClientId?: string;\n /**\n * The app's web client ID, found and created in the Google Developers Console.\n * For Android (and web in the future).\n * @example xxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com\n * @since 3.1.0\n */\n webClientId?: string;\n /**\n * The login mode, can be online or offline. In offline mode, the user will be able to login without an internet connection. It requires iOSServerClientId to be set.\n * @example offline\n * @since 3.1.0\n */\n mode?: 'online' | 'offline';\n /**\n * Filter visible accounts by hosted domain\n * @description filter visible accounts by hosted domain\n */\n hostedDomain?: string;\n };\n apple?: {\n /**\n * Apple Client ID, provided by Apple for web and Android\n */\n clientId?: string;\n /**\n * Apple Redirect URL, should be your backend url that is configured in your apple app, only for android\n */\n redirectUrl?: string;\n };\n}\n\nexport interface FacebookLoginOptions {\n /**\n * Permissions\n * @description select permissions to login with\n */\n permissions: string[];\n /**\n * Is Limited Login\n * @description use limited login for Facebook IOS\n * @default false\n */\n limitedLogin?: boolean;\n /**\n * Nonce\n * @description A custom nonce to use for the login request\n */\n nonce?: string;\n}\n\nexport interface GoogleLoginOptions {\n /**\n * Specifies the scopes required for accessing Google APIs\n * The default is defined in the configuration.\n * @example [\"profile\", \"email\"]\n * @see [Google OAuth2 Scopes](https://developers.google.com/identity/protocols/oauth2/scopes)\n */\n scopes?: string[];\n /**\n * Nonce\n * @description nonce\n */\n nonce?: string;\n /**\n * Force refresh token (only for Android)\n * @description force refresh token\n * @default false\n */\n forceRefreshToken?: boolean;\n /**\n * Force account selection prompt (iOS)\n * @description forces the account selection prompt to appear on iOS\n * @default false\n */\n forcePrompt?: boolean;\n /**\n * Style\n * @description style\n * @default 'standard'\n */\n style?: 'bottom' | 'standard';\n}\n\nexport interface GoogleLoginResponseOnline {\n accessToken: AccessToken | null;\n idToken: string | null;\n profile: {\n email: string | null;\n familyName: string | null;\n givenName: string | null;\n id: string | null;\n name: string | null;\n imageUrl: string | null;\n };\n responseType: 'online';\n}\n\nexport interface GoogleLoginResponseOffline {\n serverAuthCode: string;\n responseType: 'offline';\n}\n\nexport type GoogleLoginResponse = GoogleLoginResponseOnline | GoogleLoginResponseOffline;\n\nexport interface AppleProviderOptions {\n /**\n * Scopes\n * @description An array of scopes to request during login\n * @example [\"name\", \"email\"]\n * default: [\"name\", \"email\"]\n */\n scopes?: string[];\n /**\n * Nonce\n * @description nonce\n */\n nonce?: string;\n /**\n * State\n * @description state\n */\n state?: string;\n}\n\nexport interface AppleProviderResponse {\n accessToken: AccessToken | null;\n idToken: string | null;\n profile: {\n user: string;\n email: string | null;\n givenName: string | null;\n familyName: string | null;\n };\n}\n\nexport type LoginOptions =\n | {\n provider: 'facebook';\n options: FacebookLoginOptions;\n }\n | {\n provider: 'google';\n options: GoogleLoginOptions;\n }\n | {\n provider: 'apple';\n options: AppleProviderOptions;\n };\n\nexport type LoginResult =\n | {\n provider: 'facebook';\n result: FacebookLoginResponse;\n }\n | {\n provider: 'google';\n result: GoogleLoginResponse;\n }\n | {\n provider: 'apple';\n result: AppleProviderResponse;\n };\n\nexport interface AccessToken {\n applicationId?: string;\n declinedPermissions?: string[];\n expires?: string;\n isExpired?: boolean;\n lastRefresh?: string;\n permissions?: string[];\n token: string;\n refreshToken?: string;\n userId?: string;\n}\n\nexport interface FacebookLoginResponse {\n accessToken: AccessToken | null;\n idToken: string | null;\n profile: {\n userID: string;\n email: string | null;\n friendIDs: string[];\n birthday: string | null;\n ageRange: { min?: number; max?: number } | null;\n gender: string | null;\n location: { id: string; name: string } | null;\n hometown: { id: string; name: string } | null;\n profileURL: string | null;\n name: string | null;\n imageURL: string | null;\n };\n}\n\nexport interface AuthorizationCode {\n /**\n * Jwt\n * @description A JSON web token\n */\n jwt?: string;\n /**\n * Access Token\n * @description An access token\n */\n accessToken?: string;\n}\n\nexport interface AuthorizationCodeOptions {\n /**\n * Provider\n * @description Provider for the authorization code\n */\n provider: 'apple' | 'google' | 'facebook';\n}\n\nexport interface isLoggedInOptions {\n /**\n * Provider\n * @description Provider for the isLoggedIn\n */\n provider: 'apple' | 'google' | 'facebook';\n}\n\n// Add a helper type to map providers to their response types\nexport type ProviderResponseMap = {\n facebook: FacebookLoginResponse;\n google: GoogleLoginResponse;\n apple: AppleProviderResponse;\n};\n\nexport interface SocialLoginPlugin {\n /**\n * Initialize the plugin\n * @description initialize the plugin with the required options\n */\n initialize(options: InitializeOptions): Promise<void>;\n /**\n * Login with the selected provider\n * @description login with the selected provider\n */\n login<T extends LoginOptions['provider']>(\n options: Extract<LoginOptions, { provider: T }>,\n ): Promise<{ provider: T; result: ProviderResponseMap[T] }>;\n /**\n * Logout\n * @description logout the user\n */\n logout(options: { provider: 'apple' | 'google' | 'facebook' }): Promise<void>;\n /**\n * IsLoggedIn\n * @description logout the user\n */\n isLoggedIn(options: isLoggedInOptions): Promise<{ isLoggedIn: boolean }>;\n\n /**\n * Get the current access token\n * @description get the current access token\n */\n getAuthorizationCode(options: AuthorizationCodeOptions): Promise<AuthorizationCode>;\n /**\n * Refresh the access token\n * @description refresh the access token\n */\n refresh(options: LoginOptions): Promise<void>;\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import { BaseSocialLogin } from './base';
2
+ import type { FacebookLoginOptions, AuthorizationCode, LoginResult } from './definitions';
3
+ export declare class FacebookSocialLogin extends BaseSocialLogin {
4
+ private appId;
5
+ private scriptLoaded;
6
+ initialize(appId: string | null): Promise<void>;
7
+ login(options: FacebookLoginOptions): Promise<LoginResult>;
8
+ logout(): Promise<void>;
9
+ isLoggedIn(): Promise<{
10
+ isLoggedIn: boolean;
11
+ }>;
12
+ getAuthorizationCode(): Promise<AuthorizationCode>;
13
+ refresh(options: FacebookLoginOptions): Promise<void>;
14
+ private loadFacebookScript;
15
+ }
@@ -0,0 +1,94 @@
1
+ import { BaseSocialLogin } from './base';
2
+ export class FacebookSocialLogin extends BaseSocialLogin {
3
+ constructor() {
4
+ super(...arguments);
5
+ this.appId = null;
6
+ this.scriptLoaded = false;
7
+ }
8
+ async initialize(appId) {
9
+ this.appId = appId;
10
+ if (appId) {
11
+ await this.loadFacebookScript();
12
+ FB.init({
13
+ appId: this.appId,
14
+ version: 'v17.0',
15
+ xfbml: true,
16
+ cookie: true,
17
+ });
18
+ }
19
+ }
20
+ async login(options) {
21
+ if (!this.appId) {
22
+ throw new Error('Facebook App ID not set. Call initialize() first.');
23
+ }
24
+ return new Promise((resolve, reject) => {
25
+ FB.login((response) => {
26
+ if (response.status === 'connected') {
27
+ FB.api('/me', { fields: 'id,name,email,picture' }, (userInfo) => {
28
+ var _a, _b;
29
+ const result = {
30
+ accessToken: {
31
+ token: response.authResponse.accessToken,
32
+ userId: response.authResponse.userID,
33
+ },
34
+ profile: {
35
+ userID: userInfo.id,
36
+ name: userInfo.name,
37
+ email: userInfo.email || null,
38
+ imageURL: ((_b = (_a = userInfo.picture) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.url) || null,
39
+ friendIDs: [],
40
+ birthday: null,
41
+ ageRange: null,
42
+ gender: null,
43
+ location: null,
44
+ hometown: null,
45
+ profileURL: null,
46
+ },
47
+ idToken: null,
48
+ };
49
+ resolve({ provider: 'facebook', result });
50
+ });
51
+ }
52
+ else {
53
+ reject(new Error('Facebook login failed'));
54
+ }
55
+ }, { scope: options.permissions.join(',') });
56
+ });
57
+ }
58
+ async logout() {
59
+ return new Promise((resolve) => {
60
+ FB.logout(() => resolve());
61
+ });
62
+ }
63
+ async isLoggedIn() {
64
+ return new Promise((resolve) => {
65
+ FB.getLoginStatus((response) => {
66
+ resolve({ isLoggedIn: response.status === 'connected' });
67
+ });
68
+ });
69
+ }
70
+ async getAuthorizationCode() {
71
+ return new Promise((resolve, reject) => {
72
+ FB.getLoginStatus((response) => {
73
+ var _a;
74
+ if (response.status === 'connected') {
75
+ resolve({ jwt: ((_a = response.authResponse) === null || _a === void 0 ? void 0 : _a.accessToken) || '' });
76
+ }
77
+ else {
78
+ reject(new Error('No Facebook authorization code available'));
79
+ }
80
+ });
81
+ });
82
+ }
83
+ async refresh(options) {
84
+ await this.login(options);
85
+ }
86
+ async loadFacebookScript() {
87
+ if (this.scriptLoaded)
88
+ return;
89
+ return this.loadScript('https://connect.facebook.net/en_US/sdk.js').then(() => {
90
+ this.scriptLoaded = true;
91
+ });
92
+ }
93
+ }
94
+ //# sourceMappingURL=facebook-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facebook-provider.js","sourceRoot":"","sources":["../../src/facebook-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseSocialLogin } from './base';\nimport type { FacebookLoginOptions, FacebookLoginResponse, AuthorizationCode, LoginResult } from './definitions';\n\ndeclare const FB: {\n init(options: any): void;\n login(\n callback: (response: { status: string; authResponse: { accessToken: string; userID: string } }) => void,\n options?: { scope: string },\n ): void;\n logout(callback: () => void): void;\n api(path: string, params: { fields: string }, callback: (response: any) => void): void;\n getLoginStatus(callback: (response: { status: string; authResponse?: { accessToken: string } }) => void): void;\n};\n\nexport class FacebookSocialLogin extends BaseSocialLogin {\n private appId: string | null = null;\n private scriptLoaded = false;\n\n async initialize(appId: string | null): Promise<void> {\n this.appId = appId;\n\n if (appId) {\n await this.loadFacebookScript();\n FB.init({\n appId: this.appId,\n version: 'v17.0',\n xfbml: true,\n cookie: true,\n });\n }\n }\n\n async login(options: FacebookLoginOptions): Promise<LoginResult> {\n if (!this.appId) {\n throw new Error('Facebook App ID not set. Call initialize() first.');\n }\n\n return new Promise((resolve, reject) => {\n FB.login(\n (response) => {\n if (response.status === 'connected') {\n FB.api('/me', { fields: 'id,name,email,picture' }, (userInfo: any) => {\n const result: FacebookLoginResponse = {\n accessToken: {\n token: response.authResponse.accessToken,\n userId: response.authResponse.userID,\n },\n profile: {\n userID: userInfo.id,\n name: userInfo.name,\n email: userInfo.email || null,\n imageURL: userInfo.picture?.data?.url || null,\n friendIDs: [],\n birthday: null,\n ageRange: null,\n gender: null,\n location: null,\n hometown: null,\n profileURL: null,\n },\n idToken: null,\n };\n resolve({ provider: 'facebook', result });\n });\n } else {\n reject(new Error('Facebook login failed'));\n }\n },\n { scope: options.permissions.join(',') },\n );\n });\n }\n\n async logout(): Promise<void> {\n return new Promise<void>((resolve) => {\n FB.logout(() => resolve());\n });\n }\n\n async isLoggedIn(): Promise<{ isLoggedIn: boolean }> {\n return new Promise((resolve) => {\n FB.getLoginStatus((response) => {\n resolve({ isLoggedIn: response.status === 'connected' });\n });\n });\n }\n\n async getAuthorizationCode(): Promise<AuthorizationCode> {\n return new Promise((resolve, reject) => {\n FB.getLoginStatus((response) => {\n if (response.status === 'connected') {\n resolve({ jwt: response.authResponse?.accessToken || '' });\n } else {\n reject(new Error('No Facebook authorization code available'));\n }\n });\n });\n }\n\n async refresh(options: FacebookLoginOptions): Promise<void> {\n await this.login(options);\n }\n\n private async loadFacebookScript(): Promise<void> {\n if (this.scriptLoaded) return;\n\n return this.loadScript('https://connect.facebook.net/en_US/sdk.js').then(() => {\n this.scriptLoaded = true;\n });\n }\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import { BaseSocialLogin } from './base';
2
+ import type { GoogleLoginOptions, LoginResult, ProviderResponseMap, AuthorizationCode } from './definitions';
3
+ export declare class GoogleSocialLogin extends BaseSocialLogin {
4
+ private clientId;
5
+ private hostedDomain?;
6
+ private loginType;
7
+ private GOOGLE_TOKEN_REQUEST_URL;
8
+ private readonly GOOGLE_STATE_KEY;
9
+ initialize(clientId: string | null, mode?: 'online' | 'offline', hostedDomain?: string | null): Promise<void>;
10
+ login<T extends 'google'>(options: GoogleLoginOptions): Promise<{
11
+ provider: T;
12
+ result: ProviderResponseMap[T];
13
+ }>;
14
+ logout(): Promise<void>;
15
+ isLoggedIn(): Promise<{
16
+ isLoggedIn: boolean;
17
+ }>;
18
+ getAuthorizationCode(): Promise<AuthorizationCode>;
19
+ refresh(): Promise<void>;
20
+ handleOAuthRedirect(url: URL): LoginResult | null;
21
+ private accessTokenIsValid;
22
+ private idTokenValid;
23
+ private rawLogoutGoogle;
24
+ private persistStateGoogle;
25
+ private clearStateGoogle;
26
+ private getGoogleState;
27
+ private traditionalOAuth;
28
+ }
@@ -0,0 +1,350 @@
1
+ import { BaseSocialLogin } from './base';
2
+ export class GoogleSocialLogin extends BaseSocialLogin {
3
+ constructor() {
4
+ super(...arguments);
5
+ this.clientId = null;
6
+ this.loginType = 'online';
7
+ this.GOOGLE_TOKEN_REQUEST_URL = 'https://www.googleapis.com/oauth2/v3/tokeninfo';
8
+ this.GOOGLE_STATE_KEY = 'capgo_social_login_google_state';
9
+ }
10
+ async initialize(clientId, mode, hostedDomain) {
11
+ this.clientId = clientId;
12
+ if (mode) {
13
+ this.loginType = mode;
14
+ }
15
+ this.hostedDomain = hostedDomain;
16
+ }
17
+ async login(options) {
18
+ if (!this.clientId) {
19
+ throw new Error('Google Client ID not set. Call initialize() first.');
20
+ }
21
+ let scopes = options.scopes || [];
22
+ if (scopes.length > 0) {
23
+ // If scopes are provided, directly use the traditional OAuth flow
24
+ if (!scopes.includes('https://www.googleapis.com/auth/userinfo.email')) {
25
+ scopes.push('https://www.googleapis.com/auth/userinfo.email');
26
+ }
27
+ if (!scopes.includes('https://www.googleapis.com/auth/userinfo.profile')) {
28
+ scopes.push('https://www.googleapis.com/auth/userinfo.profile');
29
+ }
30
+ if (!scopes.includes('openid')) {
31
+ scopes.push('openid');
32
+ }
33
+ }
34
+ else {
35
+ scopes = [
36
+ 'https://www.googleapis.com/auth/userinfo.email',
37
+ 'https://www.googleapis.com/auth/userinfo.profile',
38
+ 'openid',
39
+ ];
40
+ }
41
+ const nonce = options.nonce || Math.random().toString(36).substring(2);
42
+ // If scopes are provided, directly use the traditional OAuth flow
43
+ return this.traditionalOAuth({
44
+ scopes,
45
+ nonce,
46
+ hostedDomain: this.hostedDomain,
47
+ });
48
+ }
49
+ async logout() {
50
+ if (this.loginType === 'offline') {
51
+ return Promise.reject("Offline login doesn't store tokens. logout is not available");
52
+ }
53
+ // eslint-disable-next-line
54
+ const state = this.getGoogleState();
55
+ if (!state)
56
+ return;
57
+ await this.rawLogoutGoogle(state.accessToken);
58
+ }
59
+ async isLoggedIn() {
60
+ if (this.loginType === 'offline') {
61
+ return Promise.reject("Offline login doesn't store tokens. isLoggedIn is not available");
62
+ }
63
+ // eslint-disable-next-line
64
+ const state = this.getGoogleState();
65
+ if (!state)
66
+ return { isLoggedIn: false };
67
+ try {
68
+ const isValidAccessToken = await this.accessTokenIsValid(state.accessToken);
69
+ const isValidIdToken = this.idTokenValid(state.idToken);
70
+ if (isValidAccessToken && isValidIdToken) {
71
+ return { isLoggedIn: true };
72
+ }
73
+ else {
74
+ try {
75
+ await this.rawLogoutGoogle(state.accessToken, false);
76
+ }
77
+ catch (e) {
78
+ console.error('Access token is not valid, but cannot logout', e);
79
+ }
80
+ return { isLoggedIn: false };
81
+ }
82
+ }
83
+ catch (e) {
84
+ return Promise.reject(e);
85
+ }
86
+ }
87
+ async getAuthorizationCode() {
88
+ if (this.loginType === 'offline') {
89
+ return Promise.reject("Offline login doesn't store tokens. getAuthorizationCode is not available");
90
+ }
91
+ // eslint-disable-next-line
92
+ const state = this.getGoogleState();
93
+ if (!state)
94
+ throw new Error('No Google authorization code available');
95
+ try {
96
+ const isValidAccessToken = await this.accessTokenIsValid(state.accessToken);
97
+ const isValidIdToken = this.idTokenValid(state.idToken);
98
+ if (isValidAccessToken && isValidIdToken) {
99
+ return { accessToken: state.accessToken, jwt: state.idToken };
100
+ }
101
+ else {
102
+ try {
103
+ await this.rawLogoutGoogle(state.accessToken, false);
104
+ }
105
+ catch (e) {
106
+ console.error('Access token is not valid, but cannot logout', e);
107
+ }
108
+ throw new Error('No Google authorization code available');
109
+ }
110
+ }
111
+ catch (e) {
112
+ return Promise.reject(e);
113
+ }
114
+ }
115
+ async refresh() {
116
+ // For Google, we can prompt for re-authentication
117
+ return Promise.reject('Not implemented');
118
+ }
119
+ handleOAuthRedirect(url) {
120
+ const paramsRaw = url.searchParams;
121
+ const code = paramsRaw.get('code');
122
+ if (code && paramsRaw.has('scope')) {
123
+ return {
124
+ provider: 'google',
125
+ result: {
126
+ serverAuthCode: code,
127
+ responseType: 'offline',
128
+ },
129
+ };
130
+ }
131
+ const hash = url.hash.substring(1);
132
+ console.log('handleOAuthRedirect', url.hash);
133
+ if (!hash)
134
+ return null;
135
+ console.log('handleOAuthRedirect ok');
136
+ const params = new URLSearchParams(hash);
137
+ const accessToken = params.get('access_token');
138
+ const idToken = params.get('id_token');
139
+ if (accessToken && idToken) {
140
+ localStorage.removeItem(BaseSocialLogin.OAUTH_STATE_KEY);
141
+ const profile = this.parseJwt(idToken);
142
+ return {
143
+ provider: 'google',
144
+ result: {
145
+ accessToken: {
146
+ token: accessToken,
147
+ },
148
+ idToken,
149
+ profile: {
150
+ email: profile.email || null,
151
+ familyName: profile.family_name || null,
152
+ givenName: profile.given_name || null,
153
+ id: profile.sub || null,
154
+ name: profile.name || null,
155
+ imageUrl: profile.picture || null,
156
+ },
157
+ responseType: 'online',
158
+ },
159
+ };
160
+ }
161
+ return null;
162
+ }
163
+ async accessTokenIsValid(accessToken) {
164
+ const url = `${this.GOOGLE_TOKEN_REQUEST_URL}?access_token=${encodeURIComponent(accessToken)}`;
165
+ try {
166
+ // Make the GET request using fetch
167
+ const response = await fetch(url);
168
+ // Check if the response is successful
169
+ if (!response.ok) {
170
+ console.log(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response not successful. Status code: ${response.status}. Assuming that the token is not valid`);
171
+ return false;
172
+ }
173
+ // Get the response body as text
174
+ const responseBody = await response.text();
175
+ if (!responseBody) {
176
+ console.error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is null`);
177
+ throw new Error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is null`);
178
+ }
179
+ // Parse the response body as JSON
180
+ let jsonObject;
181
+ try {
182
+ jsonObject = JSON.parse(responseBody);
183
+ }
184
+ catch (e) {
185
+ console.error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is not valid JSON. Error: ${e}`);
186
+ throw new Error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is not valid JSON. Error: ${e}`);
187
+ }
188
+ // Extract the 'expires_in' field
189
+ const expiresInStr = jsonObject['expires_in'];
190
+ if (expiresInStr === undefined || expiresInStr === null) {
191
+ console.error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response JSON does not include 'expires_in'.`);
192
+ throw new Error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response JSON does not include 'expires_in'.`);
193
+ }
194
+ // Parse 'expires_in' as an integer
195
+ let expiresInInt;
196
+ try {
197
+ expiresInInt = parseInt(expiresInStr, 10);
198
+ if (isNaN(expiresInInt)) {
199
+ throw new Error(`'expires_in' is not a valid integer`);
200
+ }
201
+ }
202
+ catch (e) {
203
+ console.error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. 'expires_in': ${expiresInStr} is not a valid integer. Error: ${e}`);
204
+ throw new Error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. 'expires_in': ${expiresInStr} is not a valid integer. Error: ${e}`);
205
+ }
206
+ // Determine if the access token is valid based on 'expires_in'
207
+ return expiresInInt > 5;
208
+ }
209
+ catch (error) {
210
+ console.error(error);
211
+ throw error;
212
+ }
213
+ }
214
+ idTokenValid(idToken) {
215
+ try {
216
+ const parsed = this.parseJwt(idToken);
217
+ const currentTime = Math.ceil(Date.now() / 1000) + 5; // Convert current time to seconds since epoch
218
+ return parsed.exp && currentTime < parsed.exp;
219
+ }
220
+ catch (e) {
221
+ return false;
222
+ }
223
+ }
224
+ async rawLogoutGoogle(accessToken, tokenValid = null) {
225
+ if (tokenValid === null) {
226
+ tokenValid = await this.accessTokenIsValid(accessToken);
227
+ }
228
+ if (tokenValid === true) {
229
+ return new Promise((resolve, reject) => {
230
+ try {
231
+ google.accounts.oauth2.revoke(accessToken, async () => {
232
+ this.clearStateGoogle();
233
+ resolve();
234
+ });
235
+ }
236
+ catch (e) {
237
+ reject(e);
238
+ }
239
+ });
240
+ }
241
+ else {
242
+ this.clearStateGoogle();
243
+ return;
244
+ }
245
+ }
246
+ persistStateGoogle(accessToken, idToken) {
247
+ try {
248
+ window.localStorage.setItem(this.GOOGLE_STATE_KEY, JSON.stringify({ accessToken, idToken }));
249
+ }
250
+ catch (e) {
251
+ console.error('Cannot persist state google', e);
252
+ }
253
+ }
254
+ clearStateGoogle() {
255
+ try {
256
+ window.localStorage.removeItem(this.GOOGLE_STATE_KEY);
257
+ }
258
+ catch (e) {
259
+ console.error('Cannot clear state google', e);
260
+ }
261
+ }
262
+ getGoogleState() {
263
+ try {
264
+ const state = window.localStorage.getItem(this.GOOGLE_STATE_KEY);
265
+ if (!state)
266
+ return null;
267
+ const { accessToken, idToken } = JSON.parse(state);
268
+ return { accessToken, idToken };
269
+ }
270
+ catch (e) {
271
+ console.error('Cannot get state google', e);
272
+ return null;
273
+ }
274
+ }
275
+ async traditionalOAuth({ scopes, hostedDomain, nonce, }) {
276
+ const uniqueScopes = [...new Set([...(scopes || []), 'openid'])];
277
+ const params = new URLSearchParams(Object.assign(Object.assign({ client_id: this.clientId, redirect_uri: window.location.href, response_type: this.loginType === 'offline' ? 'code' : 'token id_token', scope: uniqueScopes.join(' ') }, (nonce && { nonce })), { include_granted_scopes: 'true', state: 'popup' }));
278
+ if (hostedDomain !== undefined) {
279
+ params.append('hd', hostedDomain);
280
+ }
281
+ const url = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
282
+ const width = 500;
283
+ const height = 600;
284
+ const left = window.screenX + (window.outerWidth - width) / 2;
285
+ const top = window.screenY + (window.outerHeight - height) / 2;
286
+ localStorage.setItem(BaseSocialLogin.OAUTH_STATE_KEY, 'true');
287
+ const popup = window.open(url, 'Google Sign In', `width=${width},height=${height},left=${left},top=${top},popup=1`);
288
+ // This may never return...
289
+ return new Promise((resolve, reject) => {
290
+ if (!popup) {
291
+ reject(new Error('Failed to open popup'));
292
+ return;
293
+ }
294
+ const handleMessage = (event) => {
295
+ var _a, _b, _c;
296
+ if (event.origin !== window.location.origin || ((_b = (_a = event.data) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.startsWith('angular')))
297
+ return;
298
+ if (((_c = event.data) === null || _c === void 0 ? void 0 : _c.type) === 'oauth-response') {
299
+ window.removeEventListener('message', handleMessage);
300
+ if (this.loginType === 'online') {
301
+ const { accessToken, idToken } = event.data;
302
+ if (accessToken && idToken) {
303
+ const profile = this.parseJwt(idToken);
304
+ this.persistStateGoogle(accessToken.token, idToken);
305
+ resolve({
306
+ provider: 'google',
307
+ result: {
308
+ accessToken: {
309
+ token: accessToken.token,
310
+ },
311
+ idToken,
312
+ profile: {
313
+ email: profile.email || null,
314
+ familyName: profile.family_name || null,
315
+ givenName: profile.given_name || null,
316
+ id: profile.sub || null,
317
+ name: profile.name || null,
318
+ imageUrl: profile.picture || null,
319
+ },
320
+ responseType: 'online',
321
+ },
322
+ });
323
+ }
324
+ }
325
+ else {
326
+ const { serverAuthCode } = event.data;
327
+ resolve({
328
+ provider: 'google',
329
+ result: {
330
+ responseType: 'offline',
331
+ serverAuthCode,
332
+ },
333
+ });
334
+ }
335
+ }
336
+ else {
337
+ reject(new Error('Login failed'));
338
+ }
339
+ };
340
+ window.addEventListener('message', handleMessage);
341
+ // Timeout after 5 minutes
342
+ setTimeout(() => {
343
+ window.removeEventListener('message', handleMessage);
344
+ popup.close();
345
+ reject(new Error('OAuth timeout'));
346
+ }, 300000);
347
+ });
348
+ }
349
+ }
350
+ //# sourceMappingURL=google-provider.js.map