Docker/OIDC: redirect to a default URL on expired auth state instead of 400-ing (#9143)

## Problem

With OIDC on the official Docker image, interactive SSO logins intermittently return `HTTP 400` at the `/i/oidc/` callback. The failure tracks login duration. `mod_auth_openidc` sets an anti-CSRF state cookie bounded by `OIDCStateTimeout` (default 300 s). If a login through an external IdP takes longer than that (MFA, a slow provider screen, the user stepping away), the cookie is already gone when the callback returns. The image does not set `OIDCDefaultURL`, so the module has no fallback and returns an error instead of restarting the login.

Apache log:

```
oidc_response_proto_state_restore: state has expired
oidc_response_process: invalid authorization response state and
        no default SSO URL is set, sending an error...
→ GET /i/oidc/?code=…&state=… 400
```

This is [documented mod_auth_openidc behaviour](72c9f479c2/auth_openidc.conf (L723-L733)) when `OIDCDefaultURL` is unset. Both `OIDCDefaultURL` and `OIDCStateTimeout` are `RSRC_CONF` (server config only), so the `./FreshRSS/p/i/.htaccess` escape hatch cannot set them and the fix has to live in the image.

Reproduce: log out, start SSO, wait more than 5 minutes on the IdP screen, complete.

## Fix

Add `OIDC_DEFAULT_URL`, wired through the existing `${OIDC_*}` env pattern, defaulting to `/i/` (the index, consistent with `OIDCRedirectURI /i/oidc/`). On an expired or unmatchable state the module now redirects to `/i/`, which is protected and starts a fresh login against the existing IdP session. `OIDCStateTimeout` stays at 300 s; the window is fine, the missing fallback was the bug.

`OIDC_STATE_TIMEOUT` is intentionally not exposed. It can be added the same way if there is a reason to tune the window.

* Docker/OIDC: redirect to a default URL on expired auth state instead of 400-ing

Adds OIDC_DEFAULT_URL (default /i/), wired through the existing ${OIDC_*} env
pattern, so an expired or unmatchable mod_auth_openidc state redirects to the
FreshRSS index and restarts the login instead of returning HTTP 400.

* git commit update

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
This commit is contained in:
Cron
2026-07-24 10:55:36 -05:00
committed by GitHub
parent 9789aa23b2
commit 09478222ce
3 changed files with 3 additions and 0 deletions

View File

@@ -40,6 +40,7 @@ CustomLog "|/var/www/FreshRSS/cli/sensitive-log.sh" combined_proxy
OIDCSessionType ${OIDC_SESSION_TYPE}
OIDCRedirectURI /i/oidc/
OIDCDefaultURL ${OIDC_DEFAULT_URL}
OIDCCryptoPassphrase ${OIDC_CLIENT_CRYPTO_KEY}
Define "Test_${OIDC_REMOTE_USER_CLAIM}"

View File

@@ -43,6 +43,7 @@ if [ -n "$OIDC_ENABLED" ] && [ "$OIDC_ENABLED" -ne 0 ]; then
export OIDC_SESSION_INACTIVITY_TIMEOUT="${OIDC_SESSION_INACTIVITY_TIMEOUT:-300}"
export OIDC_SESSION_MAX_DURATION="${OIDC_SESSION_MAX_DURATION:-27200}"
export OIDC_SESSION_TYPE="${OIDC_SESSION_TYPE:-server-cache}"
export OIDC_DEFAULT_URL="${OIDC_DEFAULT_URL:-/i/}"
# Debian
(which a2enmod >/dev/null && a2enmod -q auth_openidc) ||

View File

@@ -46,6 +46,7 @@ OIDC support in Docker is activated by the presence of a non-empty non-zero `OID
* `OIDC_SESSION_INACTIVITY_TIMEOUT`: Optional. Interval in seconds after which the session will be invalidated when no interaction has occurred. When not defined, the default is 300 seconds.
* `OIDC_SESSION_MAX_DURATION`: Optional. Maximum duration of the application session. When not defined the default is 8 hours (3600 * 8 seconds). When set to 0, the session duration will be set equal to the expiry time of the ID token.
* `OIDC_SESSION_TYPE`: Optional. OpenID Connect session storage type. See [mod_auth_openidcs documentation for details](https://github.com/OpenIDC/mod_auth_openidc/blob/72c9f479c2d228477ff0a9518964f61879c83fb6/auth_openidc.conf#L587-L596).
* `OIDC_DEFAULT_URL`: Optional. URL the user is redirected to when the OIDC module receives a callback whose anti-CSRF state has expired or cannot be matched, for example when an interactive login (external identity provider, MFA/step-up, or the user stepping away) takes longer than the state timeout. When not defined, the default is `/i/`, the FreshRSS index, so that an expired login restarts against the existing provider session instead of returning an HTTP 400 error page. Maps to mod_auth_openidcs [`OIDCDefaultURL`](https://github.com/OpenIDC/mod_auth_openidc/blob/b2e99151bc695335089c8d4bfe5793624ac0732e/auth_openidc.conf#L786-L790).
You may add additional custom configuration in a new `./FreshRSS/p/i/.htaccess` file.