iOS/Android App HTTP Forbidden

Checklist
x I have read intro post: https://community.passbolt.com/t/about-the-installation-issues-category/12
x I have read the tutorials, help and searched for similar issues
x I provide relevant information about my server (component names and versions, etc.)
I provide a copy of my logs and healthcheck
I describe the steps I have taken to trouble shoot the problem
x I describe the steps on how to reproduce the issue

Have been running CE for a while succesfully. Server is hosted on a docker container. Accessible via Mac and windows clients. Android and iOS clients produce “HTTP Forbidden” message in a red bar on the passphrase screen on both mobile apps. I am using a wildcard certificate. I see a couple of similar issues on the forums but neither quite matched all the variables here. I have also read through this article

https://www.passbolt.com/docs/admin/server-maintenance/passbolt-api-status/#ssl-certificate

which references wildcard SSL certificates but am not sure how to overcome. My wildcard cert does contain the full certificate chain. I am using the manual certificate setup. The relevant portions of my compose.yml are

environment:
APP_FULL_BASE_URL: https://passbolt.virtualomni.com
PASSBOLT_SSL_FORCE: “true”
DATASOURCES_DEFAULT_HOST: “xx”
DATASOURCES_DEFAULT_USERNAME: “xxx”
DATASOURCES_DEFAULT_PASSWORD: “xxx”
DATASOURCES_DEFAULT_DATABASE: “xxx”
EMAIL_DEFAULT_FROM_NAME: “xx”
EMAIL_DEFAULT_FROM: “xx”
EMAIL_TRANSPORT_DEFAULT_HOST: “xx”
EMAIL_TRANSPORT_DEFAULT_PORT: xx
volumes:

  • gpg_volume:/share/Container/container-station-data/lib/docker/volumes/passbolt/passbolt_gpg_volume
  • jwt_volume:/share/Container/container-station-data/lib/docker/volumes/passbolt/passbolt_jwt_volume
  • ./certs/cert.crt:/etc/ssl/certs/certificate.crt:ro
  • ./certs/key.pem:/etc/ssl/certs/certificate.key:ro

I have tried with and without the SSL Force line…

The mobile app was working prior to upgrading to 5.2.0 - Currently on 5.4.1.

In the health check relevant sections I get

Config files

The application config file is present

The passbolt config file is missing

Core config

Cache is working

Unique value set for security.salt

Full base url is set to https://passbolt.virtualomni.com

App.fullBaseUrl validation OK

/healthcheck/status is reachable

SSL Certificate

SSL peer certificate validates

Hostname is matching SSL certificate

Not using a self-signed certificate

As I said, I’m using a wildcard with a full chain of authority, not self-signed.

Client (iPhone current up to date app and OS) Log relevant section

Passbolt:

Device: iPhone
OS: 18.6
App: 2.1.0

