@capgo/capacitor-social-login 8.2.25 → 8.3.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.
@@ -904,26 +904,106 @@ class OAuth2SocialLogin extends BaseSocialLogin {
904
904
  this.TOKENS_KEY_PREFIX = 'capgo_social_login_oauth2_tokens_';
905
905
  this.STATE_PREFIX = 'capgo_social_login_oauth2_state_';
906
906
  }
907
+ normalizeScopeValue(scope) {
908
+ if (!scope)
909
+ return '';
910
+ if (typeof scope === 'string')
911
+ return scope;
912
+ if (Array.isArray(scope))
913
+ return scope.filter(Boolean).join(' ');
914
+ return '';
915
+ }
916
+ normalizeConfig(providerId, config) {
917
+ var _a, _b, _c, _d, _e, _f, _g, _h;
918
+ const appId = (_a = config.appId) !== null && _a !== void 0 ? _a : config.clientId;
919
+ const authorizationBaseUrl = (_b = config.authorizationBaseUrl) !== null && _b !== void 0 ? _b : config.authorizationEndpoint;
920
+ const accessTokenEndpoint = (_c = config.accessTokenEndpoint) !== null && _c !== void 0 ? _c : config.tokenEndpoint;
921
+ const logoutUrl = (_d = config.logoutUrl) !== null && _d !== void 0 ? _d : config.endSessionEndpoint;
922
+ const scopeSource = (_e = config.scope) !== null && _e !== void 0 ? _e : config.scopes;
923
+ if (!appId) {
924
+ throw new Error(`OAuth2 provider '${providerId}' requires appId (or clientId).`);
925
+ }
926
+ if (!config.redirectUrl) {
927
+ throw new Error(`OAuth2 provider '${providerId}' requires redirectUrl.`);
928
+ }
929
+ if (!authorizationBaseUrl && !config.issuerUrl) {
930
+ throw new Error(`OAuth2 provider '${providerId}' requires authorizationBaseUrl (or authorizationEndpoint) or issuerUrl.`);
931
+ }
932
+ return {
933
+ appId,
934
+ issuerUrl: config.issuerUrl,
935
+ authorizationBaseUrl,
936
+ accessTokenEndpoint,
937
+ redirectUrl: config.redirectUrl,
938
+ resourceUrl: config.resourceUrl,
939
+ responseType: ((_f = config.responseType) !== null && _f !== void 0 ? _f : 'code'),
940
+ pkceEnabled: (_g = config.pkceEnabled) !== null && _g !== void 0 ? _g : true,
941
+ scope: this.normalizeScopeValue(scopeSource),
942
+ additionalParameters: config.additionalParameters,
943
+ loginHint: config.loginHint,
944
+ prompt: config.prompt,
945
+ additionalTokenParameters: config.additionalTokenParameters,
946
+ additionalResourceHeaders: config.additionalResourceHeaders,
947
+ logoutUrl,
948
+ postLogoutRedirectUrl: config.postLogoutRedirectUrl,
949
+ additionalLogoutParameters: config.additionalLogoutParameters,
950
+ logsEnabled: (_h = config.logsEnabled) !== null && _h !== void 0 ? _h : false,
951
+ };
952
+ }
953
+ async ensureDiscovered(providerId) {
954
+ const config = this.providers.get(providerId);
955
+ if (!(config === null || config === void 0 ? void 0 : config.issuerUrl))
956
+ return;
957
+ // Resolve endpoints lazily.
958
+ if (config.authorizationBaseUrl && config.accessTokenEndpoint)
959
+ return;
960
+ const issuer = config.issuerUrl.replace(/\/+$/, '');
961
+ const discoveryUrl = `${issuer}/.well-known/openid-configuration`;
962
+ const resp = await fetch(discoveryUrl);
963
+ if (!resp.ok) {
964
+ const text = await resp.text().catch(() => '');
965
+ throw new Error(`OAuth2 discovery failed (${resp.status}): ${text || discoveryUrl}`);
966
+ }
967
+ const payload = (await resp.json());
968
+ const authorizationEndpoint = payload['authorization_endpoint'];
969
+ const tokenEndpoint = payload['token_endpoint'];
970
+ const endSessionEndpoint = payload['end_session_endpoint'];
971
+ if (!config.authorizationBaseUrl && typeof authorizationEndpoint === 'string') {
972
+ config.authorizationBaseUrl = authorizationEndpoint;
973
+ }
974
+ if (!config.accessTokenEndpoint && typeof tokenEndpoint === 'string') {
975
+ config.accessTokenEndpoint = tokenEndpoint;
976
+ }
977
+ if (!config.logoutUrl && typeof endSessionEndpoint === 'string') {
978
+ config.logoutUrl = endSessionEndpoint;
979
+ }
980
+ if (config.logsEnabled) {
981
+ console.log(`[OAuth2:${providerId}] Discovery resolved`, {
982
+ authorizationBaseUrl: config.authorizationBaseUrl,
983
+ accessTokenEndpoint: config.accessTokenEndpoint,
984
+ logoutUrl: config.logoutUrl,
985
+ });
986
+ }
987
+ }
907
988
  /**
908
989
  * Initialize multiple OAuth2 providers
909
990
  */
