You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
cloudflared access login deadlocks forever against its own token lock file whenever the token minted during login fails the edge verification step. The most common trigger: the Access application has "Enable Binding Cookie" turned on, so a bare JWT (no bound cookie) is always rejected at the edge. Every retry of the command hangs the same way, and the printed "Another cloudflared process (pid N) is already waiting for authentication" names the process's own PID.
Root cause (traced in master)
login → verifyTokenAtEdge → isTokenValid → carrier.BuildAccessRequest → token.FetchTokenWithRedirect (fetch Refactor to separate command from library functions #1). getToken acquires the app-token lock via acquireLockFile (token/token.go). This lock is never released during the process lifetime — reclaim only happens when the owning PID is dead/stale.
Fetch Refactor to separate command from library functions #1 succeeds (org-token exchange or browser flow). isTokenValid then presents the JWT as a header; with the binding cookie enabled the edge responds with a login redirect → token judged invalid.
verifyTokenAtEdge calls token.RemoveTokenIfExists (deleting the just-minted token) and calls isTokenValid again → fetch Cannot register tunnel #2in the same process → acquireLockFile finds the lock from step 1, reads its own PID, sees it alive, and waits forever — printing the "Another cloudflared process" banner with its own PID and replaying the stale .url companion file from a previous run.
Because the lock owner is alive, the staleness reclaim never fires; the command hangs until lockTimeout. Users who Ctrl+C and retry see a rotating cast of "stale" PIDs (each dead predecessor) followed by the same self-deadlock, which makes this very confusing to diagnose. The replayed stale auth URL is also actively harmful: users authorize it in the browser and the resulting transfer goes to a poller that no longer exists.
Debug trace (hostname redacted)
2026-07-08T13:18:01Z DBG reclaiming stale lock file path=/Users/x/.cloudflared/app.example.com-<aud>-token.lock stale_pid=95277
2026-07-08T13:18:01Z DBG lock file acquired path=/Users/x/.cloudflared/app.example.com-<aud>-token.lock
Another cloudflared process (pid 13091) is already waiting for authentication.
...
2026-07-08T13:18:02Z DBG lock file is held by another process, retrying path=/Users/x/.cloudflared/app.example.com-<aud>-token.lock
2026-07-08T13:18:04Z DBG lock file is held by another process, retrying path=...
Confirmed: the lock file content was {"pid":13091,"start_time":1783516681035} — pid 13091 with that start time (13:18:01.035) is the process that produced this log, i.e. it is waiting on itself.
Repro
Create a self-hosted Access application with Enable Binding Cookie on.
cloudflared access login https://<app> on a machine with no cached tokens.
Complete the browser authorization → CLI hangs forever; all subsequent invocations hang too.
Workaround for users
Disable the binding cookie on the Access application (required anyway for any header-based/automated access to the app), then clear ~/.cloudflared/*.lock and retry.
cloudflared version: 2026.6.1 (built 2026-06-18), macOS (Darwin 25.5.0)
Summary
cloudflared access logindeadlocks forever against its own token lock file whenever the token minted during login fails the edge verification step. The most common trigger: the Access application has "Enable Binding Cookie" turned on, so a bare JWT (no bound cookie) is always rejected at the edge. Every retry of the command hangs the same way, and the printed "Another cloudflared process (pid N) is already waiting for authentication" names the process's own PID.Root cause (traced in master)
login→verifyTokenAtEdge→isTokenValid→carrier.BuildAccessRequest→token.FetchTokenWithRedirect(fetch Refactor to separate command from library functions #1).getTokenacquires the app-token lock viaacquireLockFile(token/token.go). This lock is never released during the process lifetime — reclaim only happens when the owning PID is dead/stale.isTokenValidthen presents the JWT as a header; with the binding cookie enabled the edge responds with a login redirect → token judged invalid.verifyTokenAtEdgecallstoken.RemoveTokenIfExists(deleting the just-minted token) and callsisTokenValidagain → fetch Cannot register tunnel #2 in the same process →acquireLockFilefinds the lock from step 1, reads its own PID, sees it alive, and waits forever — printing the "Another cloudflared process" banner with its own PID and replaying the stale.urlcompanion file from a previous run.Because the lock owner is alive, the staleness reclaim never fires; the command hangs until
lockTimeout. Users who Ctrl+C and retry see a rotating cast of "stale" PIDs (each dead predecessor) followed by the same self-deadlock, which makes this very confusing to diagnose. The replayed stale auth URL is also actively harmful: users authorize it in the browser and the resulting transfer goes to a poller that no longer exists.Debug trace (hostname redacted)
Confirmed: the lock file content was
{"pid":13091,"start_time":1783516681035}— pid 13091 with that start time (13:18:01.035) is the process that produced this log, i.e. it is waiting on itself.Repro
cloudflared access login https://<app>on a machine with no cached tokens.Workaround for users
Disable the binding cookie on the Access application (required anyway for any header-based/automated access to the app), then clear
~/.cloudflared/*.lockand retry.