[2025-08-15 02:23:49] Initializing the app…
[2025-08-15 02:23:49] …app initialization completed!
[2025-08-15 02:23:49] Verifying data integrity…
[2025-08-15 02:23:49] …data integrity verification finished
[2025-08-15 02:23:50] [CCB08B88-13FC-4E86-8A02-B6B67EC43DD4] HTTP GET /lookup
[2025-08-15 02:23:50] [CCB08B88-13FC-4E86-8A02-B6B67EC43DD4] HTTP 200 /lookup
[2025-08-15 02:23:50] [86B4B5C0-CC37-4E5E-A3E4-5B368B15EE0D] HTTP GET /img/avatar/user_medium.png
[2025-08-15 02:23:50] [59AF3499-28D4-4912-82A8-761EBDAEC02C] HTTP GET /img/avatar/user_medium.png
[2025-08-15 02:23:50] [86B4B5C0-CC37-4E5E-A3E4-5B368B15EE0D] HTTP 200 /img/avatar/user_medium.png
[2025-08-15 02:23:50] [59AF3499-28D4-4912-82A8-761EBDAEC02C] HTTP 200 /img/avatar/user_medium.png
[2025-08-15 02:24:11] Beginning authorization…
[2025-08-15 02:24:11] …creating new access token…
[2025-08-15 02:24:11] …fetching server public RSA key…
[2025-08-15 02:24:11] …fetching server public PGP key…
[2025-08-15 02:24:11] [9D75A9FC-F098-4082-A5A7-14FC1B29689D] HTTP GET /auth/jwt/rsa.json
[2025-08-15 02:24:11] [A4D077C4-33DE-4399-8FFA-A49481546437] HTTP GET /auth/verify.json
[2025-08-15 02:24:11] [A4D077C4-33DE-4399-8FFA-A49481546437] HTTP 200 /auth/verify.json
[2025-08-15 02:24:11] Local timestamp: 1755224651
[2025-08-15 02:24:11] Server timestamp: 1755224651
[2025-08-15 02:24:11] Using time diff for session: 0
[2025-08-15 02:24:11] …verifying server public PGP key…
[2025-08-15 02:24:11] …preparing authorization challenge…
[2025-08-15 02:24:11] [9D75A9FC-F098-4082-A5A7-14FC1B29689D] HTTPStatusCodeUnexpected
DiagnosticsContext:
•HTTP status code is not matching expected OSFeatures/NetworkRequestExecutor.swift:496
⮑ “path”: 496
⮑ “file”: OSFeatures/NetworkRequestExecutor.swift
[2025-08-15 02:24:11] [D51169E9-3D61-4E45-92B0-5C8C47679C42] HTTP POST /auth/jwt/login.json
[2025-08-15 02:24:12] [D51169E9-3D61-4E45-92B0-5C8C47679C42] HTTPForbidden
DiagnosticsContext:
•HTTPForbidden OSFeatures/NetworkRequestExecutor.swift:472
⮑ “path”: 472
⮑ “file”: OSFeatures/NetworkRequestExecutor.swift
[2025-08-15 02:24:12] …authorization failed!
[2025-08-15 02:24:12] :warning: HTTPForbidden
DiagnosticsContext:
•HTTPForbidden OSFeatures/NetworkRequestExecutor.swift:472
⮑ “path”: 472
⮑ “file”: OSFeatures/NetworkRequestExecutor.swift
[2025-08-15 02:24:33] Beginning importing account kit…

Please assist

1 Like

G’day Eric.

Is the strange looking mount point for GPG/JWT keys accurate?

  • gpg_volume:/share/Container/container-station-data/lib/docker/volumes/passbolt/passbolt_gpg_volume

  • jwt_volume:/share/Container/container-station-data/lib/docker/volumes/passbolt/passbolt_jwt_volume

Default should look like:

volumes:
  - gpg_volume:/etc/passbolt/gpg
  - jwt_volume:/etc/passbolt/jwt

The browser uses GPG for auth and the mobile app uses JWT for auth.

You can check in your browser at https://passbolt_instance/settings.json?api-version=v2
Look for:

    "jwtAuthentication": {
      "version": "3.3.0",
      "enabled": true
    },

You can also run a status report to find out detailed info on the JWT folder

https://www.passbolt.com/docs/hosting/troubleshooting/logs/#status-report

This other forum post is very similar to your issue:

https://community.passbolt.com/t/iphone-app-http-status-code-unexpected/5512

Let em know how you go.
Gareth

