@nihplod/sso-sdk 1.1.0 → 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 +73 -6
- package/dist/index.d.mts +46 -10
- package/dist/index.d.ts +46 -10
- package/dist/index.js +68 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +65 -9
- package/dist/index.mjs.map +1 -1
- package/dist/next/index.d.mts +38 -5
- package/dist/next/index.d.ts +38 -5
- package/dist/next/index.js +84 -45
- package/dist/next/index.js.map +1 -1
- package/dist/next/index.mjs +82 -44
- package/dist/next/index.mjs.map +1 -1
- package/dist/react/index.d.mts +108 -10
- package/dist/react/index.d.ts +108 -10
- package/dist/react/index.js +166 -55
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +169 -59
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/next/index.d.mts
CHANGED
|
@@ -61,6 +61,18 @@ interface SsoMiddlewareConfig {
|
|
|
61
61
|
returnUrlCookieName?: string;
|
|
62
62
|
/** PKCE Verifier Cookie 名称,默认 __Secure-nihplod_sso_verifier */
|
|
63
63
|
verifierCookieName?: string;
|
|
64
|
+
/**
|
|
65
|
+
* 本地 HTTP 开发模式(默认 false)。
|
|
66
|
+
*
|
|
67
|
+
* ⚠️ 仅限 http://localhost 开发:关闭 Cookie 的 Secure 属性并去除
|
|
68
|
+
* __Host-/__Secure- 前缀(浏览器拒绝在 HTTP 下写入带这两个前缀的 Cookie,
|
|
69
|
+
* 否则会出现「登录后 cookie 写不进去 → middleware 永远判定未登录 →
|
|
70
|
+
* 反复跳 SSO」的无限重定向)。开启时启动告警;生产环境严禁启用——
|
|
71
|
+
* 生产环境(NODE_ENV=production 且 ssoBaseUrl 为 https)下该开关会被
|
|
72
|
+
* 强制忽略并告警,仍走 secure cookie。
|
|
73
|
+
* middleware / callback / logout 三处配置需保持一致。
|
|
74
|
+
*/
|
|
75
|
+
insecureLocalDev?: boolean;
|
|
64
76
|
}
|
|
65
77
|
declare function createSsoMiddleware(config: SsoMiddlewareConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
66
78
|
|
|
@@ -115,6 +127,14 @@ interface CallbackRouteConfig {
|
|
|
115
127
|
returnUrlCookieName?: string;
|
|
116
128
|
/** PKCE Verifier Cookie 名称,默认 __Secure-nihplod_sso_verifier */
|
|
117
129
|
verifierCookieName?: string;
|
|
130
|
+
/**
|
|
131
|
+
* 本地 HTTP 开发模式(默认 false)。关闭 Cookie 的 Secure 属性并去除
|
|
132
|
+
* __Host-/__Secure- 前缀;必须与 createSsoMiddleware 的配置保持一致,
|
|
133
|
+
* 否则读不到 middleware 写入的 state/verifier Cookie。生产严禁启用——
|
|
134
|
+
* 生产环境(NODE_ENV=production 且 ssoBaseUrl 为 https)下该开关会被
|
|
135
|
+
* 强制忽略并告警。
|
|
136
|
+
*/
|
|
137
|
+
insecureLocalDev?: boolean;
|
|
118
138
|
}
|
|
119
139
|
declare function createCallbackRouteHandler(config: CallbackRouteConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
120
140
|
|
|
@@ -176,6 +196,13 @@ interface LogoutRouteConfig {
|
|
|
176
196
|
callbackPath?: string;
|
|
177
197
|
/** Logout State Cookie 名称(RP-Initiated Logout CSRF 防护),默认 __Host-nihplod_sso_logout_state */
|
|
178
198
|
logoutStateCookieName?: string;
|
|
199
|
+
/**
|
|
200
|
+
* 本地 HTTP 开发模式(默认 false)。关闭 Cookie 的 Secure 属性并去除
|
|
201
|
+
* __Host-/__Secure- 前缀;必须与 middleware / callback 的配置保持一致,
|
|
202
|
+
* 否则无法清除它们写入的 Cookie。生产严禁启用——生产环境
|
|
203
|
+
* (NODE_ENV=production 且 ssoBaseUrl 为 https)下该开关会被强制忽略并告警。
|
|
204
|
+
*/
|
|
205
|
+
insecureLocalDev?: boolean;
|
|
179
206
|
}
|
|
180
207
|
declare function createLogoutRouteHandler(config: LogoutRouteConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
181
208
|
|
|
@@ -196,21 +223,27 @@ declare const DEFAULT_STATE_COOKIE_NAME = "__Host-nihplod_sso_state";
|
|
|
196
223
|
declare const DEFAULT_RETURN_COOKIE_NAME = "__Host-nihplod_sso_return";
|
|
197
224
|
declare const DEFAULT_VERIFIER_COOKIE_NAME = "__Secure-nihplod_sso_verifier";
|
|
198
225
|
declare const DEFAULT_LOGOUT_STATE_COOKIE_NAME = "__Host-nihplod_sso_logout_state";
|
|
226
|
+
/**
|
|
227
|
+
* insecureLocalDev 场景:去除 __Host-/__Secure- 前缀。
|
|
228
|
+
* 浏览器强制要求带这两个前缀的 Cookie 必须设置 Secure,
|
|
229
|
+
* HTTP 本地开发时若保留前缀,即使 secure=false 也会被拒绝写入。
|
|
230
|
+
*/
|
|
231
|
+
declare function toInsecureCookieName(name: string): string;
|
|
199
232
|
/** __Host- 前缀 Cookie 的安全选项(Path 必须为 /) */
|
|
200
|
-
declare function getHostCookieOptions(maxAge?: number): {
|
|
233
|
+
declare function getHostCookieOptions(maxAge?: number, secure?: boolean): {
|
|
201
234
|
httpOnly: true;
|
|
202
|
-
secure:
|
|
235
|
+
secure: boolean;
|
|
203
236
|
sameSite: "lax";
|
|
204
237
|
path: "/";
|
|
205
238
|
maxAge?: number;
|
|
206
239
|
};
|
|
207
240
|
/** __Secure- 前缀 Cookie 的安全选项(允许自定义 Path) */
|
|
208
|
-
declare function getSecureCookieOptions(maxAge?: number, path?: string): {
|
|
241
|
+
declare function getSecureCookieOptions(maxAge?: number, path?: string, secure?: boolean): {
|
|
209
242
|
httpOnly: true;
|
|
210
|
-
secure:
|
|
243
|
+
secure: boolean;
|
|
211
244
|
sameSite: "lax";
|
|
212
245
|
path: string;
|
|
213
246
|
maxAge?: number;
|
|
214
247
|
};
|
|
215
248
|
|
|
216
|
-
export { type CallbackRouteConfig, DEFAULT_ACCESS_TOKEN_COOKIE_NAME, DEFAULT_ID_TOKEN_COOKIE_NAME, DEFAULT_LOGOUT_STATE_COOKIE_NAME, DEFAULT_REFRESH_TOKEN_COOKIE_NAME, DEFAULT_RETURN_COOKIE_NAME, DEFAULT_STATE_COOKIE_NAME, DEFAULT_VERIFIER_COOKIE_NAME, type LogoutRouteConfig, type SsoMiddlewareConfig, createCallbackRouteHandler, createLogoutRouteHandler, createSsoMiddleware, getHostCookieOptions, getSecureCookieOptions };
|
|
249
|
+
export { type CallbackRouteConfig, DEFAULT_ACCESS_TOKEN_COOKIE_NAME, DEFAULT_ID_TOKEN_COOKIE_NAME, DEFAULT_LOGOUT_STATE_COOKIE_NAME, DEFAULT_REFRESH_TOKEN_COOKIE_NAME, DEFAULT_RETURN_COOKIE_NAME, DEFAULT_STATE_COOKIE_NAME, DEFAULT_VERIFIER_COOKIE_NAME, type LogoutRouteConfig, type SsoMiddlewareConfig, createCallbackRouteHandler, createLogoutRouteHandler, createSsoMiddleware, getHostCookieOptions, getSecureCookieOptions, toInsecureCookieName };
|
package/dist/next/index.d.ts
CHANGED
|
@@ -61,6 +61,18 @@ interface SsoMiddlewareConfig {
|
|
|
61
61
|
returnUrlCookieName?: string;
|
|
62
62
|
/** PKCE Verifier Cookie 名称,默认 __Secure-nihplod_sso_verifier */
|
|
63
63
|
verifierCookieName?: string;
|
|
64
|
+
/**
|
|
65
|
+
* 本地 HTTP 开发模式(默认 false)。
|
|
66
|
+
*
|
|
67
|
+
* ⚠️ 仅限 http://localhost 开发:关闭 Cookie 的 Secure 属性并去除
|
|
68
|
+
* __Host-/__Secure- 前缀(浏览器拒绝在 HTTP 下写入带这两个前缀的 Cookie,
|
|
69
|
+
* 否则会出现「登录后 cookie 写不进去 → middleware 永远判定未登录 →
|
|
70
|
+
* 反复跳 SSO」的无限重定向)。开启时启动告警;生产环境严禁启用——
|
|
71
|
+
* 生产环境(NODE_ENV=production 且 ssoBaseUrl 为 https)下该开关会被
|
|
72
|
+
* 强制忽略并告警,仍走 secure cookie。
|
|
73
|
+
* middleware / callback / logout 三处配置需保持一致。
|
|
74
|
+
*/
|
|
75
|
+
insecureLocalDev?: boolean;
|
|
64
76
|
}
|
|
65
77
|
declare function createSsoMiddleware(config: SsoMiddlewareConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
66
78
|
|
|
@@ -115,6 +127,14 @@ interface CallbackRouteConfig {
|
|
|
115
127
|
returnUrlCookieName?: string;
|
|
116
128
|
/** PKCE Verifier Cookie 名称,默认 __Secure-nihplod_sso_verifier */
|
|
117
129
|
verifierCookieName?: string;
|
|
130
|
+
/**
|
|
131
|
+
* 本地 HTTP 开发模式(默认 false)。关闭 Cookie 的 Secure 属性并去除
|
|
132
|
+
* __Host-/__Secure- 前缀;必须与 createSsoMiddleware 的配置保持一致,
|
|
133
|
+
* 否则读不到 middleware 写入的 state/verifier Cookie。生产严禁启用——
|
|
134
|
+
* 生产环境(NODE_ENV=production 且 ssoBaseUrl 为 https)下该开关会被
|
|
135
|
+
* 强制忽略并告警。
|
|
136
|
+
*/
|
|
137
|
+
insecureLocalDev?: boolean;
|
|
118
138
|
}
|
|
119
139
|
declare function createCallbackRouteHandler(config: CallbackRouteConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
120
140
|
|
|
@@ -176,6 +196,13 @@ interface LogoutRouteConfig {
|
|
|
176
196
|
callbackPath?: string;
|
|
177
197
|
/** Logout State Cookie 名称(RP-Initiated Logout CSRF 防护),默认 __Host-nihplod_sso_logout_state */
|
|
178
198
|
logoutStateCookieName?: string;
|
|
199
|
+
/**
|
|
200
|
+
* 本地 HTTP 开发模式(默认 false)。关闭 Cookie 的 Secure 属性并去除
|
|
201
|
+
* __Host-/__Secure- 前缀;必须与 middleware / callback 的配置保持一致,
|
|
202
|
+
* 否则无法清除它们写入的 Cookie。生产严禁启用——生产环境
|
|
203
|
+
* (NODE_ENV=production 且 ssoBaseUrl 为 https)下该开关会被强制忽略并告警。
|
|
204
|
+
*/
|
|
205
|
+
insecureLocalDev?: boolean;
|
|
179
206
|
}
|
|
180
207
|
declare function createLogoutRouteHandler(config: LogoutRouteConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
181
208
|
|
|
@@ -196,21 +223,27 @@ declare const DEFAULT_STATE_COOKIE_NAME = "__Host-nihplod_sso_state";
|
|
|
196
223
|
declare const DEFAULT_RETURN_COOKIE_NAME = "__Host-nihplod_sso_return";
|
|
197
224
|
declare const DEFAULT_VERIFIER_COOKIE_NAME = "__Secure-nihplod_sso_verifier";
|
|
198
225
|
declare const DEFAULT_LOGOUT_STATE_COOKIE_NAME = "__Host-nihplod_sso_logout_state";
|
|
226
|
+
/**
|
|
227
|
+
* insecureLocalDev 场景:去除 __Host-/__Secure- 前缀。
|
|
228
|
+
* 浏览器强制要求带这两个前缀的 Cookie 必须设置 Secure,
|
|
229
|
+
* HTTP 本地开发时若保留前缀,即使 secure=false 也会被拒绝写入。
|
|
230
|
+
*/
|
|
231
|
+
declare function toInsecureCookieName(name: string): string;
|
|
199
232
|
/** __Host- 前缀 Cookie 的安全选项(Path 必须为 /) */
|
|
200
|
-
declare function getHostCookieOptions(maxAge?: number): {
|
|
233
|
+
declare function getHostCookieOptions(maxAge?: number, secure?: boolean): {
|
|
201
234
|
httpOnly: true;
|
|
202
|
-
secure:
|
|
235
|
+
secure: boolean;
|
|
203
236
|
sameSite: "lax";
|
|
204
237
|
path: "/";
|
|
205
238
|
maxAge?: number;
|
|
206
239
|
};
|
|
207
240
|
/** __Secure- 前缀 Cookie 的安全选项(允许自定义 Path) */
|
|
208
|
-
declare function getSecureCookieOptions(maxAge?: number, path?: string): {
|
|
241
|
+
declare function getSecureCookieOptions(maxAge?: number, path?: string, secure?: boolean): {
|
|
209
242
|
httpOnly: true;
|
|
210
|
-
secure:
|
|
243
|
+
secure: boolean;
|
|
211
244
|
sameSite: "lax";
|
|
212
245
|
path: string;
|
|
213
246
|
maxAge?: number;
|
|
214
247
|
};
|
|
215
248
|
|
|
216
|
-
export { type CallbackRouteConfig, DEFAULT_ACCESS_TOKEN_COOKIE_NAME, DEFAULT_ID_TOKEN_COOKIE_NAME, DEFAULT_LOGOUT_STATE_COOKIE_NAME, DEFAULT_REFRESH_TOKEN_COOKIE_NAME, DEFAULT_RETURN_COOKIE_NAME, DEFAULT_STATE_COOKIE_NAME, DEFAULT_VERIFIER_COOKIE_NAME, type LogoutRouteConfig, type SsoMiddlewareConfig, createCallbackRouteHandler, createLogoutRouteHandler, createSsoMiddleware, getHostCookieOptions, getSecureCookieOptions };
|
|
249
|
+
export { type CallbackRouteConfig, DEFAULT_ACCESS_TOKEN_COOKIE_NAME, DEFAULT_ID_TOKEN_COOKIE_NAME, DEFAULT_LOGOUT_STATE_COOKIE_NAME, DEFAULT_REFRESH_TOKEN_COOKIE_NAME, DEFAULT_RETURN_COOKIE_NAME, DEFAULT_STATE_COOKIE_NAME, DEFAULT_VERIFIER_COOKIE_NAME, type LogoutRouteConfig, type SsoMiddlewareConfig, createCallbackRouteHandler, createLogoutRouteHandler, createSsoMiddleware, getHostCookieOptions, getSecureCookieOptions, toInsecureCookieName };
|
package/dist/next/index.js
CHANGED
|
@@ -31,7 +31,8 @@ __export(next_exports, {
|
|
|
31
31
|
createLogoutRouteHandler: () => createLogoutRouteHandler,
|
|
32
32
|
createSsoMiddleware: () => createSsoMiddleware,
|
|
33
33
|
getHostCookieOptions: () => getHostCookieOptions,
|
|
34
|
-
getSecureCookieOptions: () => getSecureCookieOptions
|
|
34
|
+
getSecureCookieOptions: () => getSecureCookieOptions,
|
|
35
|
+
toInsecureCookieName: () => toInsecureCookieName
|
|
35
36
|
});
|
|
36
37
|
module.exports = __toCommonJS(next_exports);
|
|
37
38
|
|
|
@@ -46,19 +47,35 @@ var DEFAULT_STATE_COOKIE_NAME = "__Host-nihplod_sso_state";
|
|
|
46
47
|
var DEFAULT_RETURN_COOKIE_NAME = "__Host-nihplod_sso_return";
|
|
47
48
|
var DEFAULT_VERIFIER_COOKIE_NAME = "__Secure-nihplod_sso_verifier";
|
|
48
49
|
var DEFAULT_LOGOUT_STATE_COOKIE_NAME = "__Host-nihplod_sso_logout_state";
|
|
49
|
-
function
|
|
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) {
|
|
50
67
|
return {
|
|
51
68
|
httpOnly: true,
|
|
52
|
-
secure
|
|
69
|
+
secure,
|
|
53
70
|
sameSite: "lax",
|
|
54
71
|
path: "/",
|
|
55
72
|
...maxAge !== void 0 ? { maxAge } : {}
|
|
56
73
|
};
|
|
57
74
|
}
|
|
58
|
-
function getSecureCookieOptions(maxAge, path = "/") {
|
|
75
|
+
function getSecureCookieOptions(maxAge, path = "/", secure = true) {
|
|
59
76
|
return {
|
|
60
77
|
httpOnly: true,
|
|
61
|
-
secure
|
|
78
|
+
secure,
|
|
62
79
|
sameSite: "lax",
|
|
63
80
|
path,
|
|
64
81
|
...maxAge !== void 0 ? { maxAge } : {}
|
|
@@ -176,11 +193,14 @@ function createSsoMiddleware(config) {
|
|
|
176
193
|
callbackPath = "/api/auth/callback",
|
|
177
194
|
ssoCookieName = "__Host-user_token",
|
|
178
195
|
validateSsoCookie = true,
|
|
179
|
-
|
|
180
|
-
stateCookieName = DEFAULT_STATE_COOKIE_NAME,
|
|
181
|
-
returnUrlCookieName = DEFAULT_RETURN_COOKIE_NAME,
|
|
182
|
-
verifierCookieName = DEFAULT_VERIFIER_COOKIE_NAME
|
|
196
|
+
insecureLocalDev: insecureLocalDevOpt = false
|
|
183
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;
|
|
184
204
|
const normalizedBase = ssoBaseUrl.replace(/\/+$/, "");
|
|
185
205
|
if (process.env.NODE_ENV !== "production") {
|
|
186
206
|
if (!validateSsoCookie) {
|
|
@@ -248,12 +268,12 @@ function createSsoMiddleware(config) {
|
|
|
248
268
|
const loginUrl = new URL("/api/oauth/authorize", normalizedBase);
|
|
249
269
|
loginUrl.search = authorizeParams.toString();
|
|
250
270
|
const response = import_server.NextResponse.redirect(loginUrl);
|
|
251
|
-
response.cookies.set(stateCookieName, state, getHostCookieOptions(600));
|
|
252
|
-
response.cookies.set(verifierCookieName, verifier, getSecureCookieOptions(600, callbackPath));
|
|
271
|
+
response.cookies.set(stateCookieName, state, getHostCookieOptions(600, secureCookies));
|
|
272
|
+
response.cookies.set(verifierCookieName, verifier, getSecureCookieOptions(600, callbackPath, secureCookies));
|
|
253
273
|
const safeReturnUrl = (request.nextUrl.pathname + request.nextUrl.search).slice(0, 2048);
|
|
254
|
-
response.cookies.set(returnUrlCookieName, safeReturnUrl, getHostCookieOptions(600));
|
|
274
|
+
response.cookies.set(returnUrlCookieName, safeReturnUrl, getHostCookieOptions(600, secureCookies));
|
|
255
275
|
if (accessTokenCookie?.value) {
|
|
256
|
-
response.cookies.set(accessTokenCookieName, "", getHostCookieOptions(0));
|
|
276
|
+
response.cookies.set(accessTokenCookieName, "", getHostCookieOptions(0, secureCookies));
|
|
257
277
|
}
|
|
258
278
|
return response;
|
|
259
279
|
};
|
|
@@ -276,6 +296,7 @@ var SsoError = class extends Error {
|
|
|
276
296
|
// src/core/security.ts
|
|
277
297
|
function isTrustedReturnUrl(url, currentOrigin) {
|
|
278
298
|
if (!url) return false;
|
|
299
|
+
if (url.includes("\\")) return false;
|
|
279
300
|
if (url.startsWith("/") && !url.startsWith("//")) return true;
|
|
280
301
|
try {
|
|
281
302
|
return new URL(url).origin === currentOrigin;
|
|
@@ -481,7 +502,7 @@ async function validateIdToken(idToken, accessToken, expectedIssuer, expectedCli
|
|
|
481
502
|
if (typeof payload.exp !== "number") {
|
|
482
503
|
throw new SsoError("id_token_invalid", "ID Token \u7F3A\u5C11 exp \u58F0\u660E");
|
|
483
504
|
}
|
|
484
|
-
if (Date.now() >= payload.exp * 1e3) {
|
|
505
|
+
if (Date.now() >= payload.exp * 1e3 + 6e4) {
|
|
485
506
|
throw new SsoError("id_token_expired", "ID Token \u5DF2\u8FC7\u671F");
|
|
486
507
|
}
|
|
487
508
|
if (typeof payload.iat === "number" && payload.iat * 1e3 > Date.now() + 6e4) {
|
|
@@ -507,13 +528,17 @@ function createCallbackRouteHandler(config) {
|
|
|
507
528
|
redirectUri,
|
|
508
529
|
clientSecret,
|
|
509
530
|
defaultReturnPath = "/",
|
|
510
|
-
|
|
511
|
-
refreshTokenCookieName = DEFAULT_REFRESH_TOKEN_COOKIE_NAME,
|
|
512
|
-
idTokenCookieName = DEFAULT_ID_TOKEN_COOKIE_NAME,
|
|
513
|
-
stateCookieName = DEFAULT_STATE_COOKIE_NAME,
|
|
514
|
-
returnUrlCookieName = DEFAULT_RETURN_COOKIE_NAME,
|
|
515
|
-
verifierCookieName = DEFAULT_VERIFIER_COOKIE_NAME
|
|
531
|
+
insecureLocalDev: insecureLocalDevOpt = false
|
|
516
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);
|
|
517
542
|
const normalizedBase = ssoBaseUrl.replace(/\/+$/, "");
|
|
518
543
|
return async function GET(request) {
|
|
519
544
|
const { searchParams } = request.nextUrl;
|
|
@@ -621,6 +646,15 @@ function createCallbackRouteHandler(config) {
|
|
|
621
646
|
);
|
|
622
647
|
}
|
|
623
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
|
+
}
|
|
624
658
|
if (tokenData.id_token) {
|
|
625
659
|
try {
|
|
626
660
|
await validateIdToken(
|
|
@@ -643,11 +677,11 @@ function createCallbackRouteHandler(config) {
|
|
|
643
677
|
const returnUrl = isTrustedReturnUrl(rawReturnUrl, request.nextUrl.origin) ? rawReturnUrl : "/";
|
|
644
678
|
const response = import_server2.NextResponse.redirect(new URL(returnUrl, request.url));
|
|
645
679
|
response.cookies.set(accessTokenCookieName, tokenData.access_token, {
|
|
646
|
-
...getHostCookieOptions(tokenData.expires_in)
|
|
680
|
+
...getHostCookieOptions(tokenData.expires_in, secureCookies)
|
|
647
681
|
});
|
|
648
682
|
const refreshMaxAge = tokenData.refresh_expires_in != null ? tokenData.refresh_expires_in : 30 * 24 * 60 * 60;
|
|
649
683
|
response.cookies.set(refreshTokenCookieName, tokenData.refresh_token, {
|
|
650
|
-
...getHostCookieOptions(refreshMaxAge)
|
|
684
|
+
...getHostCookieOptions(refreshMaxAge, secureCookies)
|
|
651
685
|
});
|
|
652
686
|
if (tokenData.id_token) {
|
|
653
687
|
let idTokenMaxAge = 3600;
|
|
@@ -665,14 +699,14 @@ function createCallbackRouteHandler(config) {
|
|
|
665
699
|
}
|
|
666
700
|
if (idTokenMaxAge > 0) {
|
|
667
701
|
response.cookies.set(idTokenCookieName, tokenData.id_token, {
|
|
668
|
-
...getHostCookieOptions(idTokenMaxAge)
|
|
702
|
+
...getHostCookieOptions(idTokenMaxAge, secureCookies)
|
|
669
703
|
});
|
|
670
704
|
}
|
|
671
705
|
}
|
|
672
|
-
response.cookies.set(stateCookieName, "", getHostCookieOptions(0));
|
|
673
|
-
response.cookies.set(returnUrlCookieName, "", getHostCookieOptions(0));
|
|
674
|
-
response.cookies.set(verifierCookieName, "", getSecureCookieOptions(0, "/"));
|
|
675
|
-
response.cookies.set(verifierCookieName, "", getSecureCookieOptions(0, request.nextUrl.pathname));
|
|
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));
|
|
676
710
|
return response;
|
|
677
711
|
};
|
|
678
712
|
}
|
|
@@ -717,15 +751,19 @@ function createLogoutRouteHandler(config) {
|
|
|
717
751
|
clientSecret,
|
|
718
752
|
postLogoutRedirectUri = new URL(redirectUri).origin + "/",
|
|
719
753
|
redirectToSso = true,
|
|
720
|
-
accessTokenCookieName = DEFAULT_ACCESS_TOKEN_COOKIE_NAME,
|
|
721
|
-
refreshTokenCookieName = DEFAULT_REFRESH_TOKEN_COOKIE_NAME,
|
|
722
|
-
idTokenCookieName = DEFAULT_ID_TOKEN_COOKIE_NAME,
|
|
723
|
-
stateCookieName = DEFAULT_STATE_COOKIE_NAME,
|
|
724
|
-
returnUrlCookieName = DEFAULT_RETURN_COOKIE_NAME,
|
|
725
|
-
verifierCookieName = DEFAULT_VERIFIER_COOKIE_NAME,
|
|
726
754
|
callbackPath = "/api/auth/callback",
|
|
727
|
-
|
|
755
|
+
insecureLocalDev: insecureLocalDevOpt = false
|
|
728
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);
|
|
729
767
|
const normalizedBase = ssoBaseUrl.replace(/\/+$/, "");
|
|
730
768
|
return async function handler(request) {
|
|
731
769
|
const returnedState = request.nextUrl.searchParams.get("state");
|
|
@@ -738,7 +776,7 @@ function createLogoutRouteHandler(config) {
|
|
|
738
776
|
);
|
|
739
777
|
}
|
|
740
778
|
const res = import_server3.NextResponse.redirect(request.nextUrl.origin + "/");
|
|
741
|
-
res.cookies.set(logoutStateCookieName, "", getHostCookieOptions(0));
|
|
779
|
+
res.cookies.set(logoutStateCookieName, "", getHostCookieOptions(0, secureCookies));
|
|
742
780
|
return res;
|
|
743
781
|
}
|
|
744
782
|
const refreshToken = request.cookies.get(refreshTokenCookieName)?.value;
|
|
@@ -764,18 +802,18 @@ function createLogoutRouteHandler(config) {
|
|
|
764
802
|
}
|
|
765
803
|
}
|
|
766
804
|
const clearCookies = (res) => {
|
|
767
|
-
res.cookies.set(accessTokenCookieName, "", getHostCookieOptions(0));
|
|
768
|
-
res.cookies.set(refreshTokenCookieName, "", getHostCookieOptions(0));
|
|
769
|
-
res.cookies.set(idTokenCookieName, "", getHostCookieOptions(0));
|
|
770
|
-
res.cookies.set(stateCookieName, "", getHostCookieOptions(0));
|
|
771
|
-
res.cookies.set(returnUrlCookieName, "", getHostCookieOptions(0));
|
|
772
|
-
res.cookies.set(verifierCookieName, "", getSecureCookieOptions(0, "/"));
|
|
773
|
-
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));
|
|
774
812
|
return res;
|
|
775
813
|
};
|
|
776
814
|
if (redirectToSso) {
|
|
777
815
|
const discovery = await fetchDiscovery(normalizedBase);
|
|
778
|
-
const endSessionEndpoint = discovery?.end_session_endpoint || `${normalizedBase}/
|
|
816
|
+
const endSessionEndpoint = discovery?.end_session_endpoint || `${normalizedBase}/api/oauth/end-session`;
|
|
779
817
|
const logoutUrl = new URL(endSessionEndpoint);
|
|
780
818
|
logoutUrl.searchParams.set("client_id", clientId);
|
|
781
819
|
logoutUrl.searchParams.set(
|
|
@@ -788,7 +826,7 @@ function createLogoutRouteHandler(config) {
|
|
|
788
826
|
const logoutState = generateRandomString2(32);
|
|
789
827
|
logoutUrl.searchParams.set("state", logoutState);
|
|
790
828
|
const res = clearCookies(import_server3.NextResponse.redirect(logoutUrl.toString()));
|
|
791
|
-
res.cookies.set(logoutStateCookieName, logoutState, getHostCookieOptions(600));
|
|
829
|
+
res.cookies.set(logoutStateCookieName, logoutState, getHostCookieOptions(600, secureCookies));
|
|
792
830
|
return res;
|
|
793
831
|
}
|
|
794
832
|
return clearCookies(
|
|
@@ -809,6 +847,7 @@ function createLogoutRouteHandler(config) {
|
|
|
809
847
|
createLogoutRouteHandler,
|
|
810
848
|
createSsoMiddleware,
|
|
811
849
|
getHostCookieOptions,
|
|
812
|
-
getSecureCookieOptions
|
|
850
|
+
getSecureCookieOptions,
|
|
851
|
+
toInsecureCookieName
|
|
813
852
|
});
|
|
814
853
|
//# sourceMappingURL=index.js.map
|