Summary
Since v8.7.0, bearer token authentication via IApacheBackend no longer creates a session token in oc_authtoken. As a result, any endpoint that relies on a valid session token after bearer authentication (e.g. Login Flow v2's GET /ocs/v2.php/core/getapppassword) returns 403.
Environment
- user_oidc: 8.10.1 (regression present since 8.7.0)
- Nextcloud: 30.x
- Provider configured with
check_bearer = 1 and userinfo_bearer_validation = true
Root cause
PR #1376 introduced setSessionUser() calls inside getCurrentUserId() (the IApacheBackend callback). IUserSession::setUser() is called there, which sets self::$_activeUser in NC core's session before loginWithExternalBackend() completes.
NC core's loginWithExternalBackend() guards createSessionToken() with a check for an already-set active user — so once setSessionUser() runs inside getCurrentUserId(), no oc_authtoken row is ever written for the request.
When AppPasswordController::getAppPassword() then calls LoginCredentialsStore::getLoginCredentials(), tokenProvider->getToken($sessionId) throws InvalidTokenException because no row exists → 403.
Logs
user_oidc GET /ocs/v2.php/core/getapppassword
Token validated with UserInfoValidator by provider: 1
admin_audit Login attempt: "<uid>"
core could not get login credentials because the token is invalid:
Token does not exist: token does not exist
→ status: 403
Expected behaviour
Bearer token validation succeeds AND loginWithExternalBackend() completes its full flow (including createSessionToken()), so that session-dependent endpoints work correctly.
Actual behaviour
loginWithExternalBackend() skips createSessionToken() because setSessionUser() already set the active user inside getCurrentUserId(). All endpoints that require a valid oc_authtoken (e.g. Login Flow v2 app-password endpoint) return 403.
Suggested fix
Remove the setSessionUser() calls from getCurrentUserId() and instead register a listener on the TokenValidatedEvent that user_oidc already dispatches, calling setSessionUser() from there — after loginWithExternalBackend() has had the chance to complete.
Version info
Summary
Since v8.7.0, bearer token authentication via
IApacheBackendno longer creates a session token inoc_authtoken. As a result, any endpoint that relies on a valid session token after bearer authentication (e.g. Login Flow v2'sGET /ocs/v2.php/core/getapppassword) returns 403.Environment
check_bearer = 1anduserinfo_bearer_validation = trueRoot cause
PR #1376 introduced
setSessionUser()calls insidegetCurrentUserId()(theIApacheBackendcallback).IUserSession::setUser()is called there, which setsself::$_activeUserin NC core's session beforeloginWithExternalBackend()completes.NC core's
loginWithExternalBackend()guardscreateSessionToken()with a check for an already-set active user — so oncesetSessionUser()runs insidegetCurrentUserId(), nooc_authtokenrow is ever written for the request.When
AppPasswordController::getAppPassword()then callsLoginCredentialsStore::getLoginCredentials(),tokenProvider->getToken($sessionId)throwsInvalidTokenExceptionbecause no row exists → 403.Logs
Expected behaviour
Bearer token validation succeeds AND
loginWithExternalBackend()completes its full flow (includingcreateSessionToken()), so that session-dependent endpoints work correctly.Actual behaviour
loginWithExternalBackend()skipscreateSessionToken()becausesetSessionUser()already set the active user insidegetCurrentUserId(). All endpoints that require a validoc_authtoken(e.g. Login Flow v2 app-password endpoint) return 403.Suggested fix
Remove the
setSessionUser()calls fromgetCurrentUserId()and instead register a listener on theTokenValidatedEventthatuser_oidcalready dispatches, callingsetSessionUser()from there — afterloginWithExternalBackend()has had the chance to complete.Version info