The Basics
- Nextcloud Server version (e.g., 29.x.x):
31.0.10
- Operating system and version (e.g., Ubuntu 24.04):
Ubuntu 24.04 LTS (x86_64)
- Web server and version (e.g, Apache 2.4.25):
Apache 2.4.58 (prefork MPM, mod_php)
- Reverse proxy and version _(e.g. nginx 1.27.2)
none
- PHP version (e.g, 8.3):
8.3
- Is this the first time you’ve seen this error? (Yes / No):
Yes
- When did this problem seem to first start?
As soon as I attempted app password authentication
- Installation method (e.g. AlO, NCP, Bare Metal/Archive, etc.)
Manual "bare-metal" install from archive
- Are you using CloudfIare, mod_security, or similar? (Yes / No)
No
Summary of the issue you are facing:
App-passwords (auth tokens) created through:
sudo -u www-data php occ user:auth-tokens:add <user>
are invalidated 5 minutes (with a few seconds difference every time) after creation. During the first 5 minutes they work perfectly for WebDAV and OCS API calls.
After ~300 seconds the next request fails with response status code 503 and:
Session token credentials are invalid
OC\Authentication\Exceptions\TokenPasswordExpiredException
and in the database the token’s password_invalid field flips from 0 → 1.
This happens both for normal local users and SAML users.
I have tried to disable external IdP, password-policy, and all background-jobs, but no I have had no difference.
Steps to replicate it (hint: details matter!):
-
Create a new permanent token using the user password when prompted for a password:
-
sudo -u www-data php occ user:auth-tokens:add <username>Output:
App password: <app-password> -
Test the password immediately:
-
curl -u <username>:<token> \ https://nextcloud-poc.dc.kau.se/remote.php/dav/files/<username>/ -I→ Response status
200 -
Wait 5+ minutes.
-
Repeat the same request.
→Response status503 Service unavailable, and then401 Unauthorizedon the next one. -
Check database:
-
SELECT id,name,type,last_activity,password_invalid FROM oc_authtoken ORDER BY id DESC LIMIT 3;The token row now has
password_invalid = 1.
Log entries
Nextcloud
Please provide the log entries from your Nextcloud log that are generated during the time of problem (via the Copy raw option from Administration settings->Logging screen or from your nextcloud.log located in your data directory). Feel free to use a pastebin/gist service if necessary.
{"reqId":"sGsBzm35CWuZpynmopPD","level":2,"time":"2025-11-10T08:38:02+00:00","remoteAddr":"<ip_adress>","user":"--","app":"core","method":"GET","url":"/remote.php/dav/files/<username>/","message":"Lo
gin failed: '<username>' (Remote IP: '<ip_adress>')","userAgent":"curl/8.7.1","version":"31.0.10.2","data":{"app":"core"}}
{"reqId":"sGsBzm35CWuZpynmopPD","level":2,"time":"2025-11-10T08:38:02+00:00","remoteAddr":"<ip_adress>","user":"--","app":"core","method":"GET","url":"/remote.php/dav/files/<username>/","message":"Se
ssion token credentials are invalid","userAgent":"curl/8.7.1","version":"31.0.10.2","data":{"app":"core","user":"<username>"}}
{"reqId":"sGsBzm35CWuZpynmopPD","level":3,"time":"2025-11-10T08:38:02+00:00","remoteAddr":"<ip_adress>","user":"--","app":"no app in context","method":"GET","url":"/remote.php/dav/files/<username>/",
"message":"Exception thrown: OC\\Authentication\\Exceptions\\TokenPasswordExpiredException","userAgent":"curl/8.7.1","version":"31.0.10.2","exception":{"Exception":"OC\\Authentication\\Exceptions\\TokenPasswordExp
iredException","Message":"","Code":0,"Trace":[{"file":"/var/www/html/lib/private/Authentication/Token/PublicKeyTokenProvider.php","line":152,"function":"checkToken","class":"OC\\Authentication\\Token\\PublicKeyTok
enProvider","type":"->"},{"file":"/var/www/html/lib/private/Authentication/Token/Manager.php","line":121,"function":"getToken","class":"OC\\Authentication\\Token\\PublicKeyTokenProvider","type":"->","args":["*** s
ensitive parameters replaced ***"]},{"file":"/var/www/html/lib/private/User/Session.php","line":413,"function":"getToken","class":"OC\\Authentication\\Token\\Manager","type":"->","args":["*** sensitive parameters
replaced ***"]},{"file":"/var/www/html/apps/dav/lib/Connector/Sabre/Auth.php","line":80,"function":"logClientIn","class":"OC\\User\\Session","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/
var/www/html/3rdparty/sabre/dav/lib/DAV/Auth/Backend/AbstractBasic.php","line":103,"function":"validateUserPass","class":"OCA\\DAV\\Connector\\Sabre\\Auth","type":"->","args":["*** sensitive parameters replaced **
*"]},{"file":"/var/www/html/apps/dav/lib/Connector/Sabre/Auth.php","line":191,"function":"check","class":"Sabre\\DAV\\Auth\\Backend\\AbstractBasic","type":"->"},{"file":"/var/www/html/apps/dav/lib/Connector/Sabre/
Auth.php","line":105,"function":"auth","class":"OCA\\DAV\\Connector\\Sabre\\Auth","type":"->"},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Auth/Plugin.php","line":179,"function":"check","class":"OCA\\DAV\\Co
nnector\\Sabre\\Auth","type":"->"},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Auth/Plugin.php","line":135,"function":"check","class":"Sabre\\DAV\\Auth\\Plugin","type":"->"},{"file":"/var/www/html/3rdparty/s
abre/event/lib/WildcardEmitterTrait.php","line":89,"function":"beforeMethod","class":"Sabre\\DAV\\Auth\\Plugin","type":"->"},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php","line":456,"function":"emi
t","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/www/html/apps/dav/lib/Connector/Sabre/Server.php","line":49,"function":"invokeMethod","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/www/html/app
s/dav/lib/Server.php","line":403,"function":"start","class":"OCA\\DAV\\Connector\\Sabre\\Server","type":"->"},{"file":"/var/www/html/apps/dav/appinfo/v2/remote.php","line":21,"function":"exec","class":"OCA\\DAV\\S
erver","type":"->"},{"file":"/var/www/html/remote.php","line":145,"args":["/var/www/html/apps/dav/appinfo/v2/remote.php"],"function":"require_once"}],"File":"/var/www/html/lib/private/Authentication/Token/PublicKe
yTokenProvider.php","Line":226,"message":"","exception":{},"CustomMessage":"Exception thrown: OC\\Authentication\\Exceptions\\TokenPasswordExpiredException"}}
{"reqId":"sGsBzm35CWuZpynmopPD","level":3,"time":"2025-11-10T08:38:02+00:00","remoteAddr":"<ip_adress>","user":"--","app":"webdav","method":"GET","url":"/remote.php/dav/files/<username>/","message":"OC\\Authentication\\Exceptions\\TokenPasswordExpiredException: ","userAgent":"curl/8.7.1","version":"31.0.10.2","exception":{"Exception":"Sabre\\DAV\\Exception\\ServiceUnavailable","Message":"OC\\Authentication\\Exceptions\\TokenPasswordExpiredException: ","Code":0,"Trace":[{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Auth/Plugin.php","line":179,"function":"check","class":"OCA\\DAV\\Connector\\Sabre\\Auth","type":"->"},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Auth/Plugin.php","line":135,"function":"check","class":"Sabre\\DAV\\Auth\\Plugin","type":"->"},{"file":"/var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php","line":89,"function":"beforeMethod","class":"Sabre\\DAV\\Auth\\Plugin","type":"->"},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php","line":456,"function":"emit","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/www/html/apps/dav/lib/Connector/Sabre/Server.php","line":49,"function":"invokeMethod","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/www/html/apps/dav/lib/Server.php","line":403,"function":"start","class":"OCA\\DAV\\Connector\\Sabre\\Server","type":"->"},{"file":"/var/www/html/apps/dav/appinfo/v2/remote.php","line":21,"function":"exec","class":"OCA\\DAV\\Server","type":"->"},{"file":"/var/www/html/remote.php","line":145,"args":["/var/www/html/apps/dav/appinfo/v2/remote.php"],"function":"require_once"}],"File":"/var/www/html/apps/dav/lib/Connector/Sabre/Auth.php","Line":112,"message":"OC\\Authentication\\Exceptions\\TokenPasswordExpiredException: ","exception":{},"CustomMessage":"OC\\Authentication\\Exceptions\\TokenPasswordExpiredException: "}}
Web server / Reverse Proxy
No errors in the Apache service.
Configuration
Nextcloud
{
"system": {
"instanceid": "***REMOVED SENSITIVE VALUE***",
"passwordsalt": "***REMOVED SENSITIVE VALUE***",
"secret": "***REMOVED SENSITIVE VALUE***",
"trusted_domains": [
"***REMOVED SENSITIVE VALUE***"
],
"datadirectory": "***REMOVED SENSITIVE VALUE***",
"dbtype": "mysql",
"version": "31.0.10.2",
"overwrite.cli.url": "http:\/\/localhost",
"dbname": "***REMOVED SENSITIVE VALUE***",
"dbhost": "***REMOVED SENSITIVE VALUE***",
"dbport": "",
"dbtableprefix": "oc_",
"mysql.utf8mb4": true,
"dbuser": "***REMOVED SENSITIVE VALUE***",
"dbpassword": "***REMOVED SENSITIVE VALUE***",
"installed": true,
"maintenance": false,
"defaultapp": "",
"loglevel": "0",
"updater.secret": "***REMOVED SENSITIVE VALUE***",
"theme": "",
"memcache.local": "\\OC\\Memcache\\APCu",
"memcache.distributed": "\\OC\\Memcache\\Redis",
"redis": {
"host": "***REMOVED SENSITIVE VALUE***",
"port": 6379,
"timeout": 1.5
}
}
}
Apps
Enabled:
- activity: 4.0.0
- app_api: 5.0.2
- bruteforcesettings: 4.0.0
- cloud_federation_api: 1.14.0
- dashboard: 7.11.0
- dav: 1.33.0
- federatedfilesharing: 1.21.0
- federation: 1.21.0
- files: 2.3.1
- files_downloadlimit: 4.0.0
- files_pdfviewer: 4.0.0
- files_sharing: 1.23.1
- files_trashbin: 1.21.0
- files_versions: 1.24.0
- logreader: 4.0.0
- lookup_server_connector: 1.19.0
- notifications: 4.0.0
- oauth2: 1.19.1
- profile: 1.0.0
- provisioning_api: 1.21.0
- recommendations: 4.0.0
- related_resources: 2.0.0
- serverinfo: 3.0.0
- settings: 1.14.0
- support: 3.0.0
- text: 5.0.2
- theming: 2.6.1
- twofactor_backupcodes: 1.20.0
- updatenotification: 1.21.0
- user_saml: 7.0.0
- viewer: 4.0.0
- workflowengine: 2.13.0
Disabled:
- admin_audit: 1.21.0
- circles: 31.0.0 (installed 31.0.0)
- comments: 1.21.0 (installed 1.21.0)
- contactsinteraction: 1.12.1 (installed 1.12.0)
- encryption: 2.19.0
- files_external: 1.23.0
- files_reminders: 1.4.0 (installed 1.4.0)
- firstrunwizard: 4.0.0 (installed 4.0.0)
- nextcloud_announcements: 3.0.0 (installed 3.0.0)
- password_policy: 3.0.0 (installed 3.0.0)
- photos: 4.0.0 (installed 4.0.0)
- privacy: 3.0.0 (installed 3.0.0)
- sharebymail: 1.21.0 (installed 1.21.0)
- survey_client: 3.0.0 (installed 3.0.0)
- suspicious_login: 9.0.1
- systemtags: 1.21.1 (installed 1.21.1)
- twofactor_nextcloud_notification: 5.0.0
- twofactor_totp: 13.0.0-dev.0
- user_ldap: 1.22.0 (installed 1.22.0)
- user_status: 1.11.0 (installed 1.11.0)
- weather_status: 1.11.0 (installed 1.11.0)
- webhook_listeners: 1.2.0 (installed 1.2.0)
Observations
-
password_invalid is set only when a request using the token is made after 5 min, not automatically by a job. Possible that the token has a cache lifetime of 5 mins?
-
Upgrading from 31.0.8 → 31.0.10 and switching background jobs to AJAX makes no difference.
-
The issue reproduces on a clean install with all non-core apps disabled.
-
Appears to originate in
PublicKeyTokenProvider.phpduringcheckToken()/getToken(): the provider throwsTokenPasswordExpiredExceptionwhen it cannot verify the password hash of the token, even for permanent app tokens created via CLI.
Expected behavior
Permanent app tokens (type 1) should remain valid indefinitely unless explicitly revoked or the user password changes. They should not expire after 5 minutes nor set password_invalid = 1.
Actual behavior
App tokens created via occ user:auth-tokens:add are invalidated after 5 minutes of inactivity, throwing TokenPasswordExpiredException on next use after 5 minutes.
Question for maintainers / contributors
Is this a regression in PublicKeyTokenProvider (possibly a cache or password-validation mismatch for CLI-generated tokens)?