@nihplod/sso-sdk 1.0.1 → 1.2.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/README.md +92 -9
- package/dist/index.d.mts +136 -13
- package/dist/index.d.ts +136 -13
- package/dist/index.js +475 -78
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +467 -77
- package/dist/index.mjs.map +1 -1
- package/dist/next/index.d.mts +54 -6
- package/dist/next/index.d.ts +54 -6
- package/dist/next/index.js +355 -85
- package/dist/next/index.js.map +1 -1
- package/dist/next/index.mjs +351 -84
- package/dist/next/index.mjs.map +1 -1
- package/dist/react/index.d.mts +175 -14
- package/dist/react/index.d.ts +175 -14
- package/dist/react/index.js +627 -151
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +630 -155
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/next/index.js
CHANGED
|
@@ -21,6 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var next_exports = {};
|
|
22
22
|
__export(next_exports, {
|
|
23
23
|
DEFAULT_ACCESS_TOKEN_COOKIE_NAME: () => DEFAULT_ACCESS_TOKEN_COOKIE_NAME,
|
|
24
|
+
DEFAULT_ID_TOKEN_COOKIE_NAME: () => DEFAULT_ID_TOKEN_COOKIE_NAME,
|
|
25
|
+
DEFAULT_LOGOUT_STATE_COOKIE_NAME: () => DEFAULT_LOGOUT_STATE_COOKIE_NAME,
|
|
24
26
|
DEFAULT_REFRESH_TOKEN_COOKIE_NAME: () => DEFAULT_REFRESH_TOKEN_COOKIE_NAME,
|
|
25
27
|
DEFAULT_RETURN_COOKIE_NAME: () => DEFAULT_RETURN_COOKIE_NAME,
|
|
26
28
|
DEFAULT_STATE_COOKIE_NAME: () => DEFAULT_STATE_COOKIE_NAME,
|
|
@@ -29,7 +31,8 @@ __export(next_exports, {
|
|
|
29
31
|
createLogoutRouteHandler: () => createLogoutRouteHandler,
|
|
30
32
|
createSsoMiddleware: () => createSsoMiddleware,
|
|
31
33
|
getHostCookieOptions: () => getHostCookieOptions,
|
|
32
|
-
getSecureCookieOptions: () => getSecureCookieOptions
|
|
34
|
+
getSecureCookieOptions: () => getSecureCookieOptions,
|
|
35
|
+
toInsecureCookieName: () => toInsecureCookieName
|
|
33
36
|
});
|
|
34
37
|
module.exports = __toCommonJS(next_exports);
|
|
35
38
|
|
|
@@ -43,19 +46,36 @@ var DEFAULT_ID_TOKEN_COOKIE_NAME = "__Host-nihplod_sso_id";
|
|
|
43
46
|
var DEFAULT_STATE_COOKIE_NAME = "__Host-nihplod_sso_state";
|
|
44
47
|
var DEFAULT_RETURN_COOKIE_NAME = "__Host-nihplod_sso_return";
|
|
45
48
|
var DEFAULT_VERIFIER_COOKIE_NAME = "__Secure-nihplod_sso_verifier";
|
|
46
|
-
|
|
49
|
+
var DEFAULT_LOGOUT_STATE_COOKIE_NAME = "__Host-nihplod_sso_logout_state";
|
|
50
|
+
function toInsecureCookieName(name) {
|
|
51
|
+
return name.replace(/^__(Host|Secure)-/, "");
|
|
52
|
+
}
|
|
53
|
+
function resolveInsecureLocalDev(enabled, ssoBaseUrl) {
|
|
54
|
+
if (!enabled) return false;
|
|
55
|
+
if (process.env.NODE_ENV === "production" && /^https:\/\//i.test(ssoBaseUrl)) {
|
|
56
|
+
console.warn(
|
|
57
|
+
"[SSO SDK] insecureLocalDev=true \u5DF2\u88AB\u5FFD\u7565\uFF1A\u5F53\u524D\u4E3A\u751F\u4EA7\u73AF\u5883\uFF08NODE_ENV=production\uFF09\u4E14 ssoBaseUrl \u4F7F\u7528 HTTPS\uFF0CCookie \u4ECD\u4FDD\u6301 Secure \u5C5E\u6027\u4E0E __Host-/__Secure- \u524D\u7F00\u3002\u8BF7\u4ECE\u751F\u4EA7\u914D\u7F6E\u4E2D\u79FB\u9664\u8BE5\u5F00\u5173\u3002"
|
|
58
|
+
);
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
console.warn(
|
|
62
|
+
"[SSO SDK] insecureLocalDev=true\uFF1ACookie \u7684 Secure \u5C5E\u6027\u5DF2\u5173\u95ED\u4E14\u53BB\u9664 __Host-/__Secure- \u524D\u7F00\u3002\u4EC5\u9650 http://localhost \u672C\u5730\u5F00\u53D1\u4F7F\u7528\uFF0C\u751F\u4EA7\u73AF\u5883\u5FC5\u987B\u79FB\u9664\u8BE5\u914D\u7F6E\uFF08\u751F\u4EA7\u5FC5\u987B\u7528 HTTPS\uFF09\u3002"
|
|
63
|
+
);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
function getHostCookieOptions(maxAge, secure = true) {
|
|
47
67
|
return {
|
|
48
68
|
httpOnly: true,
|
|
49
|
-
secure
|
|
69
|
+
secure,
|
|
50
70
|
sameSite: "lax",
|
|
51
71
|
path: "/",
|
|
52
72
|
...maxAge !== void 0 ? { maxAge } : {}
|
|
53
73
|
};
|
|
54
74
|
}
|
|
55
|
-
function getSecureCookieOptions(maxAge, path = "/") {
|
|
75
|
+
function getSecureCookieOptions(maxAge, path = "/", secure = true) {
|
|
56
76
|
return {
|
|
57
77
|
httpOnly: true,
|
|
58
|
-
secure
|
|
78
|
+
secure,
|
|
59
79
|
sameSite: "lax",
|
|
60
80
|
path,
|
|
61
81
|
...maxAge !== void 0 ? { maxAge } : {}
|
|
@@ -96,7 +116,43 @@ function matchesPath(pathname, paths) {
|
|
|
96
116
|
return false;
|
|
97
117
|
});
|
|
98
118
|
}
|
|
119
|
+
var introspectionCache = /* @__PURE__ */ new Map();
|
|
120
|
+
var INTROSPECT_CACHE_TTL_MS = 3e4;
|
|
121
|
+
var INTROSPECT_CACHE_MAX_ENTRIES = 500;
|
|
122
|
+
async function introspectCacheKey(token, clientId) {
|
|
123
|
+
const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(token));
|
|
124
|
+
const hex = Array.from(new Uint8Array(hash)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
125
|
+
return `${hex}|${clientId}`;
|
|
126
|
+
}
|
|
127
|
+
function introspectCacheGet(key) {
|
|
128
|
+
const entry = introspectionCache.get(key);
|
|
129
|
+
if (!entry) return null;
|
|
130
|
+
if (entry.until <= Date.now()) {
|
|
131
|
+
introspectionCache.delete(key);
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
introspectionCache.delete(key);
|
|
135
|
+
introspectionCache.set(key, entry);
|
|
136
|
+
return entry;
|
|
137
|
+
}
|
|
138
|
+
function introspectCacheSet(key, active) {
|
|
139
|
+
const now = Date.now();
|
|
140
|
+
for (const [k, v] of introspectionCache) {
|
|
141
|
+
if (v.until <= now) introspectionCache.delete(k);
|
|
142
|
+
}
|
|
143
|
+
while (introspectionCache.size >= INTROSPECT_CACHE_MAX_ENTRIES) {
|
|
144
|
+
const oldest = introspectionCache.keys().next();
|
|
145
|
+
if (oldest.done) break;
|
|
146
|
+
introspectionCache.delete(oldest.value);
|
|
147
|
+
}
|
|
148
|
+
introspectionCache.set(key, { active, until: now + INTROSPECT_CACHE_TTL_MS });
|
|
149
|
+
}
|
|
99
150
|
async function introspectAccessToken(token, ssoBaseUrl, clientId, clientSecret) {
|
|
151
|
+
const cacheKey = await introspectCacheKey(token, clientId);
|
|
152
|
+
const cached = introspectCacheGet(cacheKey);
|
|
153
|
+
if (cached) {
|
|
154
|
+
return cached.active;
|
|
155
|
+
}
|
|
100
156
|
try {
|
|
101
157
|
const body = new URLSearchParams({
|
|
102
158
|
token,
|
|
@@ -111,9 +167,17 @@ async function introspectAccessToken(token, ssoBaseUrl, clientId, clientSecret)
|
|
|
111
167
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
112
168
|
body: body.toString()
|
|
113
169
|
});
|
|
114
|
-
if (!res.ok)
|
|
170
|
+
if (!res.ok) {
|
|
171
|
+
if (res.status !== 401 && res.status !== 403) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
introspectCacheSet(cacheKey, false);
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
115
177
|
const data = await res.json();
|
|
116
|
-
|
|
178
|
+
const active = data.active === true;
|
|
179
|
+
introspectCacheSet(cacheKey, active);
|
|
180
|
+
return active;
|
|
117
181
|
} catch {
|
|
118
182
|
return false;
|
|
119
183
|
}
|
|
@@ -128,12 +192,28 @@ function createSsoMiddleware(config) {
|
|
|
128
192
|
publicPaths = [],
|
|
129
193
|
callbackPath = "/api/auth/callback",
|
|
130
194
|
ssoCookieName = "__Host-user_token",
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
returnUrlCookieName = DEFAULT_RETURN_COOKIE_NAME,
|
|
134
|
-
verifierCookieName = DEFAULT_VERIFIER_COOKIE_NAME
|
|
195
|
+
validateSsoCookie = true,
|
|
196
|
+
insecureLocalDev: insecureLocalDevOpt = false
|
|
135
197
|
} = config;
|
|
198
|
+
const insecureLocalDev = resolveInsecureLocalDev(insecureLocalDevOpt, ssoBaseUrl);
|
|
199
|
+
const secureCookies = !insecureLocalDev;
|
|
200
|
+
const accessTokenCookieName = insecureLocalDev ? toInsecureCookieName(config.accessTokenCookieName ?? DEFAULT_ACCESS_TOKEN_COOKIE_NAME) : config.accessTokenCookieName ?? DEFAULT_ACCESS_TOKEN_COOKIE_NAME;
|
|
201
|
+
const stateCookieName = insecureLocalDev ? toInsecureCookieName(config.stateCookieName ?? DEFAULT_STATE_COOKIE_NAME) : config.stateCookieName ?? DEFAULT_STATE_COOKIE_NAME;
|
|
202
|
+
const returnUrlCookieName = insecureLocalDev ? toInsecureCookieName(config.returnUrlCookieName ?? DEFAULT_RETURN_COOKIE_NAME) : config.returnUrlCookieName ?? DEFAULT_RETURN_COOKIE_NAME;
|
|
203
|
+
const verifierCookieName = insecureLocalDev ? toInsecureCookieName(config.verifierCookieName ?? DEFAULT_VERIFIER_COOKIE_NAME) : config.verifierCookieName ?? DEFAULT_VERIFIER_COOKIE_NAME;
|
|
136
204
|
const normalizedBase = ssoBaseUrl.replace(/\/+$/, "");
|
|
205
|
+
if (process.env.NODE_ENV !== "production") {
|
|
206
|
+
if (!validateSsoCookie) {
|
|
207
|
+
console.warn(
|
|
208
|
+
"[SSO SDK] validateSsoCookie=false\uFF1A\u4E2D\u95F4\u4EF6\u4EC5\u68C0\u67E5 Cookie \u5B58\u5728\u6027\uFF0C\u53EF\u80FD\u653E\u884C\u5DF2\u5931\u6548\u7684\u4F1A\u8BDD\u3002\u4E2D\u95F4\u4EF6\u53EA\u662F UX \u5C42\uFF0C\u654F\u611F\u6570\u636E\u7684\u9274\u6743\u5FC5\u987B\u5728 Route Handler / Server Component \u4E2D\u5B8C\u6210\u3002"
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
if (!clientSecret) {
|
|
212
|
+
console.warn(
|
|
213
|
+
"[SSO SDK] \u672A\u914D\u7F6E clientSecret\uFF08Public Client \u6A21\u5F0F\uFF09\uFF1Aintrospection \u65E0\u5BA2\u6237\u7AEF\u8BA4\u8BC1\uFF0C\u4E2D\u95F4\u4EF6\u5224\u5B9A\u7ED3\u679C\u4EC5\u4F5C UX \u53C2\u8003\u3002Confidential Client\uFF08BFF\uFF09\u8BF7\u914D\u7F6E clientSecret\u3002"
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
137
217
|
return async function ssoMiddleware(request) {
|
|
138
218
|
const { pathname } = request.nextUrl;
|
|
139
219
|
if (pathname.startsWith("/_next/") || pathname.startsWith("/favicon.ico") || pathname.match(/\.(ico|png|jpg|jpeg|svg|css|js|woff2?)$/)) {
|
|
@@ -148,7 +228,19 @@ function createSsoMiddleware(config) {
|
|
|
148
228
|
}
|
|
149
229
|
const ssoSession = request.cookies.get(ssoCookieName);
|
|
150
230
|
if (ssoSession?.value) {
|
|
151
|
-
|
|
231
|
+
if (validateSsoCookie) {
|
|
232
|
+
const tokenActive = await introspectAccessToken(
|
|
233
|
+
ssoSession.value,
|
|
234
|
+
normalizedBase,
|
|
235
|
+
clientId,
|
|
236
|
+
clientSecret
|
|
237
|
+
);
|
|
238
|
+
if (tokenActive) {
|
|
239
|
+
return import_server.NextResponse.next();
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
return import_server.NextResponse.next();
|
|
243
|
+
}
|
|
152
244
|
}
|
|
153
245
|
const accessTokenCookie = request.cookies.get(accessTokenCookieName);
|
|
154
246
|
if (accessTokenCookie?.value) {
|
|
@@ -176,11 +268,12 @@ function createSsoMiddleware(config) {
|
|
|
176
268
|
const loginUrl = new URL("/api/oauth/authorize", normalizedBase);
|
|
177
269
|
loginUrl.search = authorizeParams.toString();
|
|
178
270
|
const response = import_server.NextResponse.redirect(loginUrl);
|
|
179
|
-
response.cookies.set(stateCookieName, state, getHostCookieOptions(600));
|
|
180
|
-
response.cookies.set(verifierCookieName, verifier, getSecureCookieOptions(600, callbackPath));
|
|
181
|
-
|
|
271
|
+
response.cookies.set(stateCookieName, state, getHostCookieOptions(600, secureCookies));
|
|
272
|
+
response.cookies.set(verifierCookieName, verifier, getSecureCookieOptions(600, callbackPath, secureCookies));
|
|
273
|
+
const safeReturnUrl = (request.nextUrl.pathname + request.nextUrl.search).slice(0, 2048);
|
|
274
|
+
response.cookies.set(returnUrlCookieName, safeReturnUrl, getHostCookieOptions(600, secureCookies));
|
|
182
275
|
if (accessTokenCookie?.value) {
|
|
183
|
-
response.cookies.set(accessTokenCookieName, "", getHostCookieOptions(0));
|
|
276
|
+
response.cookies.set(accessTokenCookieName, "", getHostCookieOptions(0, secureCookies));
|
|
184
277
|
}
|
|
185
278
|
return response;
|
|
186
279
|
};
|
|
@@ -188,8 +281,22 @@ function createSsoMiddleware(config) {
|
|
|
188
281
|
|
|
189
282
|
// src/next/callback.ts
|
|
190
283
|
var import_server2 = require("next/server");
|
|
284
|
+
|
|
285
|
+
// src/core/errors.ts
|
|
286
|
+
var SsoError = class extends Error {
|
|
287
|
+
constructor(code, description, cause) {
|
|
288
|
+
super(`[SSO SDK] ${code}: ${description}`);
|
|
289
|
+
this.name = "SsoError";
|
|
290
|
+
this.code = code;
|
|
291
|
+
this.description = description;
|
|
292
|
+
this.cause = cause;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
// src/core/security.ts
|
|
191
297
|
function isTrustedReturnUrl(url, currentOrigin) {
|
|
192
298
|
if (!url) return false;
|
|
299
|
+
if (url.includes("\\")) return false;
|
|
193
300
|
if (url.startsWith("/") && !url.startsWith("//")) return true;
|
|
194
301
|
try {
|
|
195
302
|
return new URL(url).origin === currentOrigin;
|
|
@@ -197,6 +304,23 @@ function isTrustedReturnUrl(url, currentOrigin) {
|
|
|
197
304
|
return false;
|
|
198
305
|
}
|
|
199
306
|
}
|
|
307
|
+
function timingSafeEqualString(a, b) {
|
|
308
|
+
const ba = new TextEncoder().encode(a);
|
|
309
|
+
const bb = new TextEncoder().encode(b);
|
|
310
|
+
if (ba.length === 0 || bb.length === 0) return ba.length === bb.length;
|
|
311
|
+
const len = Math.max(ba.length, bb.length);
|
|
312
|
+
let diff = ba.length ^ bb.length;
|
|
313
|
+
for (let i = 0; i < len; i++) {
|
|
314
|
+
diff |= ba[i % ba.length] ^ bb[i % bb.length];
|
|
315
|
+
}
|
|
316
|
+
return diff === 0;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/core/id-token.ts
|
|
320
|
+
var _crypto = typeof crypto !== "undefined" && crypto.subtle ? crypto : null;
|
|
321
|
+
function getCrypto() {
|
|
322
|
+
return _crypto ?? null;
|
|
323
|
+
}
|
|
200
324
|
function base64UrlDecode(input) {
|
|
201
325
|
const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
202
326
|
const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
|
|
@@ -227,11 +351,40 @@ function decodeJwtHeader(token) {
|
|
|
227
351
|
return null;
|
|
228
352
|
}
|
|
229
353
|
}
|
|
230
|
-
|
|
354
|
+
function normalizeIssuer(url) {
|
|
355
|
+
return url.replace(/\/+$/, "");
|
|
356
|
+
}
|
|
357
|
+
var cachedJwks = null;
|
|
358
|
+
var cachedDiscovery = null;
|
|
359
|
+
var JWKS_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
360
|
+
async function fetchDiscoveryDoc(baseUrl) {
|
|
361
|
+
const now = Date.now();
|
|
362
|
+
if (cachedDiscovery && cachedDiscovery.baseUrl === baseUrl && now - cachedDiscovery.fetchedAt < JWKS_CACHE_TTL_MS) {
|
|
363
|
+
return cachedDiscovery.doc;
|
|
364
|
+
}
|
|
365
|
+
try {
|
|
366
|
+
const res = await fetch(`${baseUrl}/api/oauth/.well-known/openid-configuration`);
|
|
367
|
+
const doc = res.ok ? await res.json() : null;
|
|
368
|
+
cachedDiscovery = { baseUrl, doc, fetchedAt: now };
|
|
369
|
+
return doc;
|
|
370
|
+
} catch {
|
|
371
|
+
cachedDiscovery = { baseUrl, doc: null, fetchedAt: now };
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
async function fetchJwks(baseUrl, options = {}) {
|
|
376
|
+
const now = Date.now();
|
|
377
|
+
if (!options.forceRefresh && cachedJwks && cachedJwks.baseUrl === baseUrl && now - cachedJwks.fetchedAt < JWKS_CACHE_TTL_MS) {
|
|
378
|
+
return cachedJwks.jwks;
|
|
379
|
+
}
|
|
380
|
+
const discovery = await fetchDiscoveryDoc(baseUrl);
|
|
381
|
+
const jwksUri = discovery?.jwks_uri || `${baseUrl}/api/oauth/jwks`;
|
|
231
382
|
try {
|
|
232
|
-
const res = await fetch(
|
|
383
|
+
const res = await fetch(jwksUri, options.forceRefresh ? { cache: "no-cache" } : void 0);
|
|
233
384
|
if (!res.ok) return null;
|
|
234
|
-
|
|
385
|
+
const jwks = await res.json();
|
|
386
|
+
cachedJwks = { baseUrl, jwks, fetchedAt: now };
|
|
387
|
+
return jwks;
|
|
235
388
|
} catch {
|
|
236
389
|
return null;
|
|
237
390
|
}
|
|
@@ -240,7 +393,9 @@ async function verifyRs256Signature(token, jwk) {
|
|
|
240
393
|
try {
|
|
241
394
|
const [headerB64, payloadB64, signature] = token.split(".");
|
|
242
395
|
if (!signature || !jwk.n || !jwk.e) return false;
|
|
243
|
-
const
|
|
396
|
+
const c = getCrypto();
|
|
397
|
+
if (!c) return false;
|
|
398
|
+
const cryptoKey = await c.subtle.importKey(
|
|
244
399
|
"jwk",
|
|
245
400
|
{ kty: "RSA", n: jwk.n, e: jwk.e, alg: "RS256", ext: false },
|
|
246
401
|
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
|
|
@@ -249,7 +404,7 @@ async function verifyRs256Signature(token, jwk) {
|
|
|
249
404
|
);
|
|
250
405
|
const signatureBytes = base64UrlDecode(signature);
|
|
251
406
|
const data = new TextEncoder().encode(`${headerB64}.${payloadB64}`);
|
|
252
|
-
return await
|
|
407
|
+
return await c.subtle.verify(
|
|
253
408
|
"RSASSA-PKCS1-v1_5",
|
|
254
409
|
cryptoKey,
|
|
255
410
|
signatureBytes,
|
|
@@ -260,10 +415,9 @@ async function verifyRs256Signature(token, jwk) {
|
|
|
260
415
|
}
|
|
261
416
|
}
|
|
262
417
|
async function computeAtHash(accessToken) {
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
);
|
|
418
|
+
const c = getCrypto();
|
|
419
|
+
if (!c) return "";
|
|
420
|
+
const hash = await c.subtle.digest("SHA-256", new TextEncoder().encode(accessToken));
|
|
267
421
|
const bytes = new Uint8Array(hash);
|
|
268
422
|
const half = bytes.slice(0, bytes.length / 2);
|
|
269
423
|
let binary = "";
|
|
@@ -272,54 +426,101 @@ async function computeAtHash(accessToken) {
|
|
|
272
426
|
}
|
|
273
427
|
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
274
428
|
}
|
|
275
|
-
async function validateIdToken(idToken, accessToken, expectedIssuer, expectedClientId) {
|
|
429
|
+
async function validateIdToken(idToken, accessToken, expectedIssuer, expectedClientId, options = {}) {
|
|
430
|
+
const { rejectHs256WhenRs256Available = true } = options;
|
|
276
431
|
const header = decodeJwtHeader(idToken);
|
|
277
|
-
if (!header)
|
|
432
|
+
if (!header) {
|
|
433
|
+
throw new SsoError("id_token_invalid", "ID Token \u683C\u5F0F\u9519\u8BEF");
|
|
434
|
+
}
|
|
278
435
|
const alg = header.alg;
|
|
279
436
|
if (typeof alg !== "string" || alg !== "RS256" && alg !== "HS256") {
|
|
280
|
-
throw new
|
|
437
|
+
throw new SsoError("id_token_unsupported_alg", `\u4E0D\u652F\u6301\u7684 ID Token \u7B7E\u540D\u7B97\u6CD5: ${alg}`);
|
|
281
438
|
}
|
|
439
|
+
const baseUrl = normalizeIssuer(expectedIssuer);
|
|
440
|
+
const discovery = await fetchDiscoveryDoc(baseUrl);
|
|
441
|
+
const normalizedIssuer = normalizeIssuer(discovery?.issuer || baseUrl);
|
|
282
442
|
if (alg === "RS256") {
|
|
283
|
-
const jwks = await fetchJwks(
|
|
284
|
-
if (!jwks)
|
|
443
|
+
const jwks = await fetchJwks(baseUrl);
|
|
444
|
+
if (!jwks) {
|
|
445
|
+
throw new SsoError("id_token_invalid_signature", "\u65E0\u6CD5\u83B7\u53D6 JWKS \u9A8C\u8BC1 ID Token \u7B7E\u540D");
|
|
446
|
+
}
|
|
285
447
|
const kid = typeof header.kid === "string" ? header.kid : void 0;
|
|
286
|
-
const
|
|
448
|
+
const matchCandidates = (set) => set.keys.filter(
|
|
287
449
|
(k) => k.kty === "RSA" && k.alg === "RS256" && k.use === "sig" && (kid ? k.kid === kid : true)
|
|
288
450
|
);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
451
|
+
const verifyAny = async (keys) => {
|
|
452
|
+
for (const key of keys) {
|
|
453
|
+
if (await verifyRs256Signature(idToken, key)) return true;
|
|
454
|
+
}
|
|
455
|
+
return false;
|
|
456
|
+
};
|
|
457
|
+
let candidates = matchCandidates(jwks);
|
|
458
|
+
let validSig = candidates.length > 0 ? await verifyAny(candidates) : false;
|
|
459
|
+
if (candidates.length === 0 || !validSig) {
|
|
460
|
+
const freshJwks = await fetchJwks(baseUrl, { forceRefresh: true });
|
|
461
|
+
if (freshJwks) {
|
|
462
|
+
candidates = matchCandidates(freshJwks);
|
|
463
|
+
validSig = candidates.length > 0 ? await verifyAny(candidates) : false;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (candidates.length === 0) {
|
|
467
|
+
throw new SsoError("id_token_invalid_signature", "JWKS \u4E2D\u672A\u627E\u5230\u5339\u914D\u7684 RS256 \u516C\u94A5");
|
|
468
|
+
}
|
|
469
|
+
if (!validSig) {
|
|
470
|
+
throw new SsoError("id_token_invalid_signature", "ID Token \u7B7E\u540D\u9A8C\u8BC1\u5931\u8D25");
|
|
471
|
+
}
|
|
292
472
|
}
|
|
293
473
|
if (alg === "HS256") {
|
|
294
|
-
|
|
295
|
-
|
|
474
|
+
if (rejectHs256WhenRs256Available) {
|
|
475
|
+
const jwks = await fetchJwks(baseUrl);
|
|
476
|
+
const hasRs256 = jwks?.keys?.some((k) => k.alg === "RS256" && k.use === "sig");
|
|
477
|
+
if (hasRs256) {
|
|
478
|
+
throw new SsoError("id_token_unsupported_alg", "SSO \u4E2D\u5FC3\u5DF2\u914D\u7F6E RS256\uFF0C\u62D2\u7EDD HS256 ID Token");
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
throw new SsoError(
|
|
482
|
+
"id_token_hs256_unsupported",
|
|
483
|
+
"ID Token \u4F7F\u7528 HS256 \u5BF9\u79F0\u7B7E\u540D\uFF0CSDK \u65E0\u6CD5\u5B89\u5168\u9A8C\u8BC1\u3002\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u5728 SSO \u4E3B\u7AD9\u914D\u7F6E RS256 \u5BC6\u94A5\u5BF9\uFF08JWT_ID_TOKEN_PRIVATE_KEY / JWT_ID_TOKEN_PUBLIC_KEY\uFF09\u540E\u91CD\u65B0\u7B7E\u53D1\u3002"
|
|
296
484
|
);
|
|
297
485
|
}
|
|
298
486
|
const payload = decodeJwtPayload(idToken);
|
|
299
|
-
if (!payload)
|
|
300
|
-
|
|
301
|
-
|
|
487
|
+
if (!payload) {
|
|
488
|
+
throw new SsoError("id_token_invalid", "ID Token payload \u89E3\u6790\u5931\u8D25");
|
|
489
|
+
}
|
|
490
|
+
const tokenIssuer = typeof payload.iss === "string" ? normalizeIssuer(payload.iss) : "";
|
|
302
491
|
if (tokenIssuer !== normalizedIssuer) {
|
|
303
|
-
throw new
|
|
492
|
+
throw new SsoError("id_token_issuer_mismatch", "ID Token issuer \u4E0D\u5339\u914D");
|
|
304
493
|
}
|
|
305
494
|
const aud = payload.aud;
|
|
306
|
-
const
|
|
307
|
-
if (!
|
|
308
|
-
throw new
|
|
495
|
+
const audList = Array.isArray(aud) ? aud : typeof aud === "string" ? [aud] : [];
|
|
496
|
+
if (!audList.includes(expectedClientId)) {
|
|
497
|
+
throw new SsoError("id_token_audience_mismatch", "ID Token audience \u4E0D\u5339\u914D");
|
|
498
|
+
}
|
|
499
|
+
if (audList.length > 1 && payload.azp !== expectedClientId) {
|
|
500
|
+
throw new SsoError("id_token_audience_mismatch", "ID Token \u591A audience \u65F6 azp \u5FC5\u987B\u4E3A\u5F53\u524D client");
|
|
309
501
|
}
|
|
310
|
-
if (typeof payload.exp
|
|
311
|
-
throw new
|
|
502
|
+
if (typeof payload.exp !== "number") {
|
|
503
|
+
throw new SsoError("id_token_invalid", "ID Token \u7F3A\u5C11 exp \u58F0\u660E");
|
|
504
|
+
}
|
|
505
|
+
if (Date.now() >= payload.exp * 1e3 + 6e4) {
|
|
506
|
+
throw new SsoError("id_token_expired", "ID Token \u5DF2\u8FC7\u671F");
|
|
507
|
+
}
|
|
508
|
+
if (typeof payload.iat === "number" && payload.iat * 1e3 > Date.now() + 6e4) {
|
|
509
|
+
throw new SsoError("id_token_invalid", "ID Token iat \u5728\u672A\u6765\uFF0C\u7591\u4F3C\u4F2A\u9020\u6216\u65F6\u949F\u5F02\u5E38");
|
|
312
510
|
}
|
|
313
511
|
if (typeof payload.sub !== "string" || !payload.sub) {
|
|
314
|
-
throw new
|
|
512
|
+
throw new SsoError("id_token_missing_sub", "ID Token \u7F3A\u5C11 sub");
|
|
315
513
|
}
|
|
316
514
|
if (typeof payload.at_hash === "string" && payload.at_hash) {
|
|
317
515
|
const actual = await computeAtHash(accessToken);
|
|
318
|
-
if (actual
|
|
319
|
-
throw new
|
|
516
|
+
if (!timingSafeEqualString(actual, payload.at_hash)) {
|
|
517
|
+
throw new SsoError("id_token_at_hash_mismatch", "ID Token at_hash \u4E0D\u5339\u914D");
|
|
320
518
|
}
|
|
321
519
|
}
|
|
520
|
+
return { sub: payload.sub };
|
|
322
521
|
}
|
|
522
|
+
|
|
523
|
+
// src/next/callback.ts
|
|
323
524
|
function createCallbackRouteHandler(config) {
|
|
324
525
|
const {
|
|
325
526
|
clientId,
|
|
@@ -327,13 +528,17 @@ function createCallbackRouteHandler(config) {
|
|
|
327
528
|
redirectUri,
|
|
328
529
|
clientSecret,
|
|
329
530
|
defaultReturnPath = "/",
|
|
330
|
-
|
|
331
|
-
refreshTokenCookieName = DEFAULT_REFRESH_TOKEN_COOKIE_NAME,
|
|
332
|
-
idTokenCookieName = DEFAULT_ID_TOKEN_COOKIE_NAME,
|
|
333
|
-
stateCookieName = DEFAULT_STATE_COOKIE_NAME,
|
|
334
|
-
returnUrlCookieName = DEFAULT_RETURN_COOKIE_NAME,
|
|
335
|
-
verifierCookieName = DEFAULT_VERIFIER_COOKIE_NAME
|
|
531
|
+
insecureLocalDev: insecureLocalDevOpt = false
|
|
336
532
|
} = config;
|
|
533
|
+
const insecureLocalDev = resolveInsecureLocalDev(insecureLocalDevOpt, ssoBaseUrl);
|
|
534
|
+
const secureCookies = !insecureLocalDev;
|
|
535
|
+
const pickName = (explicit, fallback) => insecureLocalDev ? toInsecureCookieName(explicit ?? fallback) : explicit ?? fallback;
|
|
536
|
+
const accessTokenCookieName = pickName(config.accessTokenCookieName, DEFAULT_ACCESS_TOKEN_COOKIE_NAME);
|
|
537
|
+
const refreshTokenCookieName = pickName(config.refreshTokenCookieName, DEFAULT_REFRESH_TOKEN_COOKIE_NAME);
|
|
538
|
+
const idTokenCookieName = pickName(config.idTokenCookieName, DEFAULT_ID_TOKEN_COOKIE_NAME);
|
|
539
|
+
const stateCookieName = pickName(config.stateCookieName, DEFAULT_STATE_COOKIE_NAME);
|
|
540
|
+
const returnUrlCookieName = pickName(config.returnUrlCookieName, DEFAULT_RETURN_COOKIE_NAME);
|
|
541
|
+
const verifierCookieName = pickName(config.verifierCookieName, DEFAULT_VERIFIER_COOKIE_NAME);
|
|
337
542
|
const normalizedBase = ssoBaseUrl.replace(/\/+$/, "");
|
|
338
543
|
return async function GET(request) {
|
|
339
544
|
const { searchParams } = request.nextUrl;
|
|
@@ -395,7 +600,7 @@ function createCallbackRouteHandler(config) {
|
|
|
395
600
|
if (clientSecret) {
|
|
396
601
|
body.set("client_secret", clientSecret);
|
|
397
602
|
}
|
|
398
|
-
let res;
|
|
603
|
+
let res = null;
|
|
399
604
|
let lastError;
|
|
400
605
|
const maxRetries = 1;
|
|
401
606
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
@@ -441,6 +646,15 @@ function createCallbackRouteHandler(config) {
|
|
|
441
646
|
);
|
|
442
647
|
}
|
|
443
648
|
const tokenData = await res.json();
|
|
649
|
+
if (!tokenData.access_token || !tokenData.refresh_token) {
|
|
650
|
+
return import_server2.NextResponse.json(
|
|
651
|
+
{
|
|
652
|
+
error: "server_error",
|
|
653
|
+
error_description: "Token \u54CD\u5E94\u7F3A\u5C11 access_token \u6216 refresh_token"
|
|
654
|
+
},
|
|
655
|
+
{ status: 502 }
|
|
656
|
+
);
|
|
657
|
+
}
|
|
444
658
|
if (tokenData.id_token) {
|
|
445
659
|
try {
|
|
446
660
|
await validateIdToken(
|
|
@@ -463,21 +677,36 @@ function createCallbackRouteHandler(config) {
|
|
|
463
677
|
const returnUrl = isTrustedReturnUrl(rawReturnUrl, request.nextUrl.origin) ? rawReturnUrl : "/";
|
|
464
678
|
const response = import_server2.NextResponse.redirect(new URL(returnUrl, request.url));
|
|
465
679
|
response.cookies.set(accessTokenCookieName, tokenData.access_token, {
|
|
466
|
-
...getHostCookieOptions(tokenData.expires_in)
|
|
680
|
+
...getHostCookieOptions(tokenData.expires_in, secureCookies)
|
|
467
681
|
});
|
|
468
682
|
const refreshMaxAge = tokenData.refresh_expires_in != null ? tokenData.refresh_expires_in : 30 * 24 * 60 * 60;
|
|
469
683
|
response.cookies.set(refreshTokenCookieName, tokenData.refresh_token, {
|
|
470
|
-
...getHostCookieOptions(refreshMaxAge)
|
|
684
|
+
...getHostCookieOptions(refreshMaxAge, secureCookies)
|
|
471
685
|
});
|
|
472
686
|
if (tokenData.id_token) {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
687
|
+
let idTokenMaxAge = 3600;
|
|
688
|
+
try {
|
|
689
|
+
const parts = tokenData.id_token.split(".");
|
|
690
|
+
if (parts.length === 3) {
|
|
691
|
+
const payload = JSON.parse(
|
|
692
|
+
Buffer.from(parts[1].replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf8")
|
|
693
|
+
);
|
|
694
|
+
if (payload.exp && typeof payload.exp === "number") {
|
|
695
|
+
idTokenMaxAge = payload.exp - Math.floor(Date.now() / 1e3);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
} catch {
|
|
699
|
+
}
|
|
700
|
+
if (idTokenMaxAge > 0) {
|
|
701
|
+
response.cookies.set(idTokenCookieName, tokenData.id_token, {
|
|
702
|
+
...getHostCookieOptions(idTokenMaxAge, secureCookies)
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
response.cookies.set(stateCookieName, "", getHostCookieOptions(0, secureCookies));
|
|
707
|
+
response.cookies.set(returnUrlCookieName, "", getHostCookieOptions(0, secureCookies));
|
|
708
|
+
response.cookies.set(verifierCookieName, "", getSecureCookieOptions(0, "/", secureCookies));
|
|
709
|
+
response.cookies.set(verifierCookieName, "", getSecureCookieOptions(0, request.nextUrl.pathname, secureCookies));
|
|
481
710
|
return response;
|
|
482
711
|
};
|
|
483
712
|
}
|
|
@@ -485,9 +714,9 @@ function createCallbackRouteHandler(config) {
|
|
|
485
714
|
// src/next/logout.ts
|
|
486
715
|
var import_server3 = require("next/server");
|
|
487
716
|
async function fetchDiscovery(ssoBaseUrl) {
|
|
717
|
+
const controller = new AbortController();
|
|
718
|
+
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
488
719
|
try {
|
|
489
|
-
const controller = new AbortController();
|
|
490
|
-
setTimeout(() => controller.abort(), 5e3);
|
|
491
720
|
const res = await fetch(
|
|
492
721
|
`${ssoBaseUrl}/api/oauth/.well-known/openid-configuration`,
|
|
493
722
|
{ signal: controller.signal }
|
|
@@ -496,7 +725,23 @@ async function fetchDiscovery(ssoBaseUrl) {
|
|
|
496
725
|
return await res.json();
|
|
497
726
|
} catch {
|
|
498
727
|
return null;
|
|
728
|
+
} finally {
|
|
729
|
+
clearTimeout(timeoutId);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
function generateRandomString2(length) {
|
|
733
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
|
|
734
|
+
const maxValid = Math.floor(256 / chars.length) * chars.length;
|
|
735
|
+
let result = "";
|
|
736
|
+
while (result.length < length) {
|
|
737
|
+
const array = new Uint8Array(length * 2);
|
|
738
|
+
crypto.getRandomValues(array);
|
|
739
|
+
for (let i = 0; i < array.length && result.length < length; i++) {
|
|
740
|
+
if (array[i] >= maxValid) continue;
|
|
741
|
+
result += chars[array[i] % chars.length];
|
|
742
|
+
}
|
|
499
743
|
}
|
|
744
|
+
return result;
|
|
500
745
|
}
|
|
501
746
|
function createLogoutRouteHandler(config) {
|
|
502
747
|
const {
|
|
@@ -506,16 +751,34 @@ function createLogoutRouteHandler(config) {
|
|
|
506
751
|
clientSecret,
|
|
507
752
|
postLogoutRedirectUri = new URL(redirectUri).origin + "/",
|
|
508
753
|
redirectToSso = true,
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
idTokenCookieName = DEFAULT_ID_TOKEN_COOKIE_NAME,
|
|
512
|
-
stateCookieName = DEFAULT_STATE_COOKIE_NAME,
|
|
513
|
-
returnUrlCookieName = DEFAULT_RETURN_COOKIE_NAME,
|
|
514
|
-
verifierCookieName = DEFAULT_VERIFIER_COOKIE_NAME,
|
|
515
|
-
callbackPath = "/api/auth/callback"
|
|
754
|
+
callbackPath = "/api/auth/callback",
|
|
755
|
+
insecureLocalDev: insecureLocalDevOpt = false
|
|
516
756
|
} = config;
|
|
757
|
+
const insecureLocalDev = resolveInsecureLocalDev(insecureLocalDevOpt, ssoBaseUrl);
|
|
758
|
+
const secureCookies = !insecureLocalDev;
|
|
759
|
+
const pickName = (explicit, fallback) => insecureLocalDev ? toInsecureCookieName(explicit ?? fallback) : explicit ?? fallback;
|
|
760
|
+
const accessTokenCookieName = pickName(config.accessTokenCookieName, DEFAULT_ACCESS_TOKEN_COOKIE_NAME);
|
|
761
|
+
const refreshTokenCookieName = pickName(config.refreshTokenCookieName, DEFAULT_REFRESH_TOKEN_COOKIE_NAME);
|
|
762
|
+
const idTokenCookieName = pickName(config.idTokenCookieName, DEFAULT_ID_TOKEN_COOKIE_NAME);
|
|
763
|
+
const stateCookieName = pickName(config.stateCookieName, DEFAULT_STATE_COOKIE_NAME);
|
|
764
|
+
const returnUrlCookieName = pickName(config.returnUrlCookieName, DEFAULT_RETURN_COOKIE_NAME);
|
|
765
|
+
const verifierCookieName = pickName(config.verifierCookieName, DEFAULT_VERIFIER_COOKIE_NAME);
|
|
766
|
+
const logoutStateCookieName = pickName(config.logoutStateCookieName, DEFAULT_LOGOUT_STATE_COOKIE_NAME);
|
|
517
767
|
const normalizedBase = ssoBaseUrl.replace(/\/+$/, "");
|
|
518
|
-
return async function
|
|
768
|
+
return async function handler(request) {
|
|
769
|
+
const returnedState = request.nextUrl.searchParams.get("state");
|
|
770
|
+
if (returnedState) {
|
|
771
|
+
const savedState = request.cookies.get(logoutStateCookieName)?.value;
|
|
772
|
+
if (!savedState || savedState !== returnedState) {
|
|
773
|
+
return import_server3.NextResponse.json(
|
|
774
|
+
{ error: "invalid_request", error_description: "Logout state \u4E0D\u5339\u914D" },
|
|
775
|
+
{ status: 400 }
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
const res = import_server3.NextResponse.redirect(request.nextUrl.origin + "/");
|
|
779
|
+
res.cookies.set(logoutStateCookieName, "", getHostCookieOptions(0, secureCookies));
|
|
780
|
+
return res;
|
|
781
|
+
}
|
|
519
782
|
const refreshToken = request.cookies.get(refreshTokenCookieName)?.value;
|
|
520
783
|
const idTokenHint = request.cookies.get(idTokenCookieName)?.value;
|
|
521
784
|
if (refreshToken) {
|
|
@@ -539,18 +802,18 @@ function createLogoutRouteHandler(config) {
|
|
|
539
802
|
}
|
|
540
803
|
}
|
|
541
804
|
const clearCookies = (res) => {
|
|
542
|
-
res.cookies.set(accessTokenCookieName, "", getHostCookieOptions(0));
|
|
543
|
-
res.cookies.set(refreshTokenCookieName, "", getHostCookieOptions(0));
|
|
544
|
-
res.cookies.set(idTokenCookieName, "", getHostCookieOptions(0));
|
|
545
|
-
res.cookies.set(stateCookieName, "", getHostCookieOptions(0));
|
|
546
|
-
res.cookies.set(returnUrlCookieName, "", getHostCookieOptions(0));
|
|
547
|
-
res.cookies.set(verifierCookieName, "", getSecureCookieOptions(0, "/"));
|
|
548
|
-
res.cookies.set(verifierCookieName, "", getSecureCookieOptions(0, callbackPath));
|
|
805
|
+
res.cookies.set(accessTokenCookieName, "", getHostCookieOptions(0, secureCookies));
|
|
806
|
+
res.cookies.set(refreshTokenCookieName, "", getHostCookieOptions(0, secureCookies));
|
|
807
|
+
res.cookies.set(idTokenCookieName, "", getHostCookieOptions(0, secureCookies));
|
|
808
|
+
res.cookies.set(stateCookieName, "", getHostCookieOptions(0, secureCookies));
|
|
809
|
+
res.cookies.set(returnUrlCookieName, "", getHostCookieOptions(0, secureCookies));
|
|
810
|
+
res.cookies.set(verifierCookieName, "", getSecureCookieOptions(0, "/", secureCookies));
|
|
811
|
+
res.cookies.set(verifierCookieName, "", getSecureCookieOptions(0, callbackPath, secureCookies));
|
|
549
812
|
return res;
|
|
550
813
|
};
|
|
551
814
|
if (redirectToSso) {
|
|
552
815
|
const discovery = await fetchDiscovery(normalizedBase);
|
|
553
|
-
const endSessionEndpoint = discovery?.end_session_endpoint || `${normalizedBase}/
|
|
816
|
+
const endSessionEndpoint = discovery?.end_session_endpoint || `${normalizedBase}/api/oauth/end-session`;
|
|
554
817
|
const logoutUrl = new URL(endSessionEndpoint);
|
|
555
818
|
logoutUrl.searchParams.set("client_id", clientId);
|
|
556
819
|
logoutUrl.searchParams.set(
|
|
@@ -560,7 +823,11 @@ function createLogoutRouteHandler(config) {
|
|
|
560
823
|
if (idTokenHint) {
|
|
561
824
|
logoutUrl.searchParams.set("id_token_hint", idTokenHint);
|
|
562
825
|
}
|
|
563
|
-
|
|
826
|
+
const logoutState = generateRandomString2(32);
|
|
827
|
+
logoutUrl.searchParams.set("state", logoutState);
|
|
828
|
+
const res = clearCookies(import_server3.NextResponse.redirect(logoutUrl.toString()));
|
|
829
|
+
res.cookies.set(logoutStateCookieName, logoutState, getHostCookieOptions(600, secureCookies));
|
|
830
|
+
return res;
|
|
564
831
|
}
|
|
565
832
|
return clearCookies(
|
|
566
833
|
import_server3.NextResponse.redirect(request.nextUrl.origin + "/")
|
|
@@ -570,6 +837,8 @@ function createLogoutRouteHandler(config) {
|
|
|
570
837
|
// Annotate the CommonJS export names for ESM import in node:
|
|
571
838
|
0 && (module.exports = {
|
|
572
839
|
DEFAULT_ACCESS_TOKEN_COOKIE_NAME,
|
|
840
|
+
DEFAULT_ID_TOKEN_COOKIE_NAME,
|
|
841
|
+
DEFAULT_LOGOUT_STATE_COOKIE_NAME,
|
|
573
842
|
DEFAULT_REFRESH_TOKEN_COOKIE_NAME,
|
|
574
843
|
DEFAULT_RETURN_COOKIE_NAME,
|
|
575
844
|
DEFAULT_STATE_COOKIE_NAME,
|
|
@@ -578,6 +847,7 @@ function createLogoutRouteHandler(config) {
|
|
|
578
847
|
createLogoutRouteHandler,
|
|
579
848
|
createSsoMiddleware,
|
|
580
849
|
getHostCookieOptions,
|
|
581
|
-
getSecureCookieOptions
|
|
850
|
+
getSecureCookieOptions,
|
|
851
|
+
toInsecureCookieName
|
|
582
852
|
});
|
|
583
853
|
//# sourceMappingURL=index.js.map
|