strapi-plugin-oidc 1.5.1 → 1.5.2

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 CHANGED
@@ -36,27 +36,15 @@ module.exports = ({ env }) => ({
36
36
  OIDC_TOKEN_ENDPOINT: env('OIDC_TOKEN_ENDPOINT'),
37
37
  OIDC_USERINFO_ENDPOINT: env('OIDC_USERINFO_ENDPOINT'),
38
38
 
39
- // Optional
39
+ // Optional — defaults shown
40
40
  OIDC_SCOPE: 'openid profile email',
41
41
  OIDC_GRANT_TYPE: 'authorization_code',
42
42
  OIDC_FAMILY_NAME_FIELD: 'family_name',
43
43
  OIDC_GIVEN_NAME_FIELD: 'given_name',
44
+ OIDC_END_SESSION_ENDPOINT: '', // Provider end-session URL; omit to redirect to Strapi login
44
45
  OIDC_SSO_BUTTON_TEXT: 'Login via SSO',
45
- OIDC_ENFORCE: null, // null = use Admin UI toggle; true/false = override
46
- REMEMBER_ME: false,
47
-
48
- // Optional — RP-Initiated Logout
49
- // Redirects the browser to the provider's end-session page on logout.
50
- // Both found in your provider's /.well-known/openid-configuration.
51
- OIDC_END_SESSION_ENDPOINT: env('OIDC_END_SESSION_ENDPOINT', ''),
52
- OIDC_POST_LOGOUT_REDIRECT_URI: env('OIDC_POST_LOGOUT_REDIRECT_URI', ''),
53
-
54
- // Optional — Backchannel Logout
55
- // Allows the provider to revoke Strapi sessions server-to-server.
56
- // Set your provider's logout URI to: https://your-strapi.com/strapi-plugin-oidc/logout
57
- // Both found in your provider's /.well-known/openid-configuration.
58
- OIDC_ISSUER: env('OIDC_ISSUER', ''),
59
- OIDC_JWKS_URI: env('OIDC_JWKS_URI', ''),
46
+ OIDC_ENFORCE: null, // null = use Admin UI toggle; true/false = override in config
47
+ REMEMBER_ME: false, // Persist session across browser restarts
60
48
  },
61
49
  },
62
50
  });
