Skip to content

Improve global auth token handling and errors#789

Open
cadeljones wants to merge 1 commit intorailwayapp:masterfrom
cadeljones:improve-token-handling-and-error-messages
Open

Improve global auth token handling and errors#789
cadeljones wants to merge 1 commit intorailwayapp:masterfrom
cadeljones:improve-token-handling-and-error-messages

Conversation

@cadeljones
Copy link
Contributor

@cadeljones cadeljones commented Feb 11, 2026

About this PR

This is an attempt to clear up some common DX issues that arise when trying to authorize the CLI with tokens.
Context: #699

The CLI accepts to types of tokens as two separate env variables

  • Scoped tokens via RAILWAY_TOKEN
  • Global tokens via RAILWAY_API_TOKEN

The two issues addressed in this PR

  1. Previously the RAILWAY_TOKEN was being preferred over the RAILWAY_API_TOKEN if both were set.

  2. If the wrong token was used (eg RAILWAY_TOKEN for whoami) the error was a generic Unauthorized warning.

What was changed

The commands that require a global token can now specify that.

This enables two DX improvements

  1. If both tokens are set the RAILWAY_API_TOKEN is used by commands that require it.
  2. If RAILWAY_TOKEN is used incorrectly for commands that require RAILWAY_API_TOKEN a helpful error message indicates this issue.

Possible future improvements

Ultimately the best DX would be a unified token env var and error messages that indicate if a scoped token is being used for a global command.

It would be possible to check on failure if the token is a valid scoped token and if it is indicate so to the user.

Something like this would do the trick


async fn check_if_token_is_scoped(token: &str) -> bool {
    let mut headers = HeaderMap::new();
    let Ok(token_header) = HeaderValue::from_str(token) else {
        return false;
    };
    headers.insert("project-access-token", token_header);
    headers.insert(
        "x-source",
        HeaderValue::from_static(consts::get_user_agent()),
    );

    let Some((client, backboard_url)) = build_probe_client(headers) else {
        return false;
    };

    let body = queries::ProjectToken::build_query(queries::project_token::Variables {});

    let Ok(response) = client.post(backboard_url).json(&body).send().await else {
        return false;
    };

    let Ok(res) = response
        .json::<GraphQLResponse<queries::project_token::ResponseData>>()
        .await
    else {
        return false;
    };

    res.data.is_some()
}

Previously the RAILWAY_TOKEN was being preferred over the RAILWAY_API_TOKEN if both were set.

Now if both are set the RAILWAY_API_TOKEN is used by commands that require it.

Also if the RAILWAY_TOKEN env incorrectly used for commands that require RAILWAY_API_TOKEN a helpful error message indicates the issue.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant