fj auth login --fjord fails out of the box: DEFAULT_PLATFORM_URL points at the Cloudflare Access-protected pages.dev origin #250

Closed
opened 2026-08-13 18:20:15 +00:00 by stephen · 1 comment
Owner

Two independent problems make Fjord Account sign-in unusable without knowing the workaround. Both hit on the current release (0.4.1) on a headless Linux box.

1. The default platform URL is the pages.dev origin, which is behind Cloudflare Access

src/fjord/mod.rs:24:

pub const DEFAULT_PLATFORM_URL: &str = "https://forgejo-site.pages.dev";

That host is protected by Cloudflare Access, so the device-authorization request gets an HTML sign-in page rather than JSON:

error: starting device-flow sign-in
  caused by: decoding device-authorization response: <!DOCTYPE html>
    <title>Sign in ・ Cloudflare Access</title>
  caused by: expected value at line 1 column 1

Passing the real production URL works immediately:

fj auth login --fjord --platform-url https://fjord.sh

The device flow then starts correctly, prints the code and QR, and points at https://fjord.sh/device.

Suggested fix: default to https://fjord.sh. A deployment-preview origin should not be the fallback for every user, and an Access-protected one can never work for a non-interactive client. Worth also detecting a non-JSON content type and saying "the platform URL is not serving the API, it returned an HTML page, check --platform-url" rather than surfacing a JSON decode error, which sends you looking at the wrong layer.

2. An exported FJ_TOKEN blocks --fjord entirely

--token is declared with env = "FJ_TOKEN", so an exported token is treated as if it had been typed:

$ fj auth login --fjord
error: the argument '--fjord' cannot be used with '--token <TOKEN>'

The workaround is env -u FJ_TOKEN fj auth login --fjord. Note FJ_TOKEN= fj auth login --fjord is not enough, since an empty-but-set variable still reads as present.

This matters more than a normal flag conflict because fj#147's own guidance is to export FJ_TOKEN from the shell profile to survive a locked keychain. Following the documented setup therefore makes --fjord unreachable in every shell.

Suggested fix: only conflict when --token came from the command line. src/cli/auth_login.rs:762 already distinguishes an env-provided token from an explicit one, so the information exists and simply is not used for the conflict rule. An env token should be ignored in --fjord mode, or at most warned about.

src/auth/mod.rs:96: "Look up the token for host: first FJ_TOKEN, then keychain, then file."

So FJ_TOKEN is presented to whatever host is targeted, and shadows any per-host credential. Concretely, fj api --host commons.fjord.host sends the rasterhub.com PAT to commons and gets a 401, and fj auth status --host commons.fjord.host reports rasterhub.com regardless. Signing into a second host does not take effect while the variable is exported.

Both hosts here are ours so the exposure is small, but a credential for one forge being transmitted to another because of an environment variable is worth closing. Scoping it, for example FJ_TOKEN_<HOST> or honouring it only for the current host, would fix the shadowing and the surprise together.

Two independent problems make Fjord Account sign-in unusable without knowing the workaround. Both hit on the current release (0.4.1) on a headless Linux box. ## 1. The default platform URL is the pages.dev origin, which is behind Cloudflare Access `src/fjord/mod.rs:24`: ```rust pub const DEFAULT_PLATFORM_URL: &str = "https://forgejo-site.pages.dev"; ``` That host is protected by Cloudflare Access, so the device-authorization request gets an HTML sign-in page rather than JSON: ``` error: starting device-flow sign-in caused by: decoding device-authorization response: <!DOCTYPE html> <title>Sign in ・ Cloudflare Access</title> caused by: expected value at line 1 column 1 ``` Passing the real production URL works immediately: ``` fj auth login --fjord --platform-url https://fjord.sh ``` The device flow then starts correctly, prints the code and QR, and points at `https://fjord.sh/device`. **Suggested fix:** default to `https://fjord.sh`. A deployment-preview origin should not be the fallback for every user, and an Access-protected one can never work for a non-interactive client. Worth also detecting a non-JSON content type and saying "the platform URL is not serving the API, it returned an HTML page, check --platform-url" rather than surfacing a JSON decode error, which sends you looking at the wrong layer. ## 2. An exported `FJ_TOKEN` blocks `--fjord` entirely `--token` is declared with `env = "FJ_TOKEN"`, so an exported token is treated as if it had been typed: ``` $ fj auth login --fjord error: the argument '--fjord' cannot be used with '--token <TOKEN>' ``` The workaround is `env -u FJ_TOKEN fj auth login --fjord`. Note `FJ_TOKEN= fj auth login --fjord` is not enough, since an empty-but-set variable still reads as present. This matters more than a normal flag conflict because fj#147's own guidance is to export `FJ_TOKEN` from the shell profile to survive a locked keychain. Following the documented setup therefore makes `--fjord` unreachable in every shell. **Suggested fix:** only conflict when `--token` came from the command line. `src/cli/auth_login.rs:762` already distinguishes an env-provided token from an explicit one, so the information exists and simply is not used for the conflict rule. An env token should be ignored in `--fjord` mode, or at most warned about. ## 3. Related, the same env token is host-agnostic `src/auth/mod.rs:96`: "Look up the token for `host`: first `FJ_TOKEN`, then keychain, then file." So `FJ_TOKEN` is presented to whatever host is targeted, and shadows any per-host credential. Concretely, `fj api --host commons.fjord.host` sends the rasterhub.com PAT to commons and gets a 401, and `fj auth status --host commons.fjord.host` reports rasterhub.com regardless. Signing into a second host does not take effect while the variable is exported. Both hosts here are ours so the exposure is small, but a credential for one forge being transmitted to another because of an environment variable is worth closing. Scoping it, for example `FJ_TOKEN_<HOST>` or honouring it only for the current host, would fix the shadowing and the surprise together.
Author
Owner

