element-hq / element-hq/element-x-android

Element X (Android) — QR login (MSC4108) never sends PUT to rendezvous; both clients cancel (Android 9 / Moto Z3)

Open
#5,187 2 comments 0 reactions 0 assignees View on GitHub
A-QR Code login O-Occasional S-Major T-Defect
Dominant language
Kotlin
Stars
2.4k
Forks
624
Avg merge
1d 14h
Merged PRs (30d)
149

Description

### Steps to reproduce

On desktop (Element Web/Desktop, Firefox 141 on Linux), logged in as @matrixadmin:matrix.example.com with a verified session.

Go to Settings → Security & Privacy → Sessions → Show QR code.

On phone (Element X 25.08.3 on Motorola Moto Z3 / Android 9), tap Sign in with QR and scan.

The flow cancels on both devices.

### Outcome

Expected: After scanning, the phone sends
PUT /_synapse/client/rendezvous/
with Content-Type: text/plain and If-Match, Synapse returns 200/204, and the device links.

Actual: Server shows only GET polling (304) from both desktop and phone; then desktop DELETEs the rendezvous (204) and subsequent GETs 404. No PUT from the phone is ever observed.
Server evidence (Synapse logs)

# GET poll from phone (Element X)
... 192.168.50.180 ... 0B 304 "GET /_synapse/client/rendezvous/01K2Z... HTTP/1.1" "Element X/25.08.3 ..."
# GET poll from desktop (Firefox)
... 192.168.50.10 ... 0B 304 "GET /_synapse/client/rendezvous/01K2Z... HTTP/1.1" "Mozilla/5.0 ..."
# Desktop cancels
... 192.168.50.10 ... 0B 204 "DELETE /_synapse/client/rendezvous/01K2Z... HTTP/1.1"
# After deletion
... 192.168.50.180 ... 45B 404 "GET /_synapse/client/rendezvous/01K2Z... HTTP/1.1"

Notice there is never a PUT /_synapse/client/rendezvous/ from the phone.

Minimal server proof (MSC4108 works when driven manually)

# Create rendezvous
POST /_matrix/client/unstable/org.matrix.msc4108/rendezvous
Content-Type: text/plain
→ 201 Created (returns rendezvous URL + ETag)

# Simulate phone write
PUT /_synapse/client/rendezvous/
If-Match:
Content-Type: text/plain
Body: ok
→ 202 / 204

This shows Synapse + proxy are fine; the phone simply never performs the PUT after scanning.
Homeserver / proxy

Domain: matrix.example.com (Synapse behind nginx)

Synapse: 1.136.0

MAS: v1.0.0-rc.0 (OIDC present but QR flow uses Synapse rendezvous, not MAS)

MSC4108 enabled; rendezvous proxied via nginx.

Rendezvous nginx block (CORS tolerant; PUT allowed):

location ^~ /_synapse/client/rendezvous {
# Echo Origin; fallback to * if none (and adjust creds)
set $cors_origin $http_origin;
if ($cors_origin = "") { set $cors_origin "*"; }
set $cors_creds "true";
if ($cors_origin = "*") { set $cors_creds "false"; }

# Preflight
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials $cors_creds always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers $http_access_control_request_headers always;
add_header Vary "Origin" always;
return 204;
}

# Actual
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials $cors_creds always;
add_header Access-Control-Expose-Headers "Location, ETag" always;
add_header Vary "Origin" always;

proxy_set_header Authorization $http_authorization;
proxy_set_header Origin $http_origin; # forward if present
proxy_pass http://127.0.0.1:8008;
proxy_http_version 1.1;
proxy_read_timeout 600s;
proxy_buffering off;
}

Preflight probes return 204, Access-Control-Allow-Methods includes PUT, and manual PUT with text/plain succeeds.
Device / client

Phone: Motorola Moto Z3, Android 9 (PDX29.84-51-11-8)

Element X: 25.08.3 (installed via Aurora Store)

Chrome & Android System WebView: installed/enabled & up to date

Permissions: Camera/network enabled for Element X; Chrome/WebView enabled

Network: Reproduces on LAN and cellular

What I tried

Reinstall Element X; clear cache

Ensure Chrome + Android System WebView enabled/updated; set WebView implementation appropriately

Loosened CORS to mirror $http_origin (fallback *) and mirror requested headers; long timeouts

Verified reachability from phone: /_matrix/client/versions OK; manual rendezvous POST/PUT OK

Tried Element Android (legacy): no “Sign in with QR” on the first screen (as expected); manual login + emoji verification works

Hypothesis

On this Android 9 device, Element X’s WebView path appears to suppress the rendezvous PUT after scanning (likely CORS/origin/preflight interaction or a WebView quirk). Since manual PUT text/plain works and logs show no server-side rejects, the request seems to never leave the client.
Workaround

Manual login on phone → verify via emoji from desktop; phone becomes trusted (works).

Attachments added:
– elementx-only.log (Element X PID during QR attempt)
– Synapse log lines (GET 304 from phone+desktop → DELETE 204 by desktop → 404; no phone PUT)
– nginx rendezvous CORS block (allows PUT, mirrors Origin/headers; preflights 204)
– Verified server path works with manual POST/PUT text/plain (202/204).
I can capture full adb logcat or try a debug build if you want deeper client traces.

[elementx-only.log](https://github.com/user-attachments/files/21864241/elementx-only.log)

### Your phone model

_No response_

### Operating system version

_No response_

### Application version and app store

_No response_

### Homeserver

_No response_

### Will you send logs?

Yes

### Are you willing to provide a PR?

No

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.