Checklist
-
I have read the intro post: About the Installation Issues category
-
I have read tutorials/help and searched for similar issues
-
I provide relevant information about my server below
Environment
-
Passbolt version: Community Edition 5.14.3 (recently upgraded from 5.14.0 during this investigation)
-
Server OS: Ubuntu (Noble), kernel 6.8.0-137-generic
-
Passbolt server hostname: srv-pass, internal IP 192.168.55.184
-
Passbolt listens on HTTP/80 only (no local TLS)
-
Reverse proxy: separate Nginx server (192.168.55.188) managed by another administrator, terminates HTTPS, I do not have access to it
-
Public URL: https://it.sicc.gov.ma
-
Certificate: Sectigo (*.sicc.gov.ma), issued via “Sectigo Public Server Authentication CA DV R36”
Problem
The Passbolt desktop app and browser extension (Chrome, latest 5.14.3 extension, tested on multiple machines/users/browsers) suddenly stopped working about a week ago after months of normal operation. Error shown:
text
Something went wrong!
Could not verify the server key.
Server internal error. Check with your administrator.
This affects all users, across different browsers and machines — not isolated to one client.
Secondary Symptom: Blank Gray Page During Account Recovery
When attempting account recovery (/setup/recover/start/...), the page loads to a blank gray screen instead of the recovery UI. The extension’s background service worker console shows repeated errors during this flow:
text
Error: The user id cannot be empty
at J.__validate (index.js:2:57445)
at J._getLocal (index.js:2:58728)
at J.get (index.js:2:58333)
Error: The user is not set
at J._getLocal (index.js:2:58805)
quickaccessPagemod::attach legacy account cannot be retrieved, please contact your administrator.
TypeError: Cannot read properties of undefined (reading 'toDto')
This occurred even after a completely clean extension reinstall (removed extension, cleared site data/cookies for the domain, restarted browser, reinstalled from Chrome Web Store) on multiple machines — same errors persist. This suggests the extension either can’t complete initialization against the server at all, or is failing before it can establish a valid session, consistent with the “could not verify the server key” failure happening earlier in the same handshake.
What I’ve Already Ruled Out
-
GPG server key: healthcheck passes every GPG-related check (encrypt/decrypt/sign/verify, fingerprint match, keyring presence).
-
Database: healthy, schema up to date, connects fine.
-
Local Nginx/PHP-FPM on srv-pass: no blocking rules, syntax OK, PHP-FPM responds.
-
Firewall on srv-pass:
ufwinactive,iptablesall-ACCEPT/empty. -
fail2ban: not installed on srv-pass.
-
Direct backend tests:
curl http://127.0.0.1/auth/verify.json?api-version=v2andcurl http://192.168.55.184/auth/verify.json?api-version=v2(from LAN) both return HTTP 200 with valid JSON containing the correct server public key and fingerprint. -
Browser extension: fully removed, browser storage/cookies cleared, freshly reinstalled (5.14.3) on multiple machines — issue persists identically.
-
Passbolt CE upgraded 5.14.0 → 5.14.3 cleanly (migrations ran fine, cleanup shell reports “no issue found”) — did not resolve the problem.
Key Diagnostic Finding
While tailing /var/log/nginx/access.log on srv-pass in real time, a colleague triggered the “Could not verify the server key” error from the desktop app. Zero log entries appeared on srv-pass during the failure — meaning the request never reaches the Passbolt backend at all. Earlier, unrelated traffic from the reverse proxy IP (192.168.55.188) does appear in Passbolt’s error log for other requests (e.g., bare / route lookups), confirming the proxy can reach the backend in general — but the specific /auth/verify.json request during a live failure never arrives.
Also Found: Incomplete TLS Certificate Chain
text
openssl s_client -connect it.sicc.gov.ma:443 -servername it.sicc.gov.ma
Returns:
text
Verify error:num=20:unable to get local issuer certificate
Verify error:num=21:unable to verify the first certificate
Verify return code: 21 (unable to verify the first certificate)
curl -k (ignoring chain validation) succeeds and returns HTTP 200 with the correct JSON payload. This suggests the reverse proxy is serving only the leaf certificate, not the full chain with the Sectigo intermediate.
Also Found: NTP/Clock Sync Failure on Backend
A recent healthcheck run surfaced:
text
[FAIL] NTP service is active but the system clock is not synchronized.
This was passing in an earlier healthcheck run in this same investigation, so it may be a new/independent issue. Currently investigating whether this contributed to signature/timestamp validation failures, or is unrelated.
My Working Hypothesis
Since curl with -k succeeds while stricter clients (browser extension, desktop app) fail uniformly across all users and machines, I suspect either:
-
The reverse proxy is blocking/dropping the specific
/auth/verify.jsonrequest (WAF rule,locationblock, or similar) before forwarding it to the backend, or -
The incomplete certificate chain is causing clients that do full TLS chain validation to abort the connection before any HTTP request is even sent (explaining why nothing reaches the backend’s logs and why the recovery flow also fails to properly initialize).
Questions for the Community/Team
-
Does the Passbolt desktop app or browser extension enforce stricter TLS certificate chain validation than a typical browser tab load? Could an incomplete intermediate chain cause exactly this “could not verify the server key” error while normal page navigation still partially works?
-
Could a TLS/handshake failure during setup/recovery cause the extension to hang on a blank gray page with “user id cannot be empty” / “user is not set” errors, as opposed to a client-side storage corruption issue?
-
Are there known cases where NTP/clock drift on the backend causes GPG signature or JWT timestamp validation to fail in a way that produces this specific error message?
-
Any recommended way to get more verbose/debug logging out of the desktop app or extension to see exactly where in the verification handshake it’s failing?
Happy to provide more logs/output as needed.



