From 9fc59ded1c940b801197fac6da87541edae3d701 Mon Sep 17 00:00:00 2001 From: L <6723574+louisgv@users.noreply.github.com> Date: Sat, 21 Feb 2026 02:54:34 -0500 Subject: [PATCH] fix: handle raw m2. macaroon tokens from Fly.io CLI Sessions API (#1552) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause of 'no tokens found in header' after browser OAuth: The Fly.io CLI Sessions API returns raw macaroon tokens (e.g. m2.XXXX) WITHOUT the 'FlyV1 ' prefix. _sanitize_fly_token only handled fm2_ tokens, so m2. tokens fell through unchanged and were sent as: Authorization: Bearer m2.XXXX Fly.io's Machines API expects FlyV1 macaroon format, not Bearer. Fixes: - _sanitize_fly_token: add m2.* case that wraps as 'FlyV1 m2.XXX' - _try_fly_browser_auth polling: eagerly wrap any non-FlyV1 token with 'FlyV1 ' prefix at the source, before it's echoed back to the caller Token format handling after fix: m2.XXXX → FlyV1 m2.XXXX ← CLI Sessions API (was broken) fm2_XXXX → FlyV1 fm2_XXXX ← still handled (unchanged) FlyV1 fm2_XXXX → FlyV1 fm2_XXXX ← already correct (unchanged) eyJhbGci... → Bearer eyJ... ← legacy JWT (fallback to manual) Co-authored-by: Claude Sonnet 4.6 (1M context) --- fly/lib/common.sh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fly/lib/common.sh b/fly/lib/common.sh index 84da3d9f..d0e5a9a3 100644 --- a/fly/lib/common.sh +++ b/fly/lib/common.sh @@ -123,18 +123,24 @@ _try_flyctl_auth() { # Sanitize a Fly.io token — the dashboard copy button may include the # display name before the actual token (e.g. "Deploy Token FlyV1 fm2_...") -# Strip everything before "FlyV1" or "fm2_", and trim whitespace/newlines. +# Also handles raw macaroon tokens returned by the CLI Sessions API +# (e.g. "m2.XXXX" or "fm2_XXXX" without the "FlyV1 " prefix). +# All Fly.io v2 macaroon tokens must be sent as "Authorization: FlyV1 " +# regardless of whether the raw value already includes the prefix. _sanitize_fly_token() { local raw="$1" # Trim leading/trailing whitespace and newlines raw=$(printf '%s' "$raw" | tr -d '\n\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') - # If it contains "FlyV1 ", strip everything before it (display name prefix) + # If it already contains "FlyV1 ", strip any display name prefix before it if [[ "$raw" == *"FlyV1 "* ]]; then raw="FlyV1 ${raw##*FlyV1 }" - # If it contains a bare "fm2_" token without FlyV1 prefix, extract it + # Raw fm2_ macaroon (no FlyV1 prefix) — extract and wrap elif [[ "$raw" == *"fm2_"* ]]; then raw=$(printf '%s' "$raw" | sed 's/.*\(fm2_[^ ]*\).*/\1/') raw="FlyV1 $raw" + # Raw m2. macaroon returned by CLI Sessions API — wrap with FlyV1 prefix + elif [[ "$raw" == m2.* ]]; then + raw="FlyV1 $raw" fi printf '%s' "$raw" } @@ -209,6 +215,9 @@ _try_fly_browser_auth() { access_token=$(echo "$poll_response" | _fly_json_get "access_token") if [[ -n "$access_token" ]]; then + # Wrap raw macaroons in FlyV1 format at the source so fly_api + # uses the correct Authorization header (not Bearer). + [[ "$access_token" != FlyV1\ * ]] && access_token="FlyV1 $access_token" echo "$access_token" return 0 fi