strapi-plugin-oidc 1.10.2 → 1.10.4
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 +12 -21
- package/dist/admin/{index-B-sTTO3a.js → index-COhAwRD-.js} +40 -16
- package/dist/admin/{index-DnhzQm30.mjs → index-D0Q_r3J6.mjs} +40 -16
- package/dist/admin/{index-DN2ccKqO.js → index-DgrNKY9Y.js} +1 -1
- package/dist/admin/{index-Dn8QUbkK.mjs → index-SjMPr_u2.mjs} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +26 -9
- package/dist/server/index.mjs +26 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,10 +35,10 @@ module.exports = ({ env }) => ({
|
|
|
35
35
|
enabled: true,
|
|
36
36
|
config: {
|
|
37
37
|
// Required
|
|
38
|
+
OIDC_PUBLIC_URL: env('PUBLIC_URL', 'https://strapi.example.com'), // origin only — we append /strapi-plugin-oidc/oidc/callback
|
|
38
39
|
OIDC_ISSUER: env('OIDC_ISSUER'), // https://your-provider or https://your-provider/realms/your-realm
|
|
39
40
|
OIDC_CLIENT_ID: env('OIDC_CLIENT_ID'),
|
|
40
41
|
OIDC_CLIENT_SECRET: env('OIDC_CLIENT_SECRET'),
|
|
41
|
-
OIDC_REDIRECT_URI: env('OIDC_REDIRECT_URI'), // https://your-strapi.com/strapi-plugin-oidc/oidc/callback
|
|
42
42
|
|
|
43
43
|
// Optional — defaults shown
|
|
44
44
|
OIDC_SCOPE: 'openid profile email', // space-separated scopes
|
|
@@ -59,6 +59,8 @@ module.exports = ({ env }) => ({
|
|
|
59
59
|
});
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
`OIDC_PUBLIC_URL` is your Strapi instance's origin (e.g. `https://myapp.com`). The plugin appends `/strapi-plugin-oidc/oidc/callback` to form the full OIDC redirect URI. If unset, falls back to the `PUBLIC_URL` environment variable. Only provide the scheme + host + port — no trailing slash or path.
|
|
63
|
+
|
|
62
64
|
`OIDC_ISSUER` is your provider's issuer URL (e.g. `https://auth.example.com` or `https://auth.example.com/realms/myrealm`). The plugin appends `/.well-known/openid-configuration` automatically if not present, and fetches the discovery document at startup to configure all endpoints, JWKS URI, and canonical issuer.
|
|
63
65
|
|
|
64
66
|
### Security features
|
|
@@ -98,17 +100,6 @@ Only headers that CDN/proxy vendors guarantee to strip from inbound client reque
|
|
|
98
100
|
|
|
99
101
|
Navigate to `/strapi-plugin-oidc/oidc` to start the OIDC flow, or click the **Login via SSO** button injected into the Strapi login page.
|
|
100
102
|
|
|
101
|
-
## Skip Login Page
|
|
102
|
-
|
|
103
|
-
Set `OIDC_SKIP_LOGIN_PAGE: true` to prevent users from ever seeing the Strapi admin login page. Unauthenticated requests are redirected directly to the OIDC provider. This is typically used alongside `OIDC_ENFORCE: true`.
|
|
104
|
-
|
|
105
|
-
Two independent mechanisms cover both entry points:
|
|
106
|
-
|
|
107
|
-
- **Server-side** — A Koa middleware intercepts unauthenticated GET requests to `/admin` and redirects to `/strapi-plugin-oidc/oidc` before the SPA is served. Excluded from this redirect: API routes (`/admin/login`, `/admin/logout`, `/admin/init`, etc.), static assets (`.js`, `.css`, `.png`, etc.), and POST requests.
|
|
108
|
-
- **Client-side** — A DOM `MutationObserver` watches for React Router navigations to `/auth/login` (triggered by session expiry or 401 responses) and redirects before the login form renders.
|
|
109
|
-
|
|
110
|
-
After logout without a provider `end_session_endpoint`, the fallback URL becomes `/strapi-plugin-oidc/oidc` instead of `/admin/auth/login`, ensuring the user lands on the provider's own page.
|
|
111
|
-
|
|
112
103
|
## Logout
|
|
113
104
|
|
|
114
105
|
When the discovery document includes an `end_session_endpoint`, clicking logout redirects to the provider's end-session URL (RP-initiated logout). If the provider session has already expired, Strapi skips the redirect and goes straight to the login page.
|
|
@@ -212,30 +203,30 @@ Duplicate emails within the payload and emails already in the whitelist are sile
|
|
|
212
203
|
```bash
|
|
213
204
|
# List
|
|
214
205
|
curl -H "Authorization: Bearer <token>" \
|
|
215
|
-
|
|
206
|
+
https://strapi.example.com/api/strapi-plugin-oidc/whitelist
|
|
216
207
|
|
|
217
208
|
# Export
|
|
218
209
|
curl -H "Authorization: Bearer <token>" \
|
|
219
|
-
|
|
210
|
+
https://strapi.example.com/api/strapi-plugin-oidc/whitelist/export \
|
|
220
211
|
-o whitelist.json
|
|
221
212
|
|
|
222
213
|
# Add
|
|
223
214
|
curl -X POST -H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
|
|
224
215
|
-d '{"email": "user@example.com"}' \
|
|
225
|
-
|
|
216
|
+
https://strapi.example.com/api/strapi-plugin-oidc/whitelist
|
|
226
217
|
|
|
227
218
|
# Bulk import
|
|
228
219
|
curl -X POST -H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
|
|
229
220
|
-d '{"users": [{"email": "a@example.com"}, {"email": "b@example.com"}]}' \
|
|
230
|
-
|
|
221
|
+
https://strapi.example.com/api/strapi-plugin-oidc/whitelist/import
|
|
231
222
|
|
|
232
223
|
# Delete one (by email)
|
|
233
224
|
curl -X DELETE -H "Authorization: Bearer <token>" \
|
|
234
|
-
"
|
|
225
|
+
"https://strapi.example.com/api/strapi-plugin-oidc/whitelist/user%40example.com"
|
|
235
226
|
|
|
236
227
|
# Delete all
|
|
237
228
|
curl -X DELETE -H "Authorization: Bearer <token>" \
|
|
238
|
-
|
|
229
|
+
https://strapi.example.com/api/strapi-plugin-oidc/whitelist
|
|
239
230
|
```
|
|
240
231
|
|
|
241
232
|
## Audit Log API
|
|
@@ -303,7 +294,7 @@ curl -H "Authorization: Bearer <token>" -G \
|
|
|
303
294
|
--data-urlencode 'filters[action][$eq]=login_failure' \
|
|
304
295
|
--data-urlencode 'filters[createdAt][$gte]=2026-04-08T00:00:00.000Z' \
|
|
305
296
|
--data-urlencode 'filters[createdAt][$lt]=2026-04-09T00:00:00.000Z' \
|
|
306
|
-
|
|
297
|
+
https://strapi.example.com/api/strapi-plugin-oidc/audit-logs
|
|
307
298
|
```
|
|
308
299
|
|
|
309
300
|
### Recorded actions
|
|
@@ -330,11 +321,11 @@ Each event is also emitted on Strapi's internal eventHub as `strapi-plugin-oidc:
|
|
|
330
321
|
```bash
|
|
331
322
|
# Paginated list
|
|
332
323
|
curl -H "Authorization: Bearer <token>" \
|
|
333
|
-
"
|
|
324
|
+
"https://strapi.example.com/api/strapi-plugin-oidc/audit-logs?page=1&pageSize=50"
|
|
334
325
|
|
|
335
326
|
# NDJSON export
|
|
336
327
|
curl -H "Authorization: Bearer <token>" \
|
|
337
|
-
|
|
328
|
+
https://strapi.example.com/api/strapi-plugin-oidc/audit-logs/export \
|
|
338
329
|
-o oidc-audit-log.ndjson
|
|
339
330
|
```
|
|
340
331
|
|
|
@@ -198,10 +198,25 @@ const AUDIT_LOG_DEFAULTS = {
|
|
|
198
198
|
ADMIN_PAGE_SIZE: 10
|
|
199
199
|
};
|
|
200
200
|
const OIDC_SIGN_IN_PATH = "/strapi-plugin-oidc/oidc";
|
|
201
|
+
const AUTH_ROUTES = [
|
|
202
|
+
"login",
|
|
203
|
+
"register",
|
|
204
|
+
"register-admin",
|
|
205
|
+
"forgot-password",
|
|
206
|
+
"reset-password"
|
|
207
|
+
];
|
|
208
|
+
const JWT_TOKEN_KEY = "jwtToken";
|
|
201
209
|
const UI_DEFAULTS = {
|
|
202
210
|
MIN_SPINNER_MS: 400
|
|
203
211
|
};
|
|
204
212
|
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
213
|
+
function shouldRedirectToOidc(params) {
|
|
214
|
+
const isServerBounce = params.search.includes("oidc_redirect=1");
|
|
215
|
+
if (isServerBounce) return false;
|
|
216
|
+
const hasToken = params.localStorage.getItem(JWT_TOKEN_KEY) || params.cookies.split(";").some((c) => c.trim().startsWith(`${JWT_TOKEN_KEY}=`));
|
|
217
|
+
if (hasToken) return false;
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
205
220
|
const name = pluginPkg.strapi.displayName;
|
|
206
221
|
const index = {
|
|
207
222
|
register(app) {
|
|
@@ -212,7 +227,7 @@ const index = {
|
|
|
212
227
|
id: "settings.configuration",
|
|
213
228
|
defaultMessage: "Configuration"
|
|
214
229
|
},
|
|
215
|
-
Component: () => Promise.resolve().then(() => require("./index-
|
|
230
|
+
Component: () => Promise.resolve().then(() => require("./index-DgrNKY9Y.js")),
|
|
216
231
|
permissions: [{ action: PERMISSIONS.READ, subject: null }]
|
|
217
232
|
};
|
|
218
233
|
app.addSettingsLink(
|
|
@@ -232,10 +247,19 @@ const index = {
|
|
|
232
247
|
});
|
|
233
248
|
},
|
|
234
249
|
bootstrap() {
|
|
235
|
-
const
|
|
236
|
-
const
|
|
237
|
-
|
|
250
|
+
const authRouteNames = AUTH_ROUTES.filter((r) => r !== "register-admin");
|
|
251
|
+
const authRoutePattern = new RegExp(`/auth/(${authRouteNames.join("|")})`);
|
|
252
|
+
const isAuthRoute = (path) => authRoutePattern.test(path);
|
|
253
|
+
if (shouldRedirectToOidc({
|
|
254
|
+
search: window.location.search,
|
|
255
|
+
localStorage: window.localStorage,
|
|
256
|
+
cookies: document.cookie
|
|
257
|
+
})) {
|
|
258
|
+
document.documentElement.innerHTML = "";
|
|
238
259
|
window.location.replace(OIDC_SIGN_IN_PATH);
|
|
260
|
+
setTimeout(() => {
|
|
261
|
+
window.location.href = OIDC_SIGN_IN_PATH;
|
|
262
|
+
}, 2e3);
|
|
239
263
|
return;
|
|
240
264
|
}
|
|
241
265
|
const overlayContainer = document.createElement("div");
|
|
@@ -317,16 +341,16 @@ const index = {
|
|
|
317
341
|
const applySettings = async () => {
|
|
318
342
|
try {
|
|
319
343
|
const response = await window.fetch("/strapi-plugin-oidc/settings/public");
|
|
320
|
-
if (response.ok) {
|
|
321
|
-
const data = await response.json();
|
|
322
|
-
if (data.skipLoginPage) {
|
|
323
|
-
startSkipLoginRedirect();
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
startLoginObserver(data.ssoButtonText || defaultButtonText, !!data.enforceOIDC);
|
|
327
|
-
} else {
|
|
344
|
+
if (!response.ok) {
|
|
328
345
|
startLoginObserver(defaultButtonText, false);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const data = await response.json();
|
|
349
|
+
if (data.skipLoginPage) {
|
|
350
|
+
startSkipLoginRedirect();
|
|
351
|
+
return;
|
|
329
352
|
}
|
|
353
|
+
startLoginObserver(data.ssoButtonText || defaultButtonText, !!data.enforceOIDC);
|
|
330
354
|
} catch (error) {
|
|
331
355
|
startLoginObserver(defaultButtonText, false);
|
|
332
356
|
console.error("Failed to fetch OIDC settings:", error);
|
|
@@ -341,12 +365,12 @@ const index = {
|
|
|
341
365
|
const isLogout = url?.endsWith("/admin/logout") && args[1]?.method?.toUpperCase() === "POST";
|
|
342
366
|
if (isLogout) {
|
|
343
367
|
window.dispatchEvent(new CustomEvent(LOGOUT_EVENT));
|
|
344
|
-
window.localStorage.removeItem(
|
|
368
|
+
window.localStorage.removeItem(JWT_TOKEN_KEY);
|
|
345
369
|
window.localStorage.removeItem("isLoggedIn");
|
|
346
|
-
window.sessionStorage.removeItem(
|
|
370
|
+
window.sessionStorage.removeItem(JWT_TOKEN_KEY);
|
|
347
371
|
window.sessionStorage.removeItem("isLoggedIn");
|
|
348
|
-
document.cookie =
|
|
349
|
-
document.cookie =
|
|
372
|
+
document.cookie = `${JWT_TOKEN_KEY}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
|
|
373
|
+
document.cookie = `${JWT_TOKEN_KEY}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/admin`;
|
|
350
374
|
originalFetch(...args).catch(() => {
|
|
351
375
|
});
|
|
352
376
|
window.location.href = "/strapi-plugin-oidc/logout";
|
|
@@ -195,10 +195,25 @@ const AUDIT_LOG_DEFAULTS = {
|
|
|
195
195
|
ADMIN_PAGE_SIZE: 10
|
|
196
196
|
};
|
|
197
197
|
const OIDC_SIGN_IN_PATH = "/strapi-plugin-oidc/oidc";
|
|
198
|
+
const AUTH_ROUTES = [
|
|
199
|
+
"login",
|
|
200
|
+
"register",
|
|
201
|
+
"register-admin",
|
|
202
|
+
"forgot-password",
|
|
203
|
+
"reset-password"
|
|
204
|
+
];
|
|
205
|
+
const JWT_TOKEN_KEY = "jwtToken";
|
|
198
206
|
const UI_DEFAULTS = {
|
|
199
207
|
MIN_SPINNER_MS: 400
|
|
200
208
|
};
|
|
201
209
|
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
210
|
+
function shouldRedirectToOidc(params) {
|
|
211
|
+
const isServerBounce = params.search.includes("oidc_redirect=1");
|
|
212
|
+
if (isServerBounce) return false;
|
|
213
|
+
const hasToken = params.localStorage.getItem(JWT_TOKEN_KEY) || params.cookies.split(";").some((c) => c.trim().startsWith(`${JWT_TOKEN_KEY}=`));
|
|
214
|
+
if (hasToken) return false;
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
202
217
|
const name = pluginPkg.strapi.displayName;
|
|
203
218
|
const index = {
|
|
204
219
|
register(app) {
|
|
@@ -209,7 +224,7 @@ const index = {
|
|
|
209
224
|
id: "settings.configuration",
|
|
210
225
|
defaultMessage: "Configuration"
|
|
211
226
|
},
|
|
212
|
-
Component: () => import("./index-
|
|
227
|
+
Component: () => import("./index-SjMPr_u2.mjs"),
|
|
213
228
|
permissions: [{ action: PERMISSIONS.READ, subject: null }]
|
|
214
229
|
};
|
|
215
230
|
app.addSettingsLink(
|
|
@@ -229,10 +244,19 @@ const index = {
|
|
|
229
244
|
});
|
|
230
245
|
},
|
|
231
246
|
bootstrap() {
|
|
232
|
-
const
|
|
233
|
-
const
|
|
234
|
-
|
|
247
|
+
const authRouteNames = AUTH_ROUTES.filter((r) => r !== "register-admin");
|
|
248
|
+
const authRoutePattern = new RegExp(`/auth/(${authRouteNames.join("|")})`);
|
|
249
|
+
const isAuthRoute = (path) => authRoutePattern.test(path);
|
|
250
|
+
if (shouldRedirectToOidc({
|
|
251
|
+
search: window.location.search,
|
|
252
|
+
localStorage: window.localStorage,
|
|
253
|
+
cookies: document.cookie
|
|
254
|
+
})) {
|
|
255
|
+
document.documentElement.innerHTML = "";
|
|
235
256
|
window.location.replace(OIDC_SIGN_IN_PATH);
|
|
257
|
+
setTimeout(() => {
|
|
258
|
+
window.location.href = OIDC_SIGN_IN_PATH;
|
|
259
|
+
}, 2e3);
|
|
236
260
|
return;
|
|
237
261
|
}
|
|
238
262
|
const overlayContainer = document.createElement("div");
|
|
@@ -314,16 +338,16 @@ const index = {
|
|
|
314
338
|
const applySettings = async () => {
|
|
315
339
|
try {
|
|
316
340
|
const response = await window.fetch("/strapi-plugin-oidc/settings/public");
|
|
317
|
-
if (response.ok) {
|
|
318
|
-
const data = await response.json();
|
|
319
|
-
if (data.skipLoginPage) {
|
|
320
|
-
startSkipLoginRedirect();
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
startLoginObserver(data.ssoButtonText || defaultButtonText, !!data.enforceOIDC);
|
|
324
|
-
} else {
|
|
341
|
+
if (!response.ok) {
|
|
325
342
|
startLoginObserver(defaultButtonText, false);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const data = await response.json();
|
|
346
|
+
if (data.skipLoginPage) {
|
|
347
|
+
startSkipLoginRedirect();
|
|
348
|
+
return;
|
|
326
349
|
}
|
|
350
|
+
startLoginObserver(data.ssoButtonText || defaultButtonText, !!data.enforceOIDC);
|
|
327
351
|
} catch (error) {
|
|
328
352
|
startLoginObserver(defaultButtonText, false);
|
|
329
353
|
console.error("Failed to fetch OIDC settings:", error);
|
|
@@ -338,12 +362,12 @@ const index = {
|
|
|
338
362
|
const isLogout = url?.endsWith("/admin/logout") && args[1]?.method?.toUpperCase() === "POST";
|
|
339
363
|
if (isLogout) {
|
|
340
364
|
window.dispatchEvent(new CustomEvent(LOGOUT_EVENT));
|
|
341
|
-
window.localStorage.removeItem(
|
|
365
|
+
window.localStorage.removeItem(JWT_TOKEN_KEY);
|
|
342
366
|
window.localStorage.removeItem("isLoggedIn");
|
|
343
|
-
window.sessionStorage.removeItem(
|
|
367
|
+
window.sessionStorage.removeItem(JWT_TOKEN_KEY);
|
|
344
368
|
window.sessionStorage.removeItem("isLoggedIn");
|
|
345
|
-
document.cookie =
|
|
346
|
-
document.cookie =
|
|
369
|
+
document.cookie = `${JWT_TOKEN_KEY}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
|
|
370
|
+
document.cookie = `${JWT_TOKEN_KEY}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/admin`;
|
|
347
371
|
originalFetch(...args).catch(() => {
|
|
348
372
|
});
|
|
349
373
|
window.location.href = "/strapi-plugin-oidc/logout";
|
|
@@ -7,7 +7,7 @@ const React = require("react");
|
|
|
7
7
|
const designSystem = require("@strapi/design-system");
|
|
8
8
|
const icons = require("@strapi/icons");
|
|
9
9
|
const reactIntl = require("react-intl");
|
|
10
|
-
const index = require("./index-
|
|
10
|
+
const index = require("./index-COhAwRD-.js");
|
|
11
11
|
const styled = require("styled-components");
|
|
12
12
|
const lucideReact = require("lucide-react");
|
|
13
13
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
@@ -5,7 +5,7 @@ import { useState, useRef, useId, useEffect, useCallback, useReducer, useMemo, m
|
|
|
5
5
|
import { Typography, Flex, Box, MultiSelect, MultiSelectOption, Button, Dialog, Table, Pagination, PreviousLink, NextLink, PageLink, Field, Divider, Thead, Tr, Th, Tbody, Td, IconButton, Loader, Tooltip, Alert } from "@strapi/design-system";
|
|
6
6
|
import { Cross, WarningCircle, Plus, Download, Upload, Trash, Calendar, Mail, Information } from "@strapi/icons";
|
|
7
7
|
import { useIntl } from "react-intl";
|
|
8
|
-
import { g as getTrad, E as EMAIL_REGEX, e as en, A as AUDIT_LOG_DEFAULTS, U as UI_DEFAULTS } from "./index-
|
|
8
|
+
import { g as getTrad, E as EMAIL_REGEX, e as en, A as AUDIT_LOG_DEFAULTS, U as UI_DEFAULTS } from "./index-D0Q_r3J6.mjs";
|
|
9
9
|
import styled from "styled-components";
|
|
10
10
|
import { Filter, ClipboardList, Server } from "lucide-react";
|
|
11
11
|
function Role({ oidcRoles, roles, onChangeRole }) {
|
package/dist/admin/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
-
const index = require("./index-
|
|
3
|
+
const index = require("./index-COhAwRD-.js");
|
|
4
4
|
require("react");
|
|
5
5
|
require("react-dom/client");
|
|
6
6
|
exports.default = index.index;
|
package/dist/admin/index.mjs
CHANGED
package/dist/server/index.js
CHANGED
|
@@ -103,7 +103,7 @@ const coerceBoolNullable = zod.z.preprocess(
|
|
|
103
103
|
);
|
|
104
104
|
const pluginConfigSchema = zod.z.object({
|
|
105
105
|
REMEMBER_ME: coerceBool(false),
|
|
106
|
-
|
|
106
|
+
OIDC_PUBLIC_URL: zod.z.string().default(""),
|
|
107
107
|
OIDC_CLIENT_ID: zod.z.string().default(""),
|
|
108
108
|
OIDC_CLIENT_SECRET: zod.z.string().default(""),
|
|
109
109
|
OIDC_SCOPE: zod.z.string().default("openid profile email"),
|
|
@@ -175,6 +175,14 @@ const DAY_MS = 864e5;
|
|
|
175
175
|
const DISCOVERY_TIMEOUT_MS = 5e3;
|
|
176
176
|
const OIDC_DISCOVERY_PATH = "/.well-known/openid-configuration";
|
|
177
177
|
const OIDC_SIGN_IN_PATH = "/strapi-plugin-oidc/oidc";
|
|
178
|
+
const OIDC_CALLBACK_PATH = "/strapi-plugin-oidc/oidc/callback";
|
|
179
|
+
const AUTH_ROUTES = [
|
|
180
|
+
"login",
|
|
181
|
+
"register",
|
|
182
|
+
"register-admin",
|
|
183
|
+
"forgot-password",
|
|
184
|
+
"reset-password"
|
|
185
|
+
];
|
|
178
186
|
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
179
187
|
function getPluginConfig() {
|
|
180
188
|
return pluginConfigSchema.parse(strapi.config.get("plugin::strapi-plugin-oidc") ?? {});
|
|
@@ -285,11 +293,11 @@ function clearAuthCookies(strapi2, ctx) {
|
|
|
285
293
|
ctx.cookies.set(COOKIE_NAMES.accessToken, "", rootPathOptions);
|
|
286
294
|
ctx.cookies.set(COOKIE_NAMES.userEmail, "", rootPathOptions);
|
|
287
295
|
}
|
|
288
|
-
const AUTH_ROUTES = ["login", "register", "register-admin", "forgot-password", "reset-password"];
|
|
289
296
|
const STATIC_EXTENSIONS = [".js", ".css", ".png", ".svg", ".ico", ".woff2", ".json", ".map"];
|
|
290
297
|
async function bootstrap({ strapi: strapi2 }) {
|
|
291
298
|
await applyDiscovery(strapi2);
|
|
292
|
-
const
|
|
299
|
+
const rawAdminUrl = strapi2.config.get("admin.url");
|
|
300
|
+
const adminUrl = typeof rawAdminUrl === "string" && rawAdminUrl.length > 0 ? rawAdminUrl : "/admin";
|
|
293
301
|
const tokenRefreshPath = `${adminUrl}/token/refresh`;
|
|
294
302
|
const EXCLUDED_ADMIN_PATHS = [
|
|
295
303
|
`${adminUrl}/login`,
|
|
@@ -415,7 +423,6 @@ function destroy() {
|
|
|
415
423
|
const config = {
|
|
416
424
|
default: {
|
|
417
425
|
REMEMBER_ME: false,
|
|
418
|
-
OIDC_REDIRECT_URI: "http://localhost:1337/strapi-plugin-oidc/oidc/callback",
|
|
419
426
|
OIDC_CLIENT_ID: "",
|
|
420
427
|
OIDC_CLIENT_SECRET: "",
|
|
421
428
|
OIDC_SCOPE: "openid profile email",
|
|
@@ -555,7 +562,6 @@ const REQUIRED_CONFIG_KEYS = [
|
|
|
555
562
|
"OIDC_ISSUER",
|
|
556
563
|
"OIDC_CLIENT_ID",
|
|
557
564
|
"OIDC_CLIENT_SECRET",
|
|
558
|
-
"OIDC_REDIRECT_URI",
|
|
559
565
|
"OIDC_SCOPE",
|
|
560
566
|
"OIDC_FAMILY_NAME_FIELD",
|
|
561
567
|
"OIDC_GIVEN_NAME_FIELD",
|
|
@@ -564,6 +570,15 @@ const REQUIRED_CONFIG_KEYS = [
|
|
|
564
570
|
"OIDC_USERINFO_ENDPOINT",
|
|
565
571
|
"OIDC_AUTHORIZATION_ENDPOINT"
|
|
566
572
|
];
|
|
573
|
+
function resolveRedirectUri(config2) {
|
|
574
|
+
const publicUrl = config2.OIDC_PUBLIC_URL || process.env.PUBLIC_URL || (process.env.NODE_ENV !== "production" ? "http://localhost:1337" : "");
|
|
575
|
+
if (!publicUrl) {
|
|
576
|
+
throw new Error(
|
|
577
|
+
"OIDC_PUBLIC_URL or PUBLIC_URL must be set in production. Provide your Strapi origin (e.g. https://myapp.com)."
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
return `${publicUrl}${OIDC_CALLBACK_PATH}`;
|
|
581
|
+
}
|
|
567
582
|
const jwksCache = /* @__PURE__ */ new Map();
|
|
568
583
|
let jwksDisabledWarned = false;
|
|
569
584
|
function getJwks(uri) {
|
|
@@ -3609,11 +3624,12 @@ async function oidcSignIn(ctx) {
|
|
|
3609
3624
|
try {
|
|
3610
3625
|
const config2 = configValidation();
|
|
3611
3626
|
if (!config2.OIDC_SKIP_LOGIN_PAGE) {
|
|
3612
|
-
const
|
|
3627
|
+
const raw = strapi.config.get("admin.url");
|
|
3628
|
+
const adminUrl = typeof raw === "string" && raw.length > 0 ? raw : "/admin";
|
|
3613
3629
|
ctx.redirect(`${adminUrl}/auth/login?oidc_redirect=1`);
|
|
3614
3630
|
return;
|
|
3615
3631
|
}
|
|
3616
|
-
const { OIDC_CLIENT_ID,
|
|
3632
|
+
const { OIDC_CLIENT_ID, OIDC_SCOPE, OIDC_AUTHORIZATION_ENDPOINT } = config2;
|
|
3617
3633
|
const { code_verifier: codeVerifier, code_challenge: codeChallenge } = await pkceChallenge__default.default();
|
|
3618
3634
|
const state = node_crypto.randomBytes(32).toString("base64url");
|
|
3619
3635
|
const nonce = node_crypto.randomBytes(32).toString("base64url");
|
|
@@ -3626,10 +3642,11 @@ async function oidcSignIn(ctx) {
|
|
|
3626
3642
|
ctx.cookies.set(COOKIE_NAMES.codeVerifier, codeVerifier, cookieOptions);
|
|
3627
3643
|
ctx.cookies.set(COOKIE_NAMES.state, state, cookieOptions);
|
|
3628
3644
|
ctx.cookies.set(COOKIE_NAMES.nonce, nonce, cookieOptions);
|
|
3645
|
+
const redirectUri = resolveRedirectUri(config2);
|
|
3629
3646
|
const params = new URLSearchParams({
|
|
3630
3647
|
response_type: "code",
|
|
3631
3648
|
client_id: OIDC_CLIENT_ID,
|
|
3632
|
-
redirect_uri:
|
|
3649
|
+
redirect_uri: redirectUri,
|
|
3633
3650
|
scope: OIDC_SCOPE,
|
|
3634
3651
|
code_challenge: codeChallenge,
|
|
3635
3652
|
code_challenge_method: "S256",
|
|
@@ -3974,7 +3991,7 @@ async function oidcSignInCallback(ctx) {
|
|
|
3974
3991
|
code: String(ctx.query.code),
|
|
3975
3992
|
client_id: config2.OIDC_CLIENT_ID,
|
|
3976
3993
|
client_secret: config2.OIDC_CLIENT_SECRET,
|
|
3977
|
-
redirect_uri: config2
|
|
3994
|
+
redirect_uri: resolveRedirectUri(config2),
|
|
3978
3995
|
grant_type: "authorization_code",
|
|
3979
3996
|
code_verifier: codeVerifier ?? ""
|
|
3980
3997
|
});
|
package/dist/server/index.mjs
CHANGED
|
@@ -97,7 +97,7 @@ const coerceBoolNullable = z.preprocess(
|
|
|
97
97
|
);
|
|
98
98
|
const pluginConfigSchema = z.object({
|
|
99
99
|
REMEMBER_ME: coerceBool(false),
|
|
100
|
-
|
|
100
|
+
OIDC_PUBLIC_URL: z.string().default(""),
|
|
101
101
|
OIDC_CLIENT_ID: z.string().default(""),
|
|
102
102
|
OIDC_CLIENT_SECRET: z.string().default(""),
|
|
103
103
|
OIDC_SCOPE: z.string().default("openid profile email"),
|
|
@@ -169,6 +169,14 @@ const DAY_MS = 864e5;
|
|
|
169
169
|
const DISCOVERY_TIMEOUT_MS = 5e3;
|
|
170
170
|
const OIDC_DISCOVERY_PATH = "/.well-known/openid-configuration";
|
|
171
171
|
const OIDC_SIGN_IN_PATH = "/strapi-plugin-oidc/oidc";
|
|
172
|
+
const OIDC_CALLBACK_PATH = "/strapi-plugin-oidc/oidc/callback";
|
|
173
|
+
const AUTH_ROUTES = [
|
|
174
|
+
"login",
|
|
175
|
+
"register",
|
|
176
|
+
"register-admin",
|
|
177
|
+
"forgot-password",
|
|
178
|
+
"reset-password"
|
|
179
|
+
];
|
|
172
180
|
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
173
181
|
function getPluginConfig() {
|
|
174
182
|
return pluginConfigSchema.parse(strapi.config.get("plugin::strapi-plugin-oidc") ?? {});
|
|
@@ -279,11 +287,11 @@ function clearAuthCookies(strapi2, ctx) {
|
|
|
279
287
|
ctx.cookies.set(COOKIE_NAMES.accessToken, "", rootPathOptions);
|
|
280
288
|
ctx.cookies.set(COOKIE_NAMES.userEmail, "", rootPathOptions);
|
|
281
289
|
}
|
|
282
|
-
const AUTH_ROUTES = ["login", "register", "register-admin", "forgot-password", "reset-password"];
|
|
283
290
|
const STATIC_EXTENSIONS = [".js", ".css", ".png", ".svg", ".ico", ".woff2", ".json", ".map"];
|
|
284
291
|
async function bootstrap({ strapi: strapi2 }) {
|
|
285
292
|
await applyDiscovery(strapi2);
|
|
286
|
-
const
|
|
293
|
+
const rawAdminUrl = strapi2.config.get("admin.url");
|
|
294
|
+
const adminUrl = typeof rawAdminUrl === "string" && rawAdminUrl.length > 0 ? rawAdminUrl : "/admin";
|
|
287
295
|
const tokenRefreshPath = `${adminUrl}/token/refresh`;
|
|
288
296
|
const EXCLUDED_ADMIN_PATHS = [
|
|
289
297
|
`${adminUrl}/login`,
|
|
@@ -409,7 +417,6 @@ function destroy() {
|
|
|
409
417
|
const config = {
|
|
410
418
|
default: {
|
|
411
419
|
REMEMBER_ME: false,
|
|
412
|
-
OIDC_REDIRECT_URI: "http://localhost:1337/strapi-plugin-oidc/oidc/callback",
|
|
413
420
|
OIDC_CLIENT_ID: "",
|
|
414
421
|
OIDC_CLIENT_SECRET: "",
|
|
415
422
|
OIDC_SCOPE: "openid profile email",
|
|
@@ -549,7 +556,6 @@ const REQUIRED_CONFIG_KEYS = [
|
|
|
549
556
|
"OIDC_ISSUER",
|
|
550
557
|
"OIDC_CLIENT_ID",
|
|
551
558
|
"OIDC_CLIENT_SECRET",
|
|
552
|
-
"OIDC_REDIRECT_URI",
|
|
553
559
|
"OIDC_SCOPE",
|
|
554
560
|
"OIDC_FAMILY_NAME_FIELD",
|
|
555
561
|
"OIDC_GIVEN_NAME_FIELD",
|
|
@@ -558,6 +564,15 @@ const REQUIRED_CONFIG_KEYS = [
|
|
|
558
564
|
"OIDC_USERINFO_ENDPOINT",
|
|
559
565
|
"OIDC_AUTHORIZATION_ENDPOINT"
|
|
560
566
|
];
|
|
567
|
+
function resolveRedirectUri(config2) {
|
|
568
|
+
const publicUrl = config2.OIDC_PUBLIC_URL || process.env.PUBLIC_URL || (process.env.NODE_ENV !== "production" ? "http://localhost:1337" : "");
|
|
569
|
+
if (!publicUrl) {
|
|
570
|
+
throw new Error(
|
|
571
|
+
"OIDC_PUBLIC_URL or PUBLIC_URL must be set in production. Provide your Strapi origin (e.g. https://myapp.com)."
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
return `${publicUrl}${OIDC_CALLBACK_PATH}`;
|
|
575
|
+
}
|
|
561
576
|
const jwksCache = /* @__PURE__ */ new Map();
|
|
562
577
|
let jwksDisabledWarned = false;
|
|
563
578
|
function getJwks(uri) {
|
|
@@ -3603,11 +3618,12 @@ async function oidcSignIn(ctx) {
|
|
|
3603
3618
|
try {
|
|
3604
3619
|
const config2 = configValidation();
|
|
3605
3620
|
if (!config2.OIDC_SKIP_LOGIN_PAGE) {
|
|
3606
|
-
const
|
|
3621
|
+
const raw = strapi.config.get("admin.url");
|
|
3622
|
+
const adminUrl = typeof raw === "string" && raw.length > 0 ? raw : "/admin";
|
|
3607
3623
|
ctx.redirect(`${adminUrl}/auth/login?oidc_redirect=1`);
|
|
3608
3624
|
return;
|
|
3609
3625
|
}
|
|
3610
|
-
const { OIDC_CLIENT_ID,
|
|
3626
|
+
const { OIDC_CLIENT_ID, OIDC_SCOPE, OIDC_AUTHORIZATION_ENDPOINT } = config2;
|
|
3611
3627
|
const { code_verifier: codeVerifier, code_challenge: codeChallenge } = await pkceChallenge();
|
|
3612
3628
|
const state = randomBytes(32).toString("base64url");
|
|
3613
3629
|
const nonce = randomBytes(32).toString("base64url");
|
|
@@ -3620,10 +3636,11 @@ async function oidcSignIn(ctx) {
|
|
|
3620
3636
|
ctx.cookies.set(COOKIE_NAMES.codeVerifier, codeVerifier, cookieOptions);
|
|
3621
3637
|
ctx.cookies.set(COOKIE_NAMES.state, state, cookieOptions);
|
|
3622
3638
|
ctx.cookies.set(COOKIE_NAMES.nonce, nonce, cookieOptions);
|
|
3639
|
+
const redirectUri = resolveRedirectUri(config2);
|
|
3623
3640
|
const params = new URLSearchParams({
|
|
3624
3641
|
response_type: "code",
|
|
3625
3642
|
client_id: OIDC_CLIENT_ID,
|
|
3626
|
-
redirect_uri:
|
|
3643
|
+
redirect_uri: redirectUri,
|
|
3627
3644
|
scope: OIDC_SCOPE,
|
|
3628
3645
|
code_challenge: codeChallenge,
|
|
3629
3646
|
code_challenge_method: "S256",
|
|
@@ -3968,7 +3985,7 @@ async function oidcSignInCallback(ctx) {
|
|
|
3968
3985
|
code: String(ctx.query.code),
|
|
3969
3986
|
client_id: config2.OIDC_CLIENT_ID,
|
|
3970
3987
|
client_secret: config2.OIDC_CLIENT_SECRET,
|
|
3971
|
-
redirect_uri: config2
|
|
3988
|
+
redirect_uri: resolveRedirectUri(config2),
|
|
3972
3989
|
grant_type: "authorization_code",
|
|
3973
3990
|
code_verifier: codeVerifier ?? ""
|
|
3974
3991
|
});
|
package/package.json
CHANGED