910
991
  async initializeProviders(configs) {
911
- var _a, _b, _c, _d;
912
992
  for (const [providerId, config] of Object.entries(configs)) {
913
- if (!config.appId || !config.authorizationBaseUrl || !config.redirectUrl) {
914
- throw new Error(`OAuth2 provider '${providerId}' requires appId, authorizationBaseUrl, and redirectUrl`);
915
- }
916
- const internalConfig = Object.assign(Object.assign({}, config), { responseType: (_a = config.responseType) !== null && _a !== void 0 ? _a : 'code', pkceEnabled: (_b = config.pkceEnabled) !== null && _b !== void 0 ? _b : true, scope: (_c = config.scope) !== null && _c !== void 0 ? _c : '', logsEnabled: (_d = config.logsEnabled) !== null && _d !== void 0 ? _d : false });
993
+ const internalConfig = this.normalizeConfig(providerId, config);
917
994
  this.providers.set(providerId, internalConfig);
918
995
  if (internalConfig.logsEnabled) {
919
996
  console.log(`[OAuth2:${providerId}] Initialized with config:`, {
920
- appId: config.appId,
921
- authorizationBaseUrl: config.authorizationBaseUrl,
922
- redirectUrl: config.redirectUrl,
997
+ appId: internalConfig.appId,
998
+ issuerUrl: internalConfig.issuerUrl,
999
+ authorizationBaseUrl: internalConfig.authorizationBaseUrl,
1000
+ redirectUrl: internalConfig.redirectUrl,
923
1001
  responseType: internalConfig.responseType,
924
1002
  pkceEnabled: internalConfig.pkceEnabled,
925
1003
  });
926
1004
  }
1005
+ // Pre-resolve discovery on web if issuerUrl is provided.
1006
+ await this.ensureDiscovered(providerId);
927
1007
  }
928
1008
  }
