strapi-plugin-oidc 1.2.3 → 1.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.
@@ -4,22 +4,19 @@ import strapiUtils from "@strapi/utils";
4
4
  import generator from "generate-password";
5
5
  function register$1() {
6
6
  }
7
- function getExpiredCookieOptions(strapi2, ctx) {
8
- const isProduction = strapi2.config.get("environment") === "production";
9
- return {
10
- httpOnly: true,
11
- secure: isProduction && ctx.request.secure,
12
- path: strapi2.config.get("admin.auth.cookie.path", "/admin"),
13
- domain: strapi2.config.get("admin.auth.cookie.domain") || strapi2.config.get("admin.auth.domain"),
14
- sameSite: strapi2.config.get("admin.auth.cookie.sameSite", "lax"),
15
- maxAge: 0,
16
- expires: /* @__PURE__ */ new Date(0)
17
- };
7
+ function getEnforceOIDCConfig(strapi2) {
8
+ const config2 = strapi2.config.get("plugin::strapi-plugin-oidc");
9
+ const val = config2.OIDC_ENFORCE;
10
+ if (val === null || val === void 0) return null;
11
+ if (typeof val === "boolean") return val;
12
+ if (val === "true") return true;
13
+ if (val === "false") return false;
14
+ return null;
18
15
  }
19
- function clearAuthCookies(strapi2, ctx) {
20
- const options2 = getExpiredCookieOptions(strapi2, ctx);
21
- ctx.cookies.set("strapi_admin_refresh", "", options2);
22
- ctx.cookies.set("oidc_authenticated", "", options2);
16
+ function resolveEnforceOIDC(strapi2, dbValue) {
17
+ const configValue = getEnforceOIDCConfig(strapi2);
18
+ if (configValue !== null) return configValue;
19
+ return dbValue ?? false;
23
20
  }
24
21
  async function bootstrap({ strapi: strapi2 }) {
25
22
  const enforceOidcMiddleware = async (ctx, next) => {
@@ -32,13 +29,12 @@ async function bootstrap({ strapi: strapi2 }) {
32
29
  ];
33
30
  const isPostAuth = authRoutes.includes(ctx.request.path) && ctx.request.method === "POST";
34
31
  const isTokenRefresh = ctx.request.path === `${adminUrl}/token/refresh` && ctx.request.method === "POST";
35
- const isHtmlRequest = ctx.request.accepts("html", "json") === "html" && !ctx.request.path.match(/\.[a-zA-Z0-9]+$/);
36
- const isGetAdminHtml = ctx.request.method === "GET" && ctx.request.path.startsWith(adminUrl) && isHtmlRequest;
37
- if (isPostAuth || isTokenRefresh || isGetAdminHtml) {
32
+ if (isPostAuth || isTokenRefresh) {
38
33
  try {
39
34
  const whitelistService2 = strapi2.plugin("strapi-plugin-oidc").service("whitelist");
40
35
  const settings = await whitelistService2.getSettings();
41
- if (settings?.enforceOIDC) {
36
+ const enforceOIDC = resolveEnforceOIDC(strapi2, settings?.enforceOIDC);
37
+ if (enforceOIDC) {
42
38
  if (isPostAuth) {
43
39
  ctx.status = 403;
44
40
  ctx.body = {
@@ -66,18 +62,6 @@ async function bootstrap({ strapi: strapi2 }) {
66
62
  };
67
63
  return;
68
64
  }
69
- if (isGetAdminHtml) {
70
- const hasRefreshCookie = !!ctx.cookies.get("strapi_admin_refresh");
71
- if (hasRefreshCookie && !hasOidcSession) {
72
- clearAuthCookies(strapi2, ctx);
73
- ctx.redirect("/strapi-plugin-oidc/oidc");
74
- return;
75
- }
76
- if (!hasRefreshCookie) {
77
- ctx.redirect("/strapi-plugin-oidc/oidc");
78
- return;
79
- }
80
- }
81
65
  }
82
66
  } catch (err) {
83
67
  strapi2.log.error("Error checking OIDC enforcement in middleware:", err);
@@ -152,8 +136,6 @@ function destroy() {
152
136
  const config = {
153
137
  default: {
154
138
  REMEMBER_ME: false,
155
- REMEMBER_ME_DAYS: 30,
156
- // 30 days
157
139
  OIDC_REDIRECT_URI: "http://localhost:1337/strapi-plugin-oidc/oidc/callback",
158
140
  OIDC_CLIENT_ID: "",
159
141
  OIDC_CLIENT_SECRET: "",
@@ -165,7 +147,10 @@ const config = {
165
147
  OIDC_GRANT_TYPE: "authorization_code",
166
148
  OIDC_FAMILY_NAME_FIELD: "family_name",
167
149
  OIDC_GIVEN_NAME_FIELD: "given_name",
168
- OIDC_LOGOUT_URL: ""
150
+ OIDC_LOGOUT_URL: "",
151
+ OIDC_SSO_BUTTON_TEXT: "Login via SSO",
152
+ OIDC_ENFORCE: null
153
+ // null = use DB setting; true/false = override DB (useful for lockout recovery)
169
154
  },
170
155
  validator() {
171
156
  }
@@ -200,6 +185,23 @@ const contentTypes = {
200
185
  roles,
201
186
  whitelists
202
187
  };
188
+ function getExpiredCookieOptions(strapi2, ctx) {
189
+ const isProduction = strapi2.config.get("environment") === "production";
190
+ return {
191
+ httpOnly: true,
192
+ secure: isProduction && ctx.request.secure,
193
+ path: strapi2.config.get("admin.auth.cookie.path", "/admin"),
194
+ domain: strapi2.config.get("admin.auth.cookie.domain") || strapi2.config.get("admin.auth.domain"),
195
+ sameSite: strapi2.config.get("admin.auth.cookie.sameSite", "lax"),
196
+ maxAge: 0,
197
+ expires: /* @__PURE__ */ new Date(0)
198
+ };
199
+ }
200
+ function clearAuthCookies(strapi2, ctx) {
201
+ const options2 = getExpiredCookieOptions(strapi2, ctx);
202
+ ctx.cookies.set("strapi_admin_refresh", "", options2);
203
+ ctx.cookies.set("oidc_authenticated", "", { ...options2, path: "/" });
204
+ }
203
205
  function configValidation() {
204
206
  const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
205
207
  const requiredKeys = [
@@ -339,6 +341,8 @@ async function oidcSignInCallback(ctx) {
339
341
  }
340
342
  const oidcState = ctx.cookies.get("oidc_state");
341
343
  const codeVerifier = ctx.cookies.get("oidc_code_verifier");
344
+ ctx.cookies.set("oidc_state", null);
345
+ ctx.cookies.set("oidc_code_verifier", null);
342
346
  if (!ctx.query.state || ctx.query.state !== oidcState) {
343
347
  return ctx.send(oauthService2.renderSignUpError("Invalid state"));
344
348
  }
@@ -419,7 +423,8 @@ async function info(ctx) {
419
423
  const whitelistUsers = await whitelistService2.getUsers();
420
424
  ctx.body = {
421
425
  useWhitelist: settings.useWhitelist,
422
- enforceOIDC: settings.enforceOIDC || false,
426
+ enforceOIDC: resolveEnforceOIDC(strapi, settings.enforceOIDC),
427
+ enforceOIDCConfig: getEnforceOIDCConfig(strapi),
423
428
  whitelistUsers
424
429
  };
425
430
  }
@@ -438,8 +443,10 @@ async function updateSettings(ctx) {
438
443
  async function publicSettings(ctx) {
439
444
  const whitelistService2 = strapi.plugin("strapi-plugin-oidc").service("whitelist");
440
445
  const settings = await whitelistService2.getSettings();
446
+ const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
441
447
  ctx.body = {
442
- enforceOIDC: settings.enforceOIDC || false
448
+ enforceOIDC: resolveEnforceOIDC(strapi, settings.enforceOIDC),
449
+ ssoButtonText: config2.OIDC_SSO_BUTTON_TEXT
443
450
  };
444
451
  }
445
452
  async function register(ctx) {
@@ -924,13 +931,11 @@ function oauthService({ strapi: strapi2 }) {
924
931
  const config2 = strapi2.config.get("plugin::strapi-plugin-oidc");
925
932
  const REMEMBER_ME = config2["REMEMBER_ME"];
926
933
  const rememberMe = !!REMEMBER_ME;
927
- const { token: refreshToken } = await sessionManager("admin").generateRefreshToken(
928
- userId,
929
- deviceId,
930
- {
931
- type: rememberMe ? "refresh" : "session"
932
- }
933
- );
934
+ const { token: refreshToken, absoluteExpiresAt } = await sessionManager(
935
+ "admin"
936
+ ).generateRefreshToken(userId, deviceId, {
937
+ type: rememberMe ? "refresh" : "session"
938
+ });
934
939
  const isProduction = strapi2.config.get("environment") === "production";
935
940
  const domain = strapi2.config.get("admin.auth.cookie.domain") || strapi2.config.get("admin.auth.domain");
936
941
  const path = strapi2.config.get("admin.auth.cookie.path", "/admin");
@@ -944,13 +949,19 @@ function oauthService({ strapi: strapi2 }) {
944
949
  sameSite
945
950
  };
946
951
  if (rememberMe) {
947
- const REMEMBER_ME_DAYS = config2["REMEMBER_ME_DAYS"] || 30;
948
- const durationInMs = REMEMBER_ME_DAYS * 24 * 60 * 60 * 1e3;
949
- cookieOptions.maxAge = durationInMs;
950
- cookieOptions.expires = new Date(Date.now() + durationInMs);
952
+ const idleLifespanSec = strapi2.config.get(
953
+ "admin.auth.sessions.idleRefreshTokenLifespan",
954
+ 1209600
955
+ // 14 days Strapi default
956
+ );
957
+ const idleMs = idleLifespanSec * 1e3;
958
+ const absoluteMs = new Date(absoluteExpiresAt).getTime() - Date.now();
959
+ const ms = Math.min(idleMs, absoluteMs);
960
+ cookieOptions.maxAge = ms;
961
+ cookieOptions.expires = new Date(Date.now() + ms);
951
962
  }
952
963
  ctx.cookies.set("strapi_admin_refresh", refreshToken, cookieOptions);
953
- ctx.cookies.set("oidc_authenticated", "1", cookieOptions);
964
+ ctx.cookies.set("oidc_authenticated", "1", { ...cookieOptions, path: "/" });
954
965
  const accessResult = await sessionManager("admin").generateAccessToken(refreshToken);
955
966
  if ("error" in accessResult) {
956
967
  throw new Error(accessResult.error);
@@ -1021,7 +1032,10 @@ function whitelistService({ strapi: strapi2 }) {
1021
1032
  }
1022
1033
  let settings = await getPluginStore().get({ key: "settings" });
1023
1034
  if (!settings) {
1024
- settings = { useWhitelist: true, enforceOIDC: false };
1035
+ settings = {
1036
+ useWhitelist: true,
1037
+ enforceOIDC: false
1038
+ };
1025
1039
  await getPluginStore().set({ key: "settings", value: settings });
1026
1040
  }
1027
1041
  settingsCache = { value: settings, ts: now };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-oidc",
3
- "version": "1.2.3",
3
+ "version": "1.3.1",
4
4
  "description": "A Strapi plugin that provides OpenID Connect (OIDC) authentication functionality for the Strapi Admin Panel.",
5
5
  "strapi": {
6
6
  "displayName": "OIDC Plugin",
@@ -86,7 +86,6 @@
86
86
  "msw": "^2.13.0",
87
87
  "prettier": "^3.8.1",
88
88
  "react": "^18.3.1",
89
- "react-dom": "^18.3.1",
90
89
  "react-router-dom": "^6.30.3",
91
90
  "styled-components": "^6.3.12",
92
91
  "supertest": "^7.2.2",