@@ -146,6 +134,7 @@ This plugin is a hard fork of [`strapi-plugin-sso`](https://github.com/yasudaclo
146
134
 
147
135
  - Removed alternative SSO methods to simplify the plugin.
148
136
  - Redesigned the Whitelist and Role management UI (switched to native Strapi cards, added pagination, etc.).
137
+ - Added an OIDC logout redirect URL.
149
138
  - Added an option to "Enforce OIDC login" with an admin toggle (automatically disabled if the whitelist is empty).
150
139
  - Migrated the testing framework to Vitest and added comprehensive test coverage for controllers and services.
151
140
  - Cleaned up dead code and unused dependencies to improve maintainability.
@@ -157,8 +146,4 @@ This plugin is a hard fork of [`strapi-plugin-sso`](https://github.com/yasudaclo
157
146
  - Bulk delete all entries with a confirmation dialog.
158
147
  - Unsaved changes confirmation when navigating away from the settings page.
159
148
  - Programmatic API for managing the whitelist via Strapi API tokens (list, register, import, delete, delete all).
160
- - **RP-Initiated Logout** (OpenID Connect RP-Initiated Logout 1.0): on logout, Strapi redirects the browser to the provider's end-session endpoint with `id_token_hint` and `post_logout_redirect_uri`, cleanly terminating the SSO session. Configured via `OIDC_END_SESSION_ENDPOINT` and `OIDC_POST_LOGOUT_REDIRECT_URI`.
161
- - **Backchannel Logout** (OIDC Back-Channel Logout 1.0): `POST /strapi-plugin-oidc/logout` accepts a signed logout token from the provider, validates it, and revokes the user's Strapi admin session — keeping Strapi in sync when a user logs out elsewhere. Configured via `OIDC_ISSUER` and `OIDC_JWKS_URI`.
162
- - Renamed config keys to match OIDC discovery document field names: `OIDC_LOGOUT_URL` → `OIDC_END_SESSION_ENDPOINT`, `OIDC_USER_INFO_ENDPOINT` → `OIDC_USERINFO_ENDPOINT`, `OIDC_SCOPES` → `OIDC_SCOPE`.
163
- - Security hardening: PKCE (`S256`), server-side `state` generation (CSRF protection), nonce validation (ID token replay prevention), `Authorization: Bearer` header for userinfo requests, generic error messages on callback failure.
164
149
  - Added misc. quality of life improvements and bug fixes.
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
3
  const node_crypto = require("node:crypto");
4
- const jose = require("jose");
5
4
  const pkceChallenge = require("pkce-challenge");
6
5
  const strapiUtils = require("@strapi/utils");
7
6
  const generator = require("generate-password");
@@ -25,17 +24,6 @@ function resolveEnforceOIDC(strapi2, dbValue) {
25
24
  if (configValue !== null) return configValue;
26
25
  return dbValue ?? false;
27
26
  }
28
- const revoked = /* @__PURE__ */ new Map();
29
- const CLEANUP_DELAY_MS = 24 * 60 * 60 * 1e3;
30
- function revokeUser(userId) {
31
- revoked.set(userId, Date.now());
32
- setTimeout(() => revoked.delete(userId), CLEANUP_DELAY_MS);
33
- }
34
- function isUserRevoked(userId, iat) {
35
- const logoutTime = revoked.get(userId);
36
- if (!logoutTime) return false;
37
- return iat * 1e3 <= logoutTime;
38
- }
39
27
  async function bootstrap({ strapi: strapi2 }) {
40
28
  const enforceOidcMiddleware = async (ctx, next) => {
41
29
  const adminUrl = strapi2.config.get("admin.url", "/admin");
@@ -88,36 +76,9 @@ async function bootstrap({ strapi: strapi2 }) {
88
76
  }
89
77
  await next();
90
78
  };
91
- const denylistMiddleware = async (ctx, next) => {
92
- const auth = ctx.request.headers.authorization;
93
- if (auth?.startsWith("Bearer ")) {
94
- try {
95
- const payload = JSON.parse(
96
- Buffer.from(auth.slice(7).split(".")[1], "base64url").toString()
97
- );
98
- if (payload.id && isUserRevoked(String(payload.id), payload.iat ?? 0)) {
99
- ctx.status = 401;
100
- ctx.body = {
101
- data: null,
102
- error: {
103
- status: 401,
104
- name: "UnauthorizedError",
105
- message: "Session revoked",
106
- details: {}
107
- }
108
- };
109
- return;
110
- }
111
- } catch {
112
- }
113
- }
114
- await next();
115
- };
116
79
  if (strapi2.server.app && Array.isArray(strapi2.server.app.middleware)) {
117
80
  strapi2.server.app.middleware.unshift(enforceOidcMiddleware);
118
- strapi2.server.app.middleware.unshift(denylistMiddleware);
119
81
  } else {
120
- strapi2.server.use(denylistMiddleware);
121
82
  strapi2.server.use(enforceOidcMiddleware);
122
83
  }
123
84
  const actions = [
@@ -208,12 +169,6 @@ const config = {
208
169
  OIDC_FAMILY_NAME_FIELD: "family_name",
209
170
  OIDC_GIVEN_NAME_FIELD: "given_name",
210
171
  OIDC_END_SESSION_ENDPOINT: "",
211
- OIDC_POST_LOGOUT_REDIRECT_URI: "",
212
- // Where to land after the provider has logged the user out (RP-Initiated Logout)
213
- OIDC_ISSUER: "",
214
- // Provider issuer URL — used to validate iss claim in backchannel logout tokens
215
- OIDC_JWKS_URI: "",
216
- // Provider JWKS endpoint — required for backchannel logout token signature verification
217
172
  OIDC_SSO_BUTTON_TEXT: "Login via SSO",
218
173
  OIDC_ENFORCE: null
219
174
  // null = use DB setting; true/false = override DB (useful for lockout recovery)
@@ -266,9 +221,7 @@ function getExpiredCookieOptions(strapi2, ctx) {
266
221
  function clearAuthCookies(strapi2, ctx) {
267
222
  const options2 = getExpiredCookieOptions(strapi2, ctx);
268
223
  ctx.cookies.set("strapi_admin_refresh", "", options2);
269
- const rootPathOptions = { ...options2, path: "/" };
270
- ctx.cookies.set("oidc_authenticated", "", rootPathOptions);
271
- ctx.cookies.set("oidc_id_token", "", rootPathOptions);
224
+ ctx.cookies.set("oidc_authenticated", "", { ...options2, path: "/" });
272
225
  }
273
226
  const REQUIRED_CONFIG_KEYS = [
274
227
  "OIDC_CLIENT_ID",
@@ -350,8 +303,7 @@ async function exchangeTokenAndFetchUserInfo(config2, params, expectedNonce) {
350
303
  if (!userResponse.ok) {
351
304
  throw new Error("Failed to fetch user info");
352
305
  }
353
- const userInfo = await userResponse.json();
354
- return { userInfo, idToken: tokenData.id_token };
306
+ return userResponse.json();
355
307
  }
356
308
  async function registerNewUser(userService, oauthService2, roleService2, email, userResponseData, whitelistUser, config2, ctx) {
357
309
  let roles2 = [];
@@ -417,11 +369,7 @@ async function oidcSignInCallback(ctx) {
417
369
  params.append("grant_type", config2.OIDC_GRANT_TYPE);
418
370
  params.append("code_verifier", codeVerifier ?? "");
419
371
  try {
420
- const { userInfo: userResponseData, idToken } = await exchangeTokenAndFetchUserInfo(
421
- config2,
422
- params,
423
- oidcNonce ?? ""
424
- );
372
+ const userResponseData = await exchangeTokenAndFetchUserInfo(config2, params, oidcNonce ?? "");
425
373
  const { activateUser, jwtToken } = await handleUserAuthentication(
426
374
  userService,
427
375
  oauthService2,
@@ -431,15 +379,6 @@ async function oidcSignInCallback(ctx) {
431
379
  config2,
432
380
  ctx
433
381
  );
434
- if (idToken) {
435
- const isProduction = strapi.config.get("environment") === "production";
436
- ctx.cookies.set("oidc_id_token", idToken, {
437
- httpOnly: true,
438
- secure: isProduction && ctx.request.secure,
439
- path: "/",
440
- sameSite: "lax"
441
- });
442
- }
443
382
  const nonce = node_crypto.randomUUID();
444
383
  const html = oauthService2.renderSignUpSuccess(jwtToken, activateUser, nonce);
445
384
  ctx.set("Content-Security-Policy", `script-src 'nonce-${nonce}'`);
@@ -453,90 +392,18 @@ async function logout(ctx) {
453
392
  const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
454
393
  const logoutUrl = config2.OIDC_END_SESSION_ENDPOINT;
455
394
  const isOidcSession = !!ctx.cookies.get("oidc_authenticated");
456
- const idToken = ctx.cookies.get("oidc_id_token");
457
395
  clearAuthCookies(strapi, ctx);
458
396
  if (logoutUrl && isOidcSession) {
459
- const url = new URL(logoutUrl);
460
- if (idToken) url.searchParams.set("id_token_hint", idToken);
461
- if (config2.OIDC_POST_LOGOUT_REDIRECT_URI) {
462
- url.searchParams.set("post_logout_redirect_uri", config2.OIDC_POST_LOGOUT_REDIRECT_URI);
463
- }
464
- ctx.redirect(url.toString());
397
+ ctx.redirect(logoutUrl);
465
398
  } else {
466
399
  const adminPanelUrl = strapi.config.get("admin.url", "/admin");
467
400
  ctx.redirect(`${adminPanelUrl}/auth/login`);
468
401
  }
469
402
  }
470
- const jwksCache = /* @__PURE__ */ new Map();
471
- function getJWKS(uri) {
472
- const cached = jwksCache.get(uri);
473
- if (cached) return cached;
474
- const jwks = jose.createRemoteJWKSet(new URL(uri));
475
- jwksCache.set(uri, jwks);
476
- return jwks;
477
- }
478
- async function backchannelLogout(ctx) {
479
- const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
480
- const logoutToken = ctx.request.body?.logout_token;
481
- if (!logoutToken) {
482
- ctx.status = 400;
483
- ctx.body = { error: "Missing logout_token" };
484
- return;
485
- }
486
- if (!config2.OIDC_JWKS_URI || !config2.OIDC_ISSUER) {
487
- ctx.status = 501;
488
- ctx.body = {
489
- error: "OIDC_JWKS_URI and OIDC_ISSUER must both be configured to enable backchannel logout"
490
- };
491
- return;
492
- }
493
- try {
494
- const JWKS = getJWKS(config2.OIDC_JWKS_URI);
495
- const verifyOptions = {
496
- issuer: config2.OIDC_ISSUER,
497
- audience: config2.OIDC_CLIENT_ID || void 0
498
- };
499
- const { payload } = await jose.jwtVerify(logoutToken, JWKS, verifyOptions);
500
- if ("nonce" in payload) {
501
- ctx.status = 400;
502
- ctx.body = { error: "logout_token must not contain nonce" };
503
- return;
504
- }
505
- const events = payload.events;
506
- if (!events?.["http://schemas.openid.net/event/backchannel-logout"]) {
507
- ctx.status = 400;
508
- ctx.body = { error: "logout_token missing backchannel-logout event" };
509
- return;
510
- }
511
- if (!payload.sub && !("sid" in payload)) {
512
- ctx.status = 400;
513
- ctx.body = { error: "logout_token must contain sub or sid" };
514
- return;
515
- }
516
- if (payload.sub) {
517
- const userService = strapi.service("admin::user");
518
- const user = await userService.findOneByEmail(payload.sub);
519
- if (user) {
520
- revokeUser(String(user.id));
521
- const sessionManager = strapi.sessionManager;
522
- if (sessionManager) {
523
- await sessionManager("admin").invalidateRefreshToken(String(user.id));
524
- }
525
- }
526
- }
527
- ctx.status = 200;
528
- ctx.body = "";
529
- } catch (e) {
530
- strapi.log.error("Backchannel logout failed:", e);
531
- ctx.status = 400;
532
- ctx.body = { error: "Invalid logout_token" };
533
- }
534
- }
535
403
  const oidc = {
536
404
  oidcSignIn,
537
405
  oidcSignInCallback,
538
- logout,
539
- backchannelLogout
406
+ logout
540
407
  };
541
408
  async function find(ctx) {
542
409
  const roleService2 = strapi.plugin("strapi-plugin-oidc").service("role");
@@ -793,12 +660,6 @@ const routes = {
793
660
  handler: "oidc.logout",
794
661
  config: { auth: false }
795
662
  },
796
- {
797
- method: "POST",
798
- path: "/logout",
799
- handler: "oidc.backchannelLogout",
800
- config: { auth: false }
801
- },
802
663
  {
803
664
  method: "GET",
804
665
  path: "/whitelist",
@@ -1,5 +1,4 @@
1
1
  import { randomUUID, randomBytes } from "node:crypto";
2
- import { jwtVerify, createRemoteJWKSet } from "jose";
3
2
  import pkceChallenge from "pkce-challenge";
4
3
  import strapiUtils from "@strapi/utils";
5
4
  import generator from "generate-password";
@@ -19,17 +18,6 @@ function resolveEnforceOIDC(strapi2, dbValue) {
19
18
  if (configValue !== null) return configValue;
20
19
  return dbValue ?? false;
21
20
  }
22
- const revoked = /* @__PURE__ */ new Map();
23
- const CLEANUP_DELAY_MS = 24 * 60 * 60 * 1e3;
24
- function revokeUser(userId) {
25
- revoked.set(userId, Date.now());
26
- setTimeout(() => revoked.delete(userId), CLEANUP_DELAY_MS);
27
- }
28
- function isUserRevoked(userId, iat) {
29
- const logoutTime = revoked.get(userId);
30
- if (!logoutTime) return false;
31
- return iat * 1e3 <= logoutTime;
32
- }
33
21
  async function bootstrap({ strapi: strapi2 }) {
34
22
  const enforceOidcMiddleware = async (ctx, next) => {
35
23
  const adminUrl = strapi2.config.get("admin.url", "/admin");
@@ -82,36 +70,9 @@ async function bootstrap({ strapi: strapi2 }) {
82
70
  }
83
71
  await next();
84
72
  };
85
- const denylistMiddleware = async (ctx, next) => {
86
- const auth = ctx.request.headers.authorization;
87
- if (auth?.startsWith("Bearer ")) {
88
- try {
89
- const payload = JSON.parse(
90
- Buffer.from(auth.slice(7).split(".")[1], "base64url").toString()
91
- );
92
- if (payload.id && isUserRevoked(String(payload.id), payload.iat ?? 0)) {
93
- ctx.status = 401;
94
- ctx.body = {
95
- data: null,
96
- error: {
97
- status: 401,
98
- name: "UnauthorizedError",
99
- message: "Session revoked",
100
- details: {}
101
- }
102
- };
103
- return;
104
- }
105
- } catch {
106
- }
107
- }
108
- await next();
109
- };
110
73
  if (strapi2.server.app && Array.isArray(strapi2.server.app.middleware)) {
111
74
  strapi2.server.app.middleware.unshift(enforceOidcMiddleware);
112
- strapi2.server.app.middleware.unshift(denylistMiddleware);
113
75
  } else {
114
- strapi2.server.use(denylistMiddleware);
115
76
  strapi2.server.use(enforceOidcMiddleware);
116
77
  }
117
78
  const actions = [
@@ -202,12 +163,6 @@ const config = {
202
163
  OIDC_FAMILY_NAME_FIELD: "family_name",
203
164
  OIDC_GIVEN_NAME_FIELD: "given_name",
204
165
  OIDC_END_SESSION_ENDPOINT: "",
205
- OIDC_POST_LOGOUT_REDIRECT_URI: "",
206
- // Where to land after the provider has logged the user out (RP-Initiated Logout)
207
- OIDC_ISSUER: "",
208
- // Provider issuer URL — used to validate iss claim in backchannel logout tokens
209
- OIDC_JWKS_URI: "",
210
- // Provider JWKS endpoint — required for backchannel logout token signature verification
211
166
  OIDC_SSO_BUTTON_TEXT: "Login via SSO",
212
167
  OIDC_ENFORCE: null
213
168
  // null = use DB setting; true/false = override DB (useful for lockout recovery)
@@ -260,9 +215,7 @@ function getExpiredCookieOptions(strapi2, ctx) {
260
215
  function clearAuthCookies(strapi2, ctx) {
261
216
  const options2 = getExpiredCookieOptions(strapi2, ctx);
262
217
  ctx.cookies.set("strapi_admin_refresh", "", options2);
263
- const rootPathOptions = { ...options2, path: "/" };
264
- ctx.cookies.set("oidc_authenticated", "", rootPathOptions);
265
- ctx.cookies.set("oidc_id_token", "", rootPathOptions);
218
+ ctx.cookies.set("oidc_authenticated", "", { ...options2, path: "/" });
266
219
  }
267
220
  const REQUIRED_CONFIG_KEYS = [
268
221
  "OIDC_CLIENT_ID",
@@ -344,8 +297,7 @@ async function exchangeTokenAndFetchUserInfo(config2, params, expectedNonce) {
344
297
  if (!userResponse.ok) {
345
298
  throw new Error("Failed to fetch user info");
346
299
  }
347
- const userInfo = await userResponse.json();
348
- return { userInfo, idToken: tokenData.id_token };
300
+ return userResponse.json();
349
301
  }
350
302
  async function registerNewUser(userService, oauthService2, roleService2, email, userResponseData, whitelistUser, config2, ctx) {
351
303
  let roles2 = [];
@@ -411,11 +363,7 @@ async function oidcSignInCallback(ctx) {
411
363
  params.append("grant_type", config2.OIDC_GRANT_TYPE);
412
364
  params.append("code_verifier", codeVerifier ?? "");
413
365
  try {
414
- const { userInfo: userResponseData, idToken } = await exchangeTokenAndFetchUserInfo(
415
- config2,
416
- params,
417
- oidcNonce ?? ""
418
- );
366
+ const userResponseData = await exchangeTokenAndFetchUserInfo(config2, params, oidcNonce ?? "");
419
367
  const { activateUser, jwtToken } = await handleUserAuthentication(
420
368
  userService,
421
369
  oauthService2,
@@ -425,15 +373,6 @@ async function oidcSignInCallback(ctx) {
425
373
  config2,
426
374
  ctx
427
375
  );
428
- if (idToken) {
429
- const isProduction = strapi.config.get("environment") === "production";
430
- ctx.cookies.set("oidc_id_token", idToken, {
431
- httpOnly: true,
432
- secure: isProduction && ctx.request.secure,
433
- path: "/",
434
- sameSite: "lax"
435
- });
436
- }
437
376
  const nonce = randomUUID();
438
377
  const html = oauthService2.renderSignUpSuccess(jwtToken, activateUser, nonce);
439
378
  ctx.set("Content-Security-Policy", `script-src 'nonce-${nonce}'`);
@@ -447,90 +386,18 @@ async function logout(ctx) {
447
386
  const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
448
387
  const logoutUrl = config2.OIDC_END_SESSION_ENDPOINT;
449
388
  const isOidcSession = !!ctx.cookies.get("oidc_authenticated");
450
- const idToken = ctx.cookies.get("oidc_id_token");
451
389
  clearAuthCookies(strapi, ctx);
452
390
  if (logoutUrl && isOidcSession) {
453
- const url = new URL(logoutUrl);
454
- if (idToken) url.searchParams.set("id_token_hint", idToken);
455
- if (config2.OIDC_POST_LOGOUT_REDIRECT_URI) {
456
- url.searchParams.set("post_logout_redirect_uri", config2.OIDC_POST_LOGOUT_REDIRECT_URI);
457
- }
458
- ctx.redirect(url.toString());
391
+ ctx.redirect(logoutUrl);
459
392
  } else {
460
393
  const adminPanelUrl = strapi.config.get("admin.url", "/admin");
461
394
  ctx.redirect(`${adminPanelUrl}/auth/login`);
462
395
  }
463
396
  }
464
- const jwksCache = /* @__PURE__ */ new Map();
465
- function getJWKS(uri) {
466
- const cached = jwksCache.get(uri);
467
- if (cached) return cached;
468
- const jwks = createRemoteJWKSet(new URL(uri));
469
- jwksCache.set(uri, jwks);
470
- return jwks;
471
- }
472
- async function backchannelLogout(ctx) {
473
- const config2 = strapi.config.get("plugin::strapi-plugin-oidc");
474
- const logoutToken = ctx.request.body?.logout_token;
475
- if (!logoutToken) {
476
- ctx.status = 400;
477
- ctx.body = { error: "Missing logout_token" };
478
- return;
479
- }
480
- if (!config2.OIDC_JWKS_URI || !config2.OIDC_ISSUER) {
481
- ctx.status = 501;
482
- ctx.body = {
483
- error: "OIDC_JWKS_URI and OIDC_ISSUER must both be configured to enable backchannel logout"
484
- };
485
- return;
486
- }
487
- try {
488
- const JWKS = getJWKS(config2.OIDC_JWKS_URI);
489
- const verifyOptions = {
490
- issuer: config2.OIDC_ISSUER,
491
- audience: config2.OIDC_CLIENT_ID || void 0
492
- };
493
- const { payload } = await jwtVerify(logoutToken, JWKS, verifyOptions);
494
- if ("nonce" in payload) {
495
- ctx.status = 400;
496
- ctx.body = { error: "logout_token must not contain nonce" };
497
- return;
498
- }
499
- const events = payload.events;
500
- if (!events?.["http://schemas.openid.net/event/backchannel-logout"]) {
501
- ctx.status = 400;
502
- ctx.body = { error: "logout_token missing backchannel-logout event" };
503
- return;
504
- }
505
- if (!payload.sub && !("sid" in payload)) {
506
- ctx.status = 400;
507
- ctx.body = { error: "logout_token must contain sub or sid" };
508
- return;
509
- }
510
- if (payload.sub) {
511
- const userService = strapi.service("admin::user");
512
- const user = await userService.findOneByEmail(payload.sub);
513
- if (user) {
514
- revokeUser(String(user.id));
515
- const sessionManager = strapi.sessionManager;
516
- if (sessionManager) {
517
- await sessionManager("admin").invalidateRefreshToken(String(user.id));
518
- }
519
- }
520
- }
521
- ctx.status = 200;
522
- ctx.body = "";
523
- } catch (e) {
524
- strapi.log.error("Backchannel logout failed:", e);
525
- ctx.status = 400;
526
- ctx.body = { error: "Invalid logout_token" };
527
- }
528
- }
529
397
  const oidc = {
530
398
  oidcSignIn,
531
399
  oidcSignInCallback,
532
- logout,
533
- backchannelLogout
400
+ logout
534
401
  };
535
402
  async function find(ctx) {
536
403
  const roleService2 = strapi.plugin("strapi-plugin-oidc").service("role");
@@ -787,12 +654,6 @@ const routes = {
787
654
  handler: "oidc.logout",
788
655
  config: { auth: false }
789
656
  },
790
- {
791
- method: "POST",
792
- path: "/logout",
793
- handler: "oidc.backchannelLogout",
794
- config: { auth: false }
795
- },
796
657
  {
797
658
  method: "GET",
798
659
  path: "/whitelist",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-oidc",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
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",
@@ -50,7 +50,6 @@
50
50
  "@strapi/icons": "^2.2.0",
51
51
  "@strapi/utils": "^5.41.1",
52
52
  "generate-password": "^1.7.1",
53
- "jose": "^6.2.2",
54
53
  "pkce-challenge": "^6.0.0",
55
54
  "react-intl": "^6.8.9"
56
55
  },
@@ -82,8 +81,6 @@
82
81
  "@eslint/eslintrc": "^3.3.5",
83
82
  "@eslint/js": "^10.0.1",
84
83
  "@strapi/sdk-plugin": "^6.0.1",
85
- "@strapi/types": "^5.41.1",
86
- "@types/koa": "^2.16.4",
87
84
  "@types/node": "^25.5.2",
88
85
  "@types/supertest": "^7.2.0",
89
86
  "@vitest/coverage-v8": "^4.1.2",