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