3.9 KiB
Root Cause Analysis: OAuth2 Bearer Token Session Invalidation
Problem
Bearer token authentication fails for app-specific APIs (like Notes) with 401 Unauthorized, even though it works for OCS APIs (capabilities).
Root Cause
The CORSMiddleware in Nextcloud server is logging out the session created by Bearer token authentication:
/home/chris/Software/server/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php:84
$this->session->logout();
Why Session is Logged Out
- Notes API has @CORS annotation
- Bearer auth via user_oidc creates a logged-in session
- Request has NO CSRF token
- Request has NO AppAPI auth flag
- Request has NO PHP_AUTH_USER/PHP_AUTH_PW (basic auth)
- Therefore CORSMiddleware calls logout()
Log Evidence
{"message":"[TokenInvalidatedListener] Could not find the OIDC session related with an invalidated token"}
Token validated successfully, then immediately invalidated by session logout.
Token Type Investigation (Opaque vs JWT)
- Finding: Token type (opaque vs JWT) does NOT affect the issue
- Reason: Session invalidation happens AFTER successful token validation
- Both opaque and JWT tokens validate correctly via TokenValidationRequestEvent
- The logout happens in CORSMiddleware, not in token validation
✅ SOLUTION (Tested & Working)
Option A: Set AppAPI Flag for Bearer Auth ✅
Status: Successfully tested and verified working
Modified user_oidc Backend.php getCurrentUserId() method to set the app_api session flag before returning the user ID:
$this->session->set('app_api', true);
This bypasses CORS middleware's logout logic at line 81-82 by setting the same flag used by Nextcloud's AppAPI framework.
Implementation
The flag is added before all successful Bearer token authentication return statements in /var/www/html/custom_apps/user_oidc/lib/User/Backend.php:
- Line ~243: After OIDC provider validation
- Line ~310: After auto-provisioning with bearer provisioning
- Line ~315: After existing user authentication
- Line ~337: After LDAP user sync
Test Results
All OAuth Bearer token operations now work correctly:
✅ Capabilities endpoint (OCS API) - 200 OK ✅ Notes API listing - 200 OK ✅ Notes API create - 200 OK (created note 112) ✅ Notes API delete - 200 OK (deleted note 112)
No session invalidation occurs, and all API operations complete successfully.
Patch File
See patches/user_oidc-bearer-auth-app-api-flag.patch for the exact changes.
Alternative Solutions (Not Tested)
Option B: Avoid Creating Full Session for Bearer Auth
Bearer token auth should not create a full session that triggers CORS middleware checks. This would require deeper architectural changes.
Option C: Add CSRF Exemption
Modify CORSMiddleware to exempt Bearer token authenticated requests from CSRF check. This would require changes to Nextcloud core.
Option D: Use Basic Auth Headers
Set PHP_AUTH_USER/PHP_AUTH_PW server variables during Bearer auth so CORSMiddleware can re-authenticate. This could have security implications.
Recommendations
Short-term (Current Implementation)
The app_api flag solution works correctly and follows Nextcloud's existing pattern for API authentication. This is the recommended approach for immediate use.
Long-term (Upstream Contribution)
Consider submitting this fix to the upstream user_oidc project as it enables proper Bearer token authentication for all Nextcloud APIs, not just OCS endpoints.
Files Involved
/home/chris/Software/user_oidc/lib/User/Backend.php(getCurrentUserId) - MODIFIED/home/chris/Software/server/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php(logout logic)/home/chris/Software/user_oidc/lib/Listener/TokenInvalidatedListener.php(cleanup handler)
Testing
Run the OAuth interactive test to verify:
uv run pytest tests/integration/test_oauth_interactive.py -v