929
1009
  getProvider(providerId) {
@@ -937,13 +1017,14 @@ class OAuth2SocialLogin extends BaseSocialLogin {
937
1017
  return `${this.TOKENS_KEY_PREFIX}${providerId}`;
938
1018
  }
939
1019
  async login(options) {
940
- var _a, _b, _c, _d;
1020
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
941
1021
  const { providerId } = options;
942
1022
  const config = this.getProvider(providerId);
1023
+ await this.ensureDiscovered(providerId);
943
1024
  const redirectUri = (_a = options.redirectUrl) !== null && _a !== void 0 ? _a : config.redirectUrl;
944
- const scope = (_b = options.scope) !== null && _b !== void 0 ? _b : config.scope;
945
- const state = (_c = options.state) !== null && _c !== void 0 ? _c : this.generateState();
946
- const codeVerifier = (_d = options.codeVerifier) !== null && _d !== void 0 ? _d : this.generateCodeVerifier();
1025
+ const scope = this.normalizeScopeValue((_c = (_b = options.scope) !== null && _b !== void 0 ? _b : options.scopes) !== null && _c !== void 0 ? _c : config.scope);
1026
+ const state = (_d = options.state) !== null && _d !== void 0 ? _d : this.generateState();
1027
+ const codeVerifier = (_e = options.codeVerifier) !== null && _e !== void 0 ? _e : this.generateCodeVerifier();
947
1028
  // Build authorization URL
948
1029
  const params = new URLSearchParams({
949
1030
  response_type: config.responseType,
@@ -954,21 +1035,25 @@ class OAuth2SocialLogin extends BaseSocialLogin {
954
1035
  if (scope) {
955
1036
  params.set('scope', scope);
956
1037
  }
1038
+ // Convenience OIDC options
1039
+ const mergedAdditionalParams = Object.assign(Object.assign({}, ((_f = config.additionalParameters) !== null && _f !== void 0 ? _f : {})), ((_g = options.additionalParameters) !== null && _g !== void 0 ? _g : {}));
1040
+ const loginHint = (_h = options.loginHint) !== null && _h !== void 0 ? _h : config.loginHint;
1041
+ const prompt = (_j = options.prompt) !== null && _j !== void 0 ? _j : config.prompt;
1042
+ if (loginHint && !('login_hint' in mergedAdditionalParams)) {
1043
+ mergedAdditionalParams.login_hint = loginHint;
1044
+ }
1045
+ if (prompt && !('prompt' in mergedAdditionalParams)) {
1046
+ mergedAdditionalParams.prompt = prompt;
1047
+ }
957
1048
  // Add PKCE for code flow
958
1049
  if (config.responseType === 'code' && config.pkceEnabled) {
959
1050
  const codeChallenge = await this.generateCodeChallenge(codeVerifier);
960
1051
  params.set('code_challenge', codeChallenge);
961
1052
  params.set('code_challenge_method', 'S256');
962
1053
  }
963
- // Add additional parameters from config
964
- if (config.additionalParameters) {
965
- for (const [key, value] of Object.entries(config.additionalParameters)) {
966
- params.set(key, value);
967
- }
968
- }
969
- // Add additional parameters from login options
970
- if (options.additionalParameters) {
971
- for (const [key, value] of Object.entries(options.additionalParameters)) {
1054
+ // Add merged additional parameters
1055
+ for (const [key, value] of Object.entries(mergedAdditionalParams)) {
1056
+ if (value !== undefined) {
972
1057
  params.set(key, value);
973
1058
  }
974
1059
  }
@@ -980,10 +1065,19 @@ class OAuth2SocialLogin extends BaseSocialLogin {
980
1065
  scope,
981
1066
  });
982
1067
  localStorage.setItem(BaseSocialLogin.OAUTH_STATE_KEY, JSON.stringify({ provider: 'oauth2', providerId, state }));
1068
+ if (!config.authorizationBaseUrl) {
1069
+ throw new Error(`OAuth2 provider '${providerId}' is missing authorizationBaseUrl (discovery may have failed).`);
1070
+ }
983
1071
  const authUrl = `${config.authorizationBaseUrl}?${params.toString()}`;
984
1072
  if (config.logsEnabled) {
985
1073
  console.log(`[OAuth2:${providerId}] Opening authorization URL:`, authUrl);
986
1074
  }
1075
+ if (options.flow === 'redirect') {
1076
+ // Trigger a full-page redirect. The promise will not resolve because the page navigates away.
1077
+ window.location.assign(authUrl);
1078
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1079
+ return new Promise(() => { });
1080
+ }
987
1081
  // Open popup window
988
1082
  const width = 500;
989
1083
  const height = 650;
@@ -1089,11 +1183,31 @@ class OAuth2SocialLogin extends BaseSocialLogin {
1089
1183
  });
1090
1184
  }
1091
1185
  async logout(providerId) {
1186
+ await this.ensureDiscovered(providerId);
1092
1187
  const config = this.providers.get(providerId);
1188
+ const stored = this.getStoredTokens(providerId);
1093
1189
  localStorage.removeItem(this.getTokensKey(providerId));
1094
- // If logout URL is configured, redirect to it
1190
+ // If logout URL is configured, build an end-session URL (OIDC) when possible.
1095
1191
  if (config === null || config === void 0 ? void 0 : config.logoutUrl) {
1096
- window.open(config.logoutUrl, '_blank');
1192
+ try {
1193
+ const url = new URL(config.logoutUrl);
1194
+ if (stored === null || stored === void 0 ? void 0 : stored.idToken) {
1195
+ url.searchParams.set('id_token_hint', stored.idToken);
1196
+ }
1197
+ const postLogout = config.postLogoutRedirectUrl;
1198
+ if (postLogout) {
1199
+ url.searchParams.set('post_logout_redirect_uri', postLogout);
1200
+ }
1201
+ if (config.additionalLogoutParameters) {
1202
+ for (const [k, v] of Object.entries(config.additionalLogoutParameters)) {
1203
+ url.searchParams.set(k, v);
1204
+ }
1205
+ }
1206
+ window.open(url.toString(), '_blank');
1207
+ }
1208
+ catch (_a) {
1209
+ window.open(config.logoutUrl, '_blank');
1210
+ }
1097
1211
  }
1098
1212
  }
1099
1213
  async isLoggedIn(providerId) {
@@ -1118,15 +1232,52 @@ class OAuth2SocialLogin extends BaseSocialLogin {
1118
1232
  };
1119
1233
  }
1120
1234
  async refresh(providerId) {
1121
- const tokens = this.getStoredTokens(providerId);
1122
- if (!(tokens === null || tokens === void 0 ? void 0 : tokens.refreshToken)) {
1235
+ await this.refreshToken(providerId);
1236
+ }
1237
+ async refreshToken(providerId, refreshToken, additionalParameters) {
1238
+ var _a, _b, _c, _d, _e, _f;
1239
+ await this.ensureDiscovered(providerId);
1240
+ const config = this.getProvider(providerId);
1241
+ const stored = this.getStoredTokens(providerId);
1242
+ const effectiveRefreshToken = refreshToken !== null && refreshToken !== void 0 ? refreshToken : stored === null || stored === void 0 ? void 0 : stored.refreshToken;
1243
+ if (!effectiveRefreshToken) {
1123
1244
  throw new Error(`No OAuth2 refresh token is available for provider '${providerId}'. Include offline_access scope to receive one.`);
1124
1245
  }
1125
- const config = this.getProvider(providerId);
1126
1246
  if (!config.accessTokenEndpoint) {
1127
1247
  throw new Error(`No accessTokenEndpoint configured for provider '${providerId}'.`);
1128
1248
  }
1129
- await this.refreshWithRefreshToken(providerId, tokens.refreshToken);
1249
+ const tokenResponse = await this.refreshWithRefreshToken(providerId, effectiveRefreshToken, additionalParameters);
1250
+ const expiresAt = tokenResponse.expires_in ? Date.now() + tokenResponse.expires_in * 1000 : Date.now() + 3600000;
1251
+ const scopeArray = (_c = (_b = (_a = tokenResponse.scope) === null || _a === void 0 ? void 0 : _a.split(' ').filter(Boolean)) !== null && _b !== void 0 ? _b : stored === null || stored === void 0 ? void 0 : stored.scope) !== null && _c !== void 0 ? _c : [];
1252
+ // Fetch resource data if configured
1253
+ let resourceData = null;
1254
+ if (config.resourceUrl) {
1255
+ resourceData = await this.fetchResource(providerId, tokenResponse.access_token);
1256
+ }
1257
+ const nextRefreshToken = (_d = tokenResponse.refresh_token) !== null && _d !== void 0 ? _d : effectiveRefreshToken;
1258
+ this.persistTokens(providerId, {
1259
+ accessToken: tokenResponse.access_token,
1260
+ refreshToken: nextRefreshToken,
1261
+ idToken: tokenResponse.id_token,
1262
+ expiresAt,
1263
+ scope: scopeArray,
1264
+ tokenType: tokenResponse.token_type,
1265
+ });
1266
+ return {
1267
+ providerId,
1268
+ accessToken: {
1269
+ token: tokenResponse.access_token,
1270
+ tokenType: tokenResponse.token_type,
1271
+ expires: new Date(expiresAt).toISOString(),
1272
+ refreshToken: nextRefreshToken,
1273
+ },
1274
+ idToken: (_e = tokenResponse.id_token) !== null && _e !== void 0 ? _e : null,
1275
+ refreshToken: nextRefreshToken !== null && nextRefreshToken !== void 0 ? nextRefreshToken : null,
1276
+ resourceData,
1277
+ scope: scopeArray,
1278
+ tokenType: tokenResponse.token_type,
1279
+ expiresIn: (_f = tokenResponse.expires_in) !== null && _f !== void 0 ? _f : null,
1280
+ };
1130
1281
  }
1131
1282
  async handleOAuthRedirect(url, expectedState) {
1132
1283
  var _a, _b, _c, _d, _e;
@@ -1147,6 +1298,7 @@ class OAuth2SocialLogin extends BaseSocialLogin {
1147
1298
  return { error: 'OAuth2 login session expired or state mismatch.' };
1148
1299
  }
1149
1300
  const { providerId } = pending;
1301
+ await this.ensureDiscovered(providerId);
1150
1302
  const config = this.providers.get(providerId);
1151
1303
  if (!config) {
1152
1304
  localStorage.removeItem(BaseSocialLogin.OAUTH_STATE_KEY);
@@ -1241,6 +1393,11 @@ class OAuth2SocialLogin extends BaseSocialLogin {
1241
1393
  if (config.pkceEnabled) {
1242
1394
  params.set('code_verifier', pending.codeVerifier);
1243
1395
  }
1396
+ if (config.additionalTokenParameters) {
1397
+ for (const [k, v] of Object.entries(config.additionalTokenParameters)) {
1398
+ params.set(k, v);
1399
+ }
1400
+ }
1244
1401
  if (config.logsEnabled) {
1245
1402
  console.log(`[OAuth2:${providerId}] Exchanging code at:`, config.accessTokenEndpoint);
1246
1403
  }
@@ -1257,8 +1414,7 @@ class OAuth2SocialLogin extends BaseSocialLogin {
1257
1414
  }
1258
1415
  return (await response.json());
1259
1416
  }
1260
- async refreshWithRefreshToken(providerId, refreshToken) {
1261
- var _a, _b, _c;
1417
+ async refreshWithRefreshToken(providerId, refreshToken, additionalParameters) {
1262
1418
  const config = this.getProvider(providerId);
1263
1419
  if (!config.accessTokenEndpoint) {
1264
1420
  throw new Error(`No accessTokenEndpoint configured for provider '${providerId}'.`);
@@ -1268,6 +1424,16 @@ class OAuth2SocialLogin extends BaseSocialLogin {
1268
1424
  refresh_token: refreshToken,
1269
1425
  client_id: config.appId,
1270
1426
  });
1427
+ if (config.additionalTokenParameters) {
1428
+ for (const [k, v] of Object.entries(config.additionalTokenParameters)) {
1429
+ params.set(k, v);
1430
+ }
1431
+ }
1432
+ if (additionalParameters) {
1433
+ for (const [k, v] of Object.entries(additionalParameters)) {
1434
+ params.set(k, v);
1435
+ }
1436
+ }
1271
1437
  const response = await fetch(config.accessTokenEndpoint, {
1272
1438
  method: 'POST',
1273
1439
  headers: {
@@ -1279,17 +1445,7 @@ class OAuth2SocialLogin extends BaseSocialLogin {
1279
1445
  const text = await response.text();
1280
1446
  throw new Error(`OAuth2 refresh failed (${response.status}): ${text}`);
1281
1447
  }
1282
- const tokens = (await response.json());
1283
- const expiresAt = tokens.expires_in ? Date.now() + tokens.expires_in * 1000 : Date.now() + 3600000;
1284
- const scopeArray = (_b = (_a = tokens.scope) === null || _a === void 0 ? void 0 : _a.split(' ').filter(Boolean)) !== null && _b !== void 0 ? _b : [];
1285
- this.persistTokens(providerId, {
1286
- accessToken: tokens.access_token,
1287
- refreshToken: (_c = tokens.refresh_token) !== null && _c !== void 0 ? _c : refreshToken,
1288
- idToken: tokens.id_token,
1289
- expiresAt,
1290
- scope: scopeArray,
1291
- tokenType: tokens.token_type,
1292
- });
1448
+ return (await response.json());
1293
1449
  }
1294
1450
  async fetchResource(providerId, accessToken) {
1295
1451
  const config = this.getProvider(providerId);
@@ -1366,6 +1522,37 @@ class OAuth2SocialLogin extends BaseSocialLogin {
1366
1522
  buffer.forEach((b) => (binary += String.fromCharCode(b)));
1367
1523
  return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
1368
1524
  }
1525
+ decodeIdToken(idToken) {
1526
+ const parts = idToken.split('.');
1527
+ if (parts.length < 2) {
1528
+ throw new Error('Invalid JWT: missing parts');
1529
+ }
1530
+ const payload = parts[1];
1531
+ const normalized = payload.replace(/-/g, '+').replace(/_/g, '/');
1532
+ const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4);
1533
+ const json = atob(padded);
1534
+ return JSON.parse(json);
1535
+ }
1536
+ getAccessTokenExpirationDate(providerId) {
1537
+ const tokens = this.getStoredTokens(providerId);
1538
+ if (!(tokens === null || tokens === void 0 ? void 0 : tokens.expiresAt))
1539
+ return { expirationDate: null };
1540
+ return { expirationDate: new Date(tokens.expiresAt).toISOString() };
1541
+ }
1542
+ isAccessTokenAvailable(providerId) {
1543
+ const tokens = this.getStoredTokens(providerId);
1544
+ return { isAvailable: !!(tokens === null || tokens === void 0 ? void 0 : tokens.accessToken) };
1545
+ }
1546
+ isAccessTokenExpired(providerId) {
1547
+ const tokens = this.getStoredTokens(providerId);
1548
+ if (!(tokens === null || tokens === void 0 ? void 0 : tokens.expiresAt))
1549
+ return { isExpired: true };
1550
+ return { isExpired: tokens.expiresAt <= Date.now() };
1551
+ }
1552
+ isRefreshTokenAvailable(providerId) {
1553
+ const tokens = this.getStoredTokens(providerId);
1554
+ return { isAvailable: !!(tokens === null || tokens === void 0 ? void 0 : tokens.refreshToken) };
1555
+ }
1369
1556
  }
1370
1557
 
1371
1558
  var __rest = (undefined && undefined.__rest) || function (s, e) {
@@ -1757,16 +1944,23 @@ class SocialLoginWeb extends core.WebPlugin {
1757
1944
  this.facebookProvider = new FacebookSocialLogin();
1758
1945
  this.twitterProvider = new TwitterSocialLogin();
1759
1946
  this.oauth2Provider = new OAuth2SocialLogin();
1760
- // Set up listener for OAuth redirects if we have a pending OAuth flow
1761
- if (localStorage.getItem(SocialLoginWeb.OAUTH_STATE_KEY)) {
1762
- console.log('OAUTH_STATE_KEY found');
1763
- this.handleOAuthRedirect().catch((error) => {
1947
+ // Auto-finish OAuth redirects only when running inside a popup window.
1948
+ // For redirect-based flows (full page navigation), the app should call `handleRedirectCallback()` explicitly.
1949
+ const hasPending = !!localStorage.getItem(SocialLoginWeb.OAUTH_STATE_KEY);
1950
+ const isPopup = !!window.opener || SocialLoginWeb.POPUP_WINDOW_NAMES.has(window.name);
1951
+ if (hasPending && isPopup) {
1952
+ this.finishOAuthRedirectInPopup().catch((error) => {
1764
1953
  console.error('Failed to finish OAuth redirect', error);
1765
- window.close();
1954
+ try {
1955
+ window.close();
1956
+ }
1957
+ catch (_a) {
1958
+ // ignore
1959
+ }
1766
1960
  });
1767
1961
  }
1768
1962
  }
1769
- async handleOAuthRedirect() {
1963
+ async parseRedirectResult() {
1770
1964
  var _a;
1771
1965
  const url = new URL(window.location.href);
1772
1966
  const stateRaw = localStorage.getItem(SocialLoginWeb.OAUTH_STATE_KEY);
@@ -1797,13 +1991,18 @@ class SocialLoginWeb extends core.WebPlugin {
1797
1991
  result = this.googleProvider.handleOAuthRedirect(url);
1798
1992
  break;
1799
1993
  }
1800
- if (!result) {
1994
+ return { provider, state, nonce, result };
1995
+ }
1996
+ async finishOAuthRedirectInPopup() {
1997
+ var _a;
1998
+ const parsed = await this.parseRedirectResult();
1999
+ const result = parsed.result;
2000
+ if (!result)
1801
2001
  return;
1802
- }
1803
2002
  // Build the message to send
1804
2003
  let message;
1805
2004
  if ('error' in result) {
1806
- const resolvedProvider = provider !== null && provider !== void 0 ? provider : null;
2005
+ const resolvedProvider = (_a = parsed.provider) !== null && _a !== void 0 ? _a : null;
1807
2006
  message = {
1808
2007
  type: 'oauth-error',
1809
2008
  provider: resolvedProvider,
@@ -1819,7 +2018,7 @@ class SocialLoginWeb extends core.WebPlugin {
1819
2018
  window.opener.postMessage(message, window.location.origin);
1820
2019
  }
1821
2020
  }
1822
- catch (_c) {
2021
+ catch (_b) {
1823
2022
  // Cross-origin error - window.opener may not be accessible
1824
2023
  console.log('postMessage to opener failed, using BroadcastChannel');
1825
2024
  }
@@ -1828,14 +2027,14 @@ class SocialLoginWeb extends core.WebPlugin {
1828
2027
  try {
1829
2028
  // Determine the channel name based on provider and state/nonce
1830
2029
  let channelName = null;
1831
- if (provider === 'oauth2' && state) {
1832
- channelName = `oauth2_${state}`;
2030
+ if (parsed.provider === 'oauth2' && parsed.state) {
2031
+ channelName = `oauth2_${parsed.state}`;
1833
2032
  }
1834
- else if (provider === 'twitter' && state) {
1835
- channelName = `twitter_oauth_${state}`;
2033
+ else if (parsed.provider === 'twitter' && parsed.state) {
2034
+ channelName = `twitter_oauth_${parsed.state}`;
1836
2035
  }
1837
- else if (provider === 'google' && nonce) {
1838
- channelName = `google_oauth_${nonce}`;
2036
+ else if (parsed.provider === 'google' && parsed.nonce) {
2037
+ channelName = `google_oauth_${parsed.nonce}`;
1839
2038
  }
1840
2039
  if (channelName) {
1841
2040
  const channel = new BroadcastChannel(channelName);
@@ -1843,7 +2042,7 @@ class SocialLoginWeb extends core.WebPlugin {
1843
2042
  channel.close();
1844
2043
  }
1845
2044
  }
1846
- catch (_d) {
2045
+ catch (_c) {
1847
2046
  // BroadcastChannel not supported or other error
1848
2047
  console.log('BroadcastChannel not available');
1849
2048
  }
@@ -1966,6 +2165,53 @@ class SocialLoginWeb extends core.WebPlugin {
1966
2165
  async providerSpecificCall(options) {
1967
2166
  throw new Error(`Provider specific call for ${options.call} is not implemented`);
1968
2167
  }
2168
+ async refreshToken(options) {
2169
+ if (options.provider !== 'oauth2') {
2170
+ throw new Error('refreshToken is only implemented for oauth2 on web');
2171
+ }
2172
+ return this.oauth2Provider.refreshToken(options.providerId, options.refreshToken, options.additionalParameters);
2173
+ }
2174
+ async handleRedirectCallback() {
2175
+ const parsed = await this.parseRedirectResult();
2176
+ const result = parsed.result;
2177
+ if (!result)
2178
+ return null;
2179
+ if ('error' in result) {
2180
+ throw new Error(result.error);
2181
+ }
2182
+ return result;
2183
+ }
2184
+ async decodeIdToken(options) {
2185
+ var _a;
2186
+ const token = (_a = options === null || options === void 0 ? void 0 : options.idToken) !== null && _a !== void 0 ? _a : options === null || options === void 0 ? void 0 : options.token;
2187
+ if (!token) {
2188
+ throw new Error('idToken (or token) is required');
2189
+ }
2190
+ const claims = this.oauth2Provider.decodeIdToken(token);
2191
+ return { claims };
2192
+ }
2193
+ async getAccessTokenExpirationDate(options) {
2194
+ if (typeof (options === null || options === void 0 ? void 0 : options.accessTokenExpirationDate) !== 'number') {
2195
+ throw new Error('accessTokenExpirationDate is required');
2196
+ }
2197
+ return { date: new Date(options.accessTokenExpirationDate).toISOString() };
2198
+ }
2199
+ async isAccessTokenAvailable(options) {
2200
+ var _a;
2201
+ const token = (_a = options === null || options === void 0 ? void 0 : options.accessToken) !== null && _a !== void 0 ? _a : null;
2202
+ return { isAvailable: typeof token === 'string' && token.length > 0 };
2203
+ }
2204
+ async isAccessTokenExpired(options) {
2205
+ if (typeof (options === null || options === void 0 ? void 0 : options.accessTokenExpirationDate) !== 'number') {
2206
+ throw new Error('accessTokenExpirationDate is required');
2207
+ }
2208
+ return { isExpired: options.accessTokenExpirationDate <= Date.now() };
2209
+ }
2210
+ async isRefreshTokenAvailable(options) {
2211
+ var _a;
2212
+ const token = (_a = options === null || options === void 0 ? void 0 : options.refreshToken) !== null && _a !== void 0 ? _a : null;
2213
+ return { isAvailable: typeof token === 'string' && token.length > 0 };
2214
+ }
1969
2215
  async getPluginVersion() {
1970
2216
  return { version: 'web' };
1971
2217
  }
@@ -2004,6 +2250,7 @@ class SocialLoginWeb extends core.WebPlugin {
2004
2250
  }
2005
2251
  }
2006
2252
  SocialLoginWeb.OAUTH_STATE_KEY = 'social_login_oauth_pending';
2253
+ SocialLoginWeb.POPUP_WINDOW_NAMES = new Set(['OAuth2Login', 'XLogin', 'Google Sign In', 'Authorization']);
2007
2254
 
2008
2255
  var web = /*#__PURE__*/Object.freeze({
2009
2256
  __proto__: null,