Recording why this stayed closed, since a branch fixing it is still sitting on the remote.

fix/250-auth-fixes exists at b08c803 ("Fix Fjord auth defaults and token scoping"), is not an ancestor of main, and never had a PR opened. It surfaced tonight as stranded work on a lane. It is redundant: current main fixes all three problems by other commits, verified by reading the code rather than commit subjects.

  1. Default platform URL. src/fjord/mod.rs:24 is pub const DEFAULT_PLATFORM_URL: &str = "https://fjord.sh";, pinned by src/client/integration_tests.rs:573. The secondary ask landed too: src/fjord/mod.rs:180-204 inspects Content-Type, sniffs a leading <!doctype html / <html, and errors with "returned an HTML page rather than the Fjord platform API (HTTP {status}); check --platform-url" instead of a JSON decode error.
  2. FJ_TOKEN blocking --fjord. src/cli/auth.rs:97-99 declares --token as #[arg(long, hide_env_values = true)]. The env = "FJ_TOKEN" binding is gone, so an exported token no longer synthesizes the flag and cannot trip conflicts_with_all = ["token", "with_token"] on --fjord at line 111. Covered by src/cli/mod.rs:322.
  3. Host-agnostic env token. src/client/resolve.rs:61-80: generic_env_allowed_for_resolved_host returns true only when no --host was passed or when --host names the configured default, and pat_token_for_resolved_host tries auth::env_token_for_host(name) first. src/auth/mod.rs:191-205 adds FJ_TOKEN_<HOST>. So fj api --host commons.fjord.host no longer sends the rasterhub.com PAT.

So the branch can be deleted. Leaving that to the operator rather than doing it here, since it is the only copy of that work and nothing is gained by removing it today. b08c803 is recorded above if it is ever wanted.

Recording why this stayed closed, since a branch fixing it is still sitting on the remote. `fix/250-auth-fixes` exists at `b08c803` ("Fix Fjord auth defaults and token scoping"), is **not** an ancestor of `main`, and never had a PR opened. It surfaced tonight as stranded work on a lane. It is redundant: current `main` fixes all three problems by other commits, verified by reading the code rather than commit subjects. 1. **Default platform URL.** `src/fjord/mod.rs:24` is `pub const DEFAULT_PLATFORM_URL: &str = "https://fjord.sh";`, pinned by `src/client/integration_tests.rs:573`. The secondary ask landed too: `src/fjord/mod.rs:180-204` inspects `Content-Type`, sniffs a leading `<!doctype html` / `<html`, and errors with "returned an HTML page rather than the Fjord platform API (HTTP {status}); check --platform-url" instead of a JSON decode error. 2. **`FJ_TOKEN` blocking `--fjord`.** `src/cli/auth.rs:97-99` declares `--token` as `#[arg(long, hide_env_values = true)]`. The `env = "FJ_TOKEN"` binding is gone, so an exported token no longer synthesizes the flag and cannot trip `conflicts_with_all = ["token", "with_token"]` on `--fjord` at line 111. Covered by `src/cli/mod.rs:322`. 3. **Host-agnostic env token.** `src/client/resolve.rs:61-80`: `generic_env_allowed_for_resolved_host` returns true only when no `--host` was passed or when `--host` names the configured default, and `pat_token_for_resolved_host` tries `auth::env_token_for_host(name)` first. `src/auth/mod.rs:191-205` adds `FJ_TOKEN_<HOST>`. So `fj api --host commons.fjord.host` no longer sends the rasterhub.com PAT. So the branch can be deleted. Leaving that to the operator rather than doing it here, since it is the only copy of that work and nothing is gained by removing it today. `b08c803` is recorded above if it is ever wanted.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rasterstate/fj#250
No description provided.