@nihplod/sso-sdk 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +69 -78
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +69 -78
- package/dist/index.mjs.map +1 -1
- package/dist/next/index.d.mts +50 -1
- package/dist/next/index.d.ts +50 -1
- package/dist/next/index.js +260 -56
- package/dist/next/index.js.map +1 -1
- package/dist/next/index.mjs +259 -56
- package/dist/next/index.mjs.map +1 -1
- package/dist/react/index.d.mts +7 -2
- package/dist/react/index.d.ts +7 -2
- package/dist/react/index.js +106 -96
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +106 -96
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -89,24 +89,6 @@ var SILENT_PROBE_KEY = "silent_probe";
|
|
|
89
89
|
function buildKey(base, clientId) {
|
|
90
90
|
return clientId ? `${base}:${clientId}` : base;
|
|
91
91
|
}
|
|
92
|
-
function createMemoryStorageAdapter() {
|
|
93
|
-
const store = /* @__PURE__ */ new Map();
|
|
94
|
-
return {
|
|
95
|
-
get(key) {
|
|
96
|
-
return store.get(key) ?? null;
|
|
97
|
-
},
|
|
98
|
-
set(key, value) {
|
|
99
|
-
store.set(key, value);
|
|
100
|
-
},
|
|
101
|
-
remove(key) {
|
|
102
|
-
store.delete(key);
|
|
103
|
-
},
|
|
104
|
-
keys() {
|
|
105
|
-
return [...store.keys()];
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
var memoryStorageAdapter = createMemoryStorageAdapter();
|
|
110
92
|
var localStorageAdapter = {
|
|
111
93
|
get(key) {
|
|
112
94
|
try {
|
|
@@ -428,7 +410,19 @@ async function fetchJwks(baseUrl, options = {}) {
|
|
|
428
410
|
return cachedJwks.jwks;
|
|
429
411
|
}
|
|
430
412
|
const discovery = await fetchDiscoveryDoc(baseUrl);
|
|
431
|
-
|
|
413
|
+
let jwksUri = `${baseUrl}/api/oauth/jwks`;
|
|
414
|
+
if (discovery?.jwks_uri) {
|
|
415
|
+
try {
|
|
416
|
+
if (new URL(discovery.jwks_uri).origin === new URL(baseUrl).origin) {
|
|
417
|
+
jwksUri = discovery.jwks_uri;
|
|
418
|
+
} else {
|
|
419
|
+
console.warn(
|
|
420
|
+
"[SSO SDK] Discovery \u7684 jwks_uri \u4E0E ssoBaseUrl \u4E0D\u540C\u6E90\uFF0C\u5DF2\u5FFD\u7565\u5E76\u4F7F\u7528\u9ED8\u8BA4 JWKS \u7AEF\u70B9"
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
} catch {
|
|
424
|
+
}
|
|
425
|
+
}
|
|
432
426
|
try {
|
|
433
427
|
const res = await fetch(jwksUri, {
|
|
434
428
|
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
@@ -619,11 +613,7 @@ function assertValidTokenResponse(data, requireRefreshToken) {
|
|
|
619
613
|
);
|
|
620
614
|
}
|
|
621
615
|
}
|
|
622
|
-
var SILENT_PROBE_ERRORS = /* @__PURE__ */ new Set([
|
|
623
|
-
"login_required",
|
|
624
|
-
"consent_required",
|
|
625
|
-
"interaction_required"
|
|
626
|
-
]);
|
|
616
|
+
var SILENT_PROBE_ERRORS = /* @__PURE__ */ new Set(["login_required", "consent_required", "interaction_required"]);
|
|
627
617
|
var _SsoClient = class _SsoClient {
|
|
628
618
|
constructor(config) {
|
|
629
619
|
this._discovery = null;
|
|
@@ -689,6 +679,22 @@ var _SsoClient = class _SsoClient {
|
|
|
689
679
|
if (!authorizationOk) bad.push("authorization_endpoint");
|
|
690
680
|
if (!sameOrigin(d.token_endpoint)) bad.push("token_endpoint");
|
|
691
681
|
if (!sameOrigin(d.userinfo_endpoint)) bad.push("userinfo_endpoint");
|
|
682
|
+
if (d.jwks_uri && !sameOrigin(d.jwks_uri)) bad.push("jwks_uri");
|
|
683
|
+
if (d.revocation_endpoint && !sameOrigin(d.revocation_endpoint)) {
|
|
684
|
+
bad.push("revocation_endpoint");
|
|
685
|
+
}
|
|
686
|
+
if (d.introspection_endpoint && !sameOrigin(d.introspection_endpoint)) {
|
|
687
|
+
bad.push("introspection_endpoint");
|
|
688
|
+
}
|
|
689
|
+
if (d.end_session_endpoint) {
|
|
690
|
+
try {
|
|
691
|
+
if (new URL(d.end_session_endpoint).origin !== publicOrigin) {
|
|
692
|
+
bad.push("end_session_endpoint");
|
|
693
|
+
}
|
|
694
|
+
} catch {
|
|
695
|
+
bad.push("end_session_endpoint");
|
|
696
|
+
}
|
|
697
|
+
}
|
|
692
698
|
if (bad.length > 0) {
|
|
693
699
|
if (!this._discoveryOriginWarned) {
|
|
694
700
|
this._discoveryOriginWarned = true;
|
|
@@ -714,16 +720,11 @@ var _SsoClient = class _SsoClient {
|
|
|
714
720
|
const url = `${this._serverBase}/api/oauth/.well-known/openid-configuration`;
|
|
715
721
|
try {
|
|
716
722
|
const controller = new AbortController();
|
|
717
|
-
const timeoutId = setTimeout(
|
|
718
|
-
() => controller.abort(),
|
|
719
|
-
_SsoClient.DISCOVERY_TIMEOUT_MS
|
|
720
|
-
);
|
|
723
|
+
const timeoutId = setTimeout(() => controller.abort(), _SsoClient.DISCOVERY_TIMEOUT_MS);
|
|
721
724
|
const res = await fetch(url, { signal: controller.signal });
|
|
722
725
|
clearTimeout(timeoutId);
|
|
723
726
|
if (!res.ok) {
|
|
724
|
-
console.warn(
|
|
725
|
-
`[SSO SDK] OIDC Discovery \u8BF7\u6C42\u5931\u8D25: HTTP ${res.status}, \u56DE\u9000\u5230\u9ED8\u8BA4\u7AEF\u70B9`
|
|
726
|
-
);
|
|
727
|
+
console.warn(`[SSO SDK] OIDC Discovery \u8BF7\u6C42\u5931\u8D25: HTTP ${res.status}, \u56DE\u9000\u5230\u9ED8\u8BA4\u7AEF\u70B9`);
|
|
727
728
|
return null;
|
|
728
729
|
}
|
|
729
730
|
const doc = await res.json();
|
|
@@ -938,10 +939,7 @@ var _SsoClient = class _SsoClient {
|
|
|
938
939
|
removeOAuthState(this.config.clientId);
|
|
939
940
|
removeOAuthNonce(this.config.clientId);
|
|
940
941
|
removePkceVerifier(`${this.config.clientId}_popup_nonce`);
|
|
941
|
-
throw new SsoError(
|
|
942
|
-
"popup_blocked",
|
|
943
|
-
"\u5F39\u7A97\u88AB\u6D4F\u89C8\u5668\u62E6\u622A\uFF0C\u8BF7\u5141\u8BB8\u5F39\u7A97\u540E\u91CD\u8BD5"
|
|
944
|
-
);
|
|
942
|
+
throw new SsoError("popup_blocked", "\u5F39\u7A97\u88AB\u6D4F\u89C8\u5668\u62E6\u622A\uFF0C\u8BF7\u5141\u8BB8\u5F39\u7A97\u540E\u91CD\u8BD5");
|
|
945
943
|
}
|
|
946
944
|
const redirectUriOrigin = new URL(this.config.redirectUri).origin;
|
|
947
945
|
try {
|
|
@@ -970,9 +968,7 @@ var _SsoClient = class _SsoClient {
|
|
|
970
968
|
}
|
|
971
969
|
this.handleCallback(event.data.callbackUrl).then((tokenData) => {
|
|
972
970
|
if (tokenData === null) {
|
|
973
|
-
reject(
|
|
974
|
-
new SsoError("not_authenticated", "SSO \u4F1A\u8BDD\u4E0D\u5B58\u5728\uFF08\u9759\u9ED8\u63A2\u6D4B\u65E0\u4F1A\u8BDD\uFF09")
|
|
975
|
-
);
|
|
971
|
+
reject(new SsoError("not_authenticated", "SSO \u4F1A\u8BDD\u4E0D\u5B58\u5728\uFF08\u9759\u9ED8\u63A2\u6D4B\u65E0\u4F1A\u8BDD\uFF09"));
|
|
976
972
|
return;
|
|
977
973
|
}
|
|
978
974
|
resolve(tokenData);
|
|
@@ -983,12 +979,7 @@ var _SsoClient = class _SsoClient {
|
|
|
983
979
|
if (!completed) {
|
|
984
980
|
completed = true;
|
|
985
981
|
cleanup();
|
|
986
|
-
reject(
|
|
987
|
-
new SsoError(
|
|
988
|
-
"popup_closed",
|
|
989
|
-
"\u767B\u5F55\u7A97\u53E3\u5DF2\u5173\u95ED"
|
|
990
|
-
)
|
|
991
|
-
);
|
|
982
|
+
reject(new SsoError("popup_closed", "\u767B\u5F55\u7A97\u53E3\u5DF2\u5173\u95ED"));
|
|
992
983
|
}
|
|
993
984
|
}
|
|
994
985
|
}, 500);
|
|
@@ -1055,18 +1046,24 @@ var _SsoClient = class _SsoClient {
|
|
|
1055
1046
|
removeOAuthNonce(this.config.clientId);
|
|
1056
1047
|
removePkceVerifier(this.config.clientId);
|
|
1057
1048
|
removeSilentProbe(this.config.clientId);
|
|
1058
|
-
throw new SsoError(
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1049
|
+
throw new SsoError("state_mismatch", "State \u53C2\u6570\u4E0D\u5339\u914D\uFF0C\u53EF\u80FD\u5B58\u5728 CSRF \u653B\u51FB");
|
|
1050
|
+
}
|
|
1051
|
+
const returnedIss = params.get("iss");
|
|
1052
|
+
if (returnedIss) {
|
|
1053
|
+
const discovery = await this._getDiscovery();
|
|
1054
|
+
const expectedIssuer = (discovery?.issuer || this.config.ssoBaseUrl).replace(/\/+$/, "");
|
|
1055
|
+
if (returnedIss.replace(/\/+$/, "") !== expectedIssuer) {
|
|
1056
|
+
removeOAuthState(this.config.clientId);
|
|
1057
|
+
removeOAuthNonce(this.config.clientId);
|
|
1058
|
+
removePkceVerifier(this.config.clientId);
|
|
1059
|
+
removeSilentProbe(this.config.clientId);
|
|
1060
|
+
throw new SsoError("issuer_mismatch", "\u6388\u6743\u54CD\u5E94 issuer \u4E0D\u5339\u914D\uFF0C\u53EF\u80FD\u5B58\u5728 IdP \u6DF7\u53E0\u653B\u51FB");
|
|
1061
|
+
}
|
|
1062
1062
|
}
|
|
1063
1063
|
const expectedNonce = getOAuthNonce(this.config.clientId) ?? void 0;
|
|
1064
1064
|
const verifier = getPkceVerifier(this.config.clientId);
|
|
1065
1065
|
if (!verifier) {
|
|
1066
|
-
throw new SsoError(
|
|
1067
|
-
"pkce_required",
|
|
1068
|
-
"code_verifier \u4E0D\u5B58\u5728\uFF08\u53EF\u80FD\u5DF2\u8FC7\u671F\u6216\u6765\u81EA\u5176\u4ED6\u6807\u7B7E\u9875\uFF09"
|
|
1069
|
-
);
|
|
1066
|
+
throw new SsoError("pkce_required", "code_verifier \u4E0D\u5B58\u5728\uFF08\u53EF\u80FD\u5DF2\u8FC7\u671F\u6216\u6765\u81EA\u5176\u4ED6\u6807\u7B7E\u9875\uFF09");
|
|
1070
1067
|
}
|
|
1071
1068
|
const tokenEndpoint = await this._getTokenEndpoint();
|
|
1072
1069
|
const body = new URLSearchParams();
|
|
@@ -1113,10 +1110,7 @@ var _SsoClient = class _SsoClient {
|
|
|
1113
1110
|
removePkceVerifier(this.config.clientId);
|
|
1114
1111
|
removeSilentProbe(this.config.clientId);
|
|
1115
1112
|
removeTokenData(this.config.clientId);
|
|
1116
|
-
throw new SsoError(
|
|
1117
|
-
"id_token_invalid",
|
|
1118
|
-
"Token \u54CD\u5E94\u7F3A\u5C11 id_token\uFF08scope \u542B openid \u65F6\u5FC5\u9700\uFF09"
|
|
1119
|
-
);
|
|
1113
|
+
throw new SsoError("id_token_invalid", "Token \u54CD\u5E94\u7F3A\u5C11 id_token\uFF08scope \u542B openid \u65F6\u5FC5\u9700\uFF09");
|
|
1120
1114
|
}
|
|
1121
1115
|
if (data.id_token) {
|
|
1122
1116
|
try {
|
|
@@ -1181,19 +1175,14 @@ var _SsoClient = class _SsoClient {
|
|
|
1181
1175
|
}
|
|
1182
1176
|
let res = null;
|
|
1183
1177
|
let lastErr;
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
break;
|
|
1193
|
-
} catch (err) {
|
|
1194
|
-
lastErr = err;
|
|
1195
|
-
if (attempt < 1) await new Promise((r) => setTimeout(r, 1e3));
|
|
1196
|
-
}
|
|
1178
|
+
try {
|
|
1179
|
+
res = await fetchWithTimeout(tokenEndpoint, {
|
|
1180
|
+
method: "POST",
|
|
1181
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1182
|
+
body: body.toString()
|
|
1183
|
+
});
|
|
1184
|
+
} catch (err) {
|
|
1185
|
+
lastErr = err;
|
|
1197
1186
|
}
|
|
1198
1187
|
if (lastErr || !res) {
|
|
1199
1188
|
throw new SsoError("network_error", "\u5237\u65B0 Token \u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25", lastErr);
|
|
@@ -1275,10 +1264,7 @@ var _SsoClient = class _SsoClient {
|
|
|
1275
1264
|
removeTokenData(this.config.clientId);
|
|
1276
1265
|
throw new SsoError("not_authenticated", "Token \u5DF2\u5931\u6548");
|
|
1277
1266
|
}
|
|
1278
|
-
throw new SsoError(
|
|
1279
|
-
"userinfo_failed",
|
|
1280
|
-
`\u83B7\u53D6\u7528\u6237\u4FE1\u606F\u5931\u8D25: HTTP ${res.status}`
|
|
1281
|
-
);
|
|
1267
|
+
throw new SsoError("userinfo_failed", `\u83B7\u53D6\u7528\u6237\u4FE1\u606F\u5931\u8D25: HTTP ${res.status}`);
|
|
1282
1268
|
}
|
|
1283
1269
|
return await res.json();
|
|
1284
1270
|
}
|
|
@@ -1338,7 +1324,7 @@ var _SsoClient = class _SsoClient {
|
|
|
1338
1324
|
if (this.config.clientSecret) {
|
|
1339
1325
|
revokeBody.set("client_secret", this.config.clientSecret);
|
|
1340
1326
|
}
|
|
1341
|
-
|
|
1327
|
+
const doRevoke = () => fetchWithTimeout(
|
|
1342
1328
|
revokeUrl,
|
|
1343
1329
|
{
|
|
1344
1330
|
method: "POST",
|
|
@@ -1347,6 +1333,14 @@ var _SsoClient = class _SsoClient {
|
|
|
1347
1333
|
},
|
|
1348
1334
|
REVOKE_TIMEOUT_MS
|
|
1349
1335
|
);
|
|
1336
|
+
let res = await doRevoke();
|
|
1337
|
+
if (!res.ok && (res.status >= 500 || res.status === 429)) {
|
|
1338
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
1339
|
+
res = await doRevoke();
|
|
1340
|
+
}
|
|
1341
|
+
if (!res.ok) {
|
|
1342
|
+
this.debugLog("logout: \u670D\u52A1\u7AEF\u64A4\u9500 refresh_token \u5931\u8D25", { status: res.status });
|
|
1343
|
+
}
|
|
1350
1344
|
} catch {
|
|
1351
1345
|
}
|
|
1352
1346
|
}
|
|
@@ -1357,10 +1351,7 @@ var _SsoClient = class _SsoClient {
|
|
|
1357
1351
|
logoutUrl.searchParams.set("client_id", this.config.clientId);
|
|
1358
1352
|
const postLogoutUri = this.config.postLogoutRedirectUri || this.config.redirectUri;
|
|
1359
1353
|
if (postLogoutUri) {
|
|
1360
|
-
logoutUrl.searchParams.set(
|
|
1361
|
-
"post_logout_redirect_uri",
|
|
1362
|
-
postLogoutUri
|
|
1363
|
-
);
|
|
1354
|
+
logoutUrl.searchParams.set("post_logout_redirect_uri", postLogoutUri);
|
|
1364
1355
|
}
|
|
1365
1356
|
if (idTokenHint) {
|
|
1366
1357
|
logoutUrl.searchParams.set("id_token_hint", idTokenHint);
|