@capgo/capacitor-social-login 7.2.2 → 7.4.5

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,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.result;
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-provider.js","sourceRoot":"","sources":["../../src/google-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseSocialLogin } from './base';\nimport type { GoogleLoginOptions, LoginResult, ProviderResponseMap, AuthorizationCode } from './definitions';\n\ndeclare const google: any;\n\nexport class GoogleSocialLogin extends BaseSocialLogin {\n private clientId: string | null = null;\n private hostedDomain?: string;\n private loginType: 'online' | 'offline' = 'online';\n private GOOGLE_TOKEN_REQUEST_URL = 'https://www.googleapis.com/oauth2/v3/tokeninfo';\n private readonly GOOGLE_STATE_KEY = 'capgo_social_login_google_state';\n\n async initialize(clientId: string | null, mode?: 'online' | 'offline', hostedDomain?: string | null): Promise<void> {\n this.clientId = clientId;\n if (mode) {\n this.loginType = mode;\n }\n this.hostedDomain = hostedDomain as string | undefined;\n }\n\n async login<T extends 'google'>(\n options: GoogleLoginOptions,\n ): Promise<{ provider: T; result: ProviderResponseMap[T] }> {\n if (!this.clientId) {\n throw new Error('Google Client ID not set. Call initialize() first.');\n }\n\n let scopes = options.scopes || [];\n\n if (scopes.length > 0) {\n // If scopes are provided, directly use the traditional OAuth flow\n if (!scopes.includes('https://www.googleapis.com/auth/userinfo.email')) {\n scopes.push('https://www.googleapis.com/auth/userinfo.email');\n }\n if (!scopes.includes('https://www.googleapis.com/auth/userinfo.profile')) {\n scopes.push('https://www.googleapis.com/auth/userinfo.profile');\n }\n if (!scopes.includes('openid')) {\n scopes.push('openid');\n }\n } else {\n scopes = [\n 'https://www.googleapis.com/auth/userinfo.email',\n 'https://www.googleapis.com/auth/userinfo.profile',\n 'openid',\n ];\n }\n\n const nonce = options.nonce || Math.random().toString(36).substring(2);\n\n // If scopes are provided, directly use the traditional OAuth flow\n return this.traditionalOAuth({\n scopes,\n nonce,\n hostedDomain: this.hostedDomain,\n });\n }\n\n async logout(): Promise<void> {\n if (this.loginType === 'offline') {\n return Promise.reject(\"Offline login doesn't store tokens. logout is not available\");\n }\n // eslint-disable-next-line\n const state = this.getGoogleState();\n if (!state) return;\n await this.rawLogoutGoogle(state.accessToken);\n }\n\n async isLoggedIn(): Promise<{ isLoggedIn: boolean }> {\n if (this.loginType === 'offline') {\n return Promise.reject(\"Offline login doesn't store tokens. isLoggedIn is not available\");\n }\n // eslint-disable-next-line\n const state = this.getGoogleState();\n if (!state) return { isLoggedIn: false };\n\n try {\n const isValidAccessToken = await this.accessTokenIsValid(state.accessToken);\n const isValidIdToken = this.idTokenValid(state.idToken);\n if (isValidAccessToken && isValidIdToken) {\n return { isLoggedIn: true };\n } else {\n try {\n await this.rawLogoutGoogle(state.accessToken, false);\n } catch (e) {\n console.error('Access token is not valid, but cannot logout', e);\n }\n return { isLoggedIn: false };\n }\n } catch (e) {\n return Promise.reject(e);\n }\n }\n\n async getAuthorizationCode(): Promise<AuthorizationCode> {\n if (this.loginType === 'offline') {\n return Promise.reject(\"Offline login doesn't store tokens. getAuthorizationCode is not available\");\n }\n // eslint-disable-next-line\n const state = this.getGoogleState();\n if (!state) throw new Error('No Google authorization code available');\n\n try {\n const isValidAccessToken = await this.accessTokenIsValid(state.accessToken);\n const isValidIdToken = this.idTokenValid(state.idToken);\n if (isValidAccessToken && isValidIdToken) {\n return { accessToken: state.accessToken, jwt: state.idToken };\n } else {\n try {\n await this.rawLogoutGoogle(state.accessToken, false);\n } catch (e) {\n console.error('Access token is not valid, but cannot logout', e);\n }\n throw new Error('No Google authorization code available');\n }\n } catch (e) {\n return Promise.reject(e);\n }\n }\n\n async refresh(): Promise<void> {\n // For Google, we can prompt for re-authentication\n return Promise.reject('Not implemented');\n }\n\n handleOAuthRedirect(url: URL): LoginResult | null {\n const paramsRaw = url.searchParams;\n const code = paramsRaw.get('code');\n\n if (code && paramsRaw.has('scope')) {\n return {\n provider: 'google',\n result: {\n serverAuthCode: code,\n responseType: 'offline',\n },\n };\n }\n\n const hash = url.hash.substring(1);\n console.log('handleOAuthRedirect', url.hash);\n if (!hash) return null;\n console.log('handleOAuthRedirect ok');\n\n const params = new URLSearchParams(hash);\n const accessToken = params.get('access_token');\n const idToken = params.get('id_token');\n\n if (accessToken && idToken) {\n localStorage.removeItem(BaseSocialLogin.OAUTH_STATE_KEY);\n const profile = this.parseJwt(idToken);\n return {\n provider: 'google',\n result: {\n accessToken: {\n token: accessToken,\n },\n idToken,\n profile: {\n email: profile.email || null,\n familyName: profile.family_name || null,\n givenName: profile.given_name || null,\n id: profile.sub || null,\n name: profile.name || null,\n imageUrl: profile.picture || null,\n },\n responseType: 'online',\n },\n };\n }\n return null;\n }\n\n private async accessTokenIsValid(accessToken: string): Promise<boolean> {\n const url = `${this.GOOGLE_TOKEN_REQUEST_URL}?access_token=${encodeURIComponent(accessToken)}`;\n\n try {\n // Make the GET request using fetch\n const response = await fetch(url);\n\n // Check if the response is successful\n if (!response.ok) {\n console.log(\n `Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response not successful. Status code: ${response.status}. Assuming that the token is not valid`,\n );\n return false;\n }\n\n // Get the response body as text\n const responseBody = await response.text();\n\n if (!responseBody) {\n console.error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is null`);\n throw new Error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is null`);\n }\n\n // Parse the response body as JSON\n let jsonObject: any;\n try {\n jsonObject = JSON.parse(responseBody);\n } catch (e) {\n console.error(\n `Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is not valid JSON. Error: ${e}`,\n );\n throw new Error(\n `Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is not valid JSON. Error: ${e}`,\n );\n }\n\n // Extract the 'expires_in' field\n const expiresInStr = jsonObject['expires_in'];\n\n if (expiresInStr === undefined || expiresInStr === null) {\n console.error(\n `Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response JSON does not include 'expires_in'.`,\n );\n throw new Error(\n `Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response JSON does not include 'expires_in'.`,\n );\n }\n\n // Parse 'expires_in' as an integer\n let expiresInInt: number;\n try {\n expiresInInt = parseInt(expiresInStr, 10);\n if (isNaN(expiresInInt)) {\n throw new Error(`'expires_in' is not a valid integer`);\n }\n } catch (e) {\n console.error(\n `Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. 'expires_in': ${expiresInStr} is not a valid integer. Error: ${e}`,\n );\n throw new Error(\n `Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. 'expires_in': ${expiresInStr} is not a valid integer. Error: ${e}`,\n );\n }\n\n // Determine if the access token is valid based on 'expires_in'\n return expiresInInt > 5;\n } catch (error) {\n console.error(error);\n throw error;\n }\n }\n\n private idTokenValid(idToken: string): boolean {\n try {\n const parsed = this.parseJwt(idToken);\n const currentTime = Math.ceil(Date.now() / 1000) + 5; // Convert current time to seconds since epoch\n return parsed.exp && currentTime < parsed.exp;\n } catch (e) {\n return false;\n }\n }\n\n private async rawLogoutGoogle(accessToken: string, tokenValid: boolean | null = null) {\n if (tokenValid === null) {\n tokenValid = await this.accessTokenIsValid(accessToken);\n }\n\n if (tokenValid === true) {\n return new Promise<void>((resolve, reject) => {\n try {\n google.accounts.oauth2.revoke(accessToken, async () => {\n this.clearStateGoogle();\n resolve();\n });\n } catch (e) {\n reject(e);\n }\n });\n } else {\n this.clearStateGoogle();\n return;\n }\n }\n\n private persistStateGoogle(accessToken: string, idToken: string) {\n try {\n window.localStorage.setItem(this.GOOGLE_STATE_KEY, JSON.stringify({ accessToken, idToken }));\n } catch (e) {\n console.error('Cannot persist state google', e);\n }\n }\n\n private clearStateGoogle() {\n try {\n window.localStorage.removeItem(this.GOOGLE_STATE_KEY);\n } catch (e) {\n console.error('Cannot clear state google', e);\n }\n }\n\n private getGoogleState(): { accessToken: string; idToken: string } | null {\n try {\n const state = window.localStorage.getItem(this.GOOGLE_STATE_KEY);\n if (!state) return null;\n const { accessToken, idToken } = JSON.parse(state);\n return { accessToken, idToken };\n } catch (e) {\n console.error('Cannot get state google', e);\n return null;\n }\n }\n\n private async traditionalOAuth<T extends 'google'>({\n scopes,\n hostedDomain,\n nonce,\n }: GoogleLoginOptions & { hostedDomain?: string }): Promise<{ provider: T; result: ProviderResponseMap[T] }> {\n const uniqueScopes = [...new Set([...(scopes || []), 'openid'])];\n\n const params = new URLSearchParams({\n client_id: this.clientId!,\n redirect_uri: window.location.href,\n response_type: this.loginType === 'offline' ? 'code' : 'token id_token',\n scope: uniqueScopes.join(' '),\n ...(nonce && { nonce }),\n include_granted_scopes: 'true',\n state: 'popup',\n });\n if (hostedDomain !== undefined) {\n params.append('hd', hostedDomain);\n }\n\n const url = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;\n const width = 500;\n const height = 600;\n const left = window.screenX + (window.outerWidth - width) / 2;\n const top = window.screenY + (window.outerHeight - height) / 2;\n localStorage.setItem(BaseSocialLogin.OAUTH_STATE_KEY, 'true');\n const popup = window.open(url, 'Google Sign In', `width=${width},height=${height},left=${left},top=${top},popup=1`);\n\n // This may never return...\n return new Promise((resolve, reject) => {\n if (!popup) {\n reject(new Error('Failed to open popup'));\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n if (event.origin !== window.location.origin || event.data?.source?.startsWith('angular')) return;\n\n if (event.data?.type === 'oauth-response') {\n window.removeEventListener('message', handleMessage);\n\n if (this.loginType === 'online') {\n const { accessToken, idToken } = event.data;\n if (accessToken && idToken) {\n const profile = this.parseJwt(idToken);\n this.persistStateGoogle(accessToken.token, idToken);\n resolve({\n provider: 'google' as T,\n result: {\n accessToken: {\n token: accessToken.token,\n },\n idToken,\n profile: {\n email: profile.email || null,\n familyName: profile.family_name || null,\n givenName: profile.given_name || null,\n id: profile.sub || null,\n name: profile.name || null,\n imageUrl: profile.picture || null,\n },\n responseType: 'online',\n },\n });\n }\n } else {\n const { serverAuthCode } = event.data.result as {\n serverAuthCode: string;\n };\n resolve({\n provider: 'google' as T,\n result: {\n responseType: 'offline',\n serverAuthCode,\n },\n });\n }\n } else {\n reject(new Error('Login failed'));\n }\n };\n\n window.addEventListener('message', handleMessage);\n\n // Timeout after 5 minutes\n setTimeout(() => {\n window.removeEventListener('message', handleMessage);\n popup.close();\n reject(new Error('OAuth timeout'));\n }, 300000);\n });\n }\n}\n"]}
package/dist/esm/web.d.ts CHANGED
@@ -1,18 +1,10 @@
1
1
  import { WebPlugin } from '@capacitor/core';
2
- import type { SocialLoginPlugin, InitializeOptions, LoginOptions, AuthorizationCode, isLoggedInOptions, AuthorizationCodeOptions, ProviderResponseMap } from './definitions';
2
+ import type { SocialLoginPlugin, InitializeOptions, LoginOptions, AuthorizationCode, AuthorizationCodeOptions, isLoggedInOptions, ProviderResponseMap } from './definitions';
3
3
  export declare class SocialLoginWeb extends WebPlugin implements SocialLoginPlugin {
4
4
  private static readonly OAUTH_STATE_KEY;
5
- private googleClientId;
6
- private googleHostedDomain?;
7
- private appleClientId;
8
- private appleRedirectUrl;
9
- private googleScriptLoaded;
10
- private googleLoginType;
11
- private appleScriptLoaded;
12
- private appleScriptUrl;
13
- private GOOGLE_TOKEN_REQUEST_URL;
14
- private facebookAppId;
15
- private facebookScriptLoaded;
5
+ private googleProvider;
6
+ private appleProvider;
7
+ private facebookProvider;
16
8
  constructor();
17
9
  private handleOAuthRedirect;
18
10
  initialize(options: InitializeOptions): Promise<void>;
@@ -25,23 +17,9 @@ export declare class SocialLoginWeb extends WebPlugin implements SocialLoginPlug
25
17
  logout(options: {
26
18
  provider: 'apple' | 'google' | 'facebook';
27
19
  }): Promise<void>;
28
- private accessTokenIsValid;
29
- private idTokenValid;
30
- private rawLogoutGoogle;
31
20
  isLoggedIn(options: isLoggedInOptions): Promise<{
32
21
  isLoggedIn: boolean;
33
22
  }>;
34
23
  getAuthorizationCode(options: AuthorizationCodeOptions): Promise<AuthorizationCode>;
35
24
  refresh(options: LoginOptions): Promise<void>;
36
- private loginWithGoogle;
37
- private parseJwt;
38
- private loadGoogleScript;
39
- private loginWithApple;
40
- private loadAppleScript;
41
- private persistStateGoogle;
42
- private clearStateGoogle;
43
- private getGoogleState;
44
- private loadFacebookScript;
45
- private loginWithFacebook;
46
- private fallbackToTraditionalOAuth;
47
25
  }