Sorry, just got back to this. I can confirm that I have

  },
        "jwtAuthentication": {
          "version": "3.3.0",
          "enabled": true

in settings.json

The volume mapping was due to the way volumes are mapped on a qnap device but I changed them back to defaults and got the same result in settings.json.

I reverted the volume mapping to the defaults,

volumes:

  • gpg_volume:/etc/passbolt/gpg
  • jwt_volume:/etc/passbolt/jwt

and re-ran the jwt key pair creation manually. They files now exist but when I run the status report I get this returned

JWT Authentication

[PASS] The JWT Authentication plugin is enabled.
[PASS] The /etc/passbolt/jwt/ directory is not writable.
[FAIL] A valid JWT key pair is missing.
[HELP] Run the create JWT keys script to create a valid JWT secret and public key pair:
[HELP] sudo su -s /bin/bash -c “/usr/share/php/passbolt/bin/cake passbolt create_jwt_keys” www-data

rights on the directory are

drwxr-x—+ 2 root www-data 4 Aug 17 20:42 jwt

and the files are

drwxr-x—+ 2 root www-data 4 Aug 17 20:42 .
drwxrwx—+ 6 root www-data 19 Aug 17 20:22 ..
-rw-r-----+ 1 root root 3272 Aug 17 20:42 jwt.key
-rw-r-----+ 1 root root 800 Aug 17 20:42 jwt.pem

I’m also now seeing different errors in the client log on iOS

Passbolt:

Device: iPhone
OS: 18.6
App: 2.1.0

………
[2025-08-17 21:05:36] Processing QR code payload…
[2025-08-17 21:05:36] …processing canceled!
[2025-08-17 21:05:37] [016F75A5-1CFF-41AE-8456-2DB3718CB667] HTTP GET /img/avatar/user_medium.png
[2025-08-17 21:05:37] [016F75A5-1CFF-41AE-8456-2DB3718CB667] HTTP 200 /img/avatar/user_medium.png
[2025-08-17 21:05:49] Completing account transfer…
[2025-08-17 21:05:49] Verifying data integrity…
[2025-08-17 21:05:49] …data integrity verification finished
[2025-08-17 21:05:49] Beginning authorization…
[2025-08-17 21:05:49] …creating new access token…
[2025-08-17 21:05:49] …fetching server public PGP key…
[2025-08-17 21:05:49] …fetching server public RSA key…
[2025-08-17 21:05:49] [4F632242-28FF-4324-9C33-A7997B623281] HTTP GET /auth/jwt/rsa.json
[2025-08-17 21:05:49] [82D5E6FD-66FE-49B8-8201-E91FE74D2FD0] HTTP GET /auth/verify.json
[2025-08-17 21:05:49] [82D5E6FD-66FE-49B8-8201-E91FE74D2FD0] HTTP 200 /auth/verify.json
[2025-08-17 21:05:49] Local timestamp: 1755464749
[2025-08-17 21:05:49] Server timestamp: 1755464749
[2025-08-17 21:05:49] Using time diff for session: 0
[2025-08-17 21:05:49] …verifying server public PGP key…
[2025-08-17 21:05:49] [4F632242-28FF-4324-9C33-A7997B623281] HTTPStatusCodeUnexpected
DiagnosticsContext:
•HTTP status code is not matching expected OSFeatures/NetworkRequestExecutor.swift:496
⮑ “path”: 496
⮑ “file”: OSFeatures/NetworkRequestExecutor.swift
[2025-08-17 21:05:49] …preparing authorization challenge…
[2025-08-17 21:05:49] [B7899D44-ED86-42D5-8B16-A8876FB52C7E] HTTP POST /auth/jwt/login.json
[2025-08-17 21:05:49] [B7899D44-ED86-42D5-8B16-A8876FB52C7E] HTTPForbidden
DiagnosticsContext:
•HTTPForbidden OSFeatures/NetworkRequestExecutor.swift:472
⮑ “path”: 472
⮑ “file”: OSFeatures/NetworkRequestExecutor.swift
[2025-08-17 21:05:49] …authorization failed!
[2025-08-17 21:05:49] …account transfer failed!
[2025-08-17 21:05:56] Beginning importing account kit…

Hey Eric.

With JWT auth enabled you should be able to hit the two endpoints
GET /auth/jwt/rsa.json
POST /auth/jwt/login.json

rsa.jsonexample response:

{
  "header": {
    "id": "c4a59349-fade-4e4d-ab0e-c56e7d217186",
    "status": "success",
    "servertime": 1755584001,
    "action": "2a80ca92-0e47-5780-b338-3568f3cff69e",
    "message": "The operation was successful.",
    "url": "/auth/jwt/rsa.json",
    "code": 200
  },
  "body": {
    "keydata": "-----BEGIN PUBLIC KEY<snip>\n"
  }
}

The plugin is enabled by default (unless you disabled it):

PASSBOLT_PLUGINS_JWT_AUTHENTICATION_ENABLED=true

Fix the permissions:

[HELP] sudo chown -Rf root:www-data /etc/passbolt/jwt/
[HELP] sudo chmod 750 /etc/passbolt/jwt/
[HELP] sudo chmod 640 /etc/passbolt/jwt/jwt.key
[HELP] sudo chmod 640 /etc/passbolt/jwt/jwt.pem

Let me know how you go.

Cheers

Gareth

Thanks, tht worked. I know I followed these steps (or at least thought I did) from the docs but I must have missed something. Thanks for the assist.

Actually I just did a fresh install according to the docker instructions and the rights for the JWT volume are definitely wrong, user www-data was NOT allowed to write there. I fixed the rights after some hunting. I think there might be something wrong with the script(?) that creates the initial environment inside the docker container?

1 Like

Hello,

It seems something changed in image version 5.2.0-1-ce, and the issue persists through the latest release. These are a clean setups with an identical Docker Compose.

image:5.1.1-1-ce

JWT Authentication

\[PASS\] The JWT Authentication plugin is enabled.
\[FAIL\] The /etc/passbolt/jwt/ directory should not be writable.
\[HELP\] You can try:
\[HELP\] sudo chown -Rf root:www-data /etc/passbolt/jwt/
\[HELP\] sudo chmod 750 /etc/passbolt/jwt/
\[HELP\] sudo chmod 640 /etc/passbolt/jwt/jwt.key
\[HELP\] sudo chmod 640 /etc/passbolt/jwt/jwt.pem
\[PASS\] A valid JWT key pair was found.

\[FAIL\] 1 error(s) found. Hang in there!

jwt keys are created properly.

ls -l /etc/passbolt/jwt/
total 8
-rw-r----- 1 www-data www-data 3268 Oct 30 06:54 jwt.key
-rw-r----- 1 www-data www-data  800 Oct 30 06:54 jwt.pem

jwt/rsa.json is OK

{“header”:{“id”:“80ca05c4-4f3f-4b72-85dc-02e351ce4d8a”,“status”:“success”,“servertime”:1761808102,“action”:“2a80ca92-0e47-5780-b338-3568f3cff69e”,“message”:“The operation was successful.”,“url”:“/auth/jwt/rsa.json”,“code”:200},".....

and I can connect Android device with Passbolt, no issue here.

vs.
image:5.2.0-1-ce

JWT Authentication

\[PASS\] The JWT Authentication plugin is enabled.
\[PASS\] The /etc/passbolt/jwt/ directory is not writable.
\[FAIL\] A valid JWT key pair is missing.
\[HELP\] Run the create JWT keys script to create a valid JWT secret and public key pair:
\[HELP\] sudo su -s /bin/bash -c “/usr/share/php/passbolt/bin/cake passbolt create_jwt_keys” www-data
/bin/bash -c “/usr/share/php/passbolt/bin/cake passbolt create_jwt_keys” www-data

The JWT private key could not be written.

no jwt keys have been deployed.

ls -l /etc/passbolt/jwt/
total 0
{"header":{"id":"bf942988-bb05-4db6-818a-b7064d9b844a","status":"error","servertime":1761811815,"action":"2a80ca92-0e47-5780-b338-3568f3cff69e","message":"The key pair for JWT Authentication is not complete.","url":"\/auth\/jwt\/rsa.json","code":500},"body":""}

and of course, I can no longer connect any Android devices.

It seems that when the jwt directory isn’t writable, no keys are generated. However, according to the health check, this is considered a valid state.
So what’s the next step? Is there a possible permanent fix for this?