fix: handle raw m2. macaroon tokens from Fly.io CLI Sessions API (#1552)

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) <noreply@anthropic.com>
This commit is contained in:
L 2026-02-21 02:54:34 -05:00 committed by GitHub
parent 328e6a6da4
commit 9fc59ded1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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 <token>"
# 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