Summary
The Railway CLI returns
Invalid or expired Railway token. Please run 'railway login' to refresh your authentication
when authenticating via RAILWAY_API_TOKEN with a workspace-scoped API
token, even though the same token authenticates successfully against
https://backboard.railway.com/graphql/v2. An account-scoped ("No workspace")
token, minted from the same account at the same time, works fine with the CLI.
This forces users who want least-privilege scoped access to fall back to broader
account tokens, which defeats the purpose of workspace scoping.
This is not a duplicate of #699.
That issue reports account tokens failing on Linux; this issue reports
workspace tokens failing on macOS while account tokens from the same
account succeed. Same error string, different failure mode.
Reproduction
- In Account Settings → Tokens, mint two tokens from the same account:
- Token A — Workspace dropdown set to
<your workspace> (workspace-scoped)
- Token B — Workspace dropdown set to
No workspace (account-scoped)
- Test Token A with the CLI:
export RAILWAY_API_TOKEN=<Token A>
railway whoami # → "Invalid or expired Railway token."
railway list # → same error
- Test Token B with the CLI:
export RAILWAY_API_TOKEN=<Token B>
railway whoami # → succeeds
railway list # → succeeds
- Test Token A against GraphQL to prove the token itself is valid:
curl -sS \
-H "Authorization: Bearer <Token A>" \
-H "Content-Type: application/json" \
-d '{"query":"{ projects { edges { node { id name } } } }"}' \
https://backboard.railway.com/graphql/v2
→ returns the expected projects payload for the workspace.
So the token is valid; the CLI is the component rejecting it.
Expected behavior
Workspace-scoped tokens should authenticate CLI operations that fall within
their scope (railway list, railway link, railway up, etc. scoped to
projects inside that workspace).
If some CLI endpoint genuinely requires account-wide scope (e.g. whoami
resolving across workspaces), the CLI should surface a clearer error — e.g.
"This command requires an account-scoped token; the provided token is scoped
to workspace <name>" — rather than the generic "Invalid or expired", which
sends users down the wrong diagnostic path (they rotate tokens instead of
narrowing scope).
Environment
| Field |
Value |
| CLI versions tested |
railway 4.36.1 and railway 4.37.4 (both fail identically; 4.37.4 was the latest release at repro time) |
| OS |
macOS 15 (Darwin 25.3.0) |
| Architecture |
arm64 (Apple Silicon) |
| Install method |
Homebrew (brew install railway) |
| Env var used |
RAILWAY_API_TOKEN (the CLI-wide account/workspace var — not RAILWAY_TOKEN, which is the project-token var) |
| Also reproduced via |
@railway/mcp-server (it wraps the CLI and inherits the failure); reproduced calling the CLI directly, so the MCP wrapper is not the cause |
Verbose output
Run with debug logging, workspace token in env:
export RAILWAY_API_TOKEN=<Token A — workspace-scoped>
RUST_LOG=debug railway whoami 2>&1
Output (token redacted — RUST_LOG=debug prints the full Authorization
header, so make sure to scrub it before pasting here):
<paste redacted debug output from the command above>
Impact
Blocks adoption of workspace-scoped tokens for any CLI-driven or CLI-wrapped
workflow:
- Interactive development where a user wants a workspace-scoped token rather
than a full account token on their dev machine.
- Automated tooling that wraps the CLI — e.g.
@railway/mcp-server, IDE
integrations, internal scripts.
- CI/CD that operates across multiple projects in a single workspace, where a
project token is too narrow but an account token is broader than desired.
The currently viable fallbacks are:
- Account tokens — work with the CLI but grant account-wide access.
- Project tokens (
RAILWAY_TOKEN) — work for railway up / railway run
but are scoped to a single project + environment.
Neither covers the "scoped to one workspace" use case that workspace tokens
are meant to provide.
Notes for maintainers
- Workspace and user IDs, plus a UTC timestamp of a failing attempt, are
available on request — happy to share those via a Central Station Private
Thread so the token/IDs aren't exposed publicly.
- Raw token material will not be attached here; any debug output above has the
Authorization header redacted.
Summary
The Railway CLI returns
when authenticating via
RAILWAY_API_TOKENwith a workspace-scoped APItoken, even though the same token authenticates successfully against
https://backboard.railway.com/graphql/v2. An account-scoped ("No workspace")token, minted from the same account at the same time, works fine with the CLI.
This forces users who want least-privilege scoped access to fall back to broader
account tokens, which defeats the purpose of workspace scoping.
This is not a duplicate of #699.
That issue reports account tokens failing on Linux; this issue reports
workspace tokens failing on macOS while account tokens from the same
account succeed. Same error string, different failure mode.
Reproduction
<your workspace>(workspace-scoped)No workspace(account-scoped)projectspayload for the workspace.So the token is valid; the CLI is the component rejecting it.
Expected behavior
Workspace-scoped tokens should authenticate CLI operations that fall within
their scope (
railway list,railway link,railway up, etc. scoped toprojects inside that workspace).
If some CLI endpoint genuinely requires account-wide scope (e.g.
whoamiresolving across workspaces), the CLI should surface a clearer error — e.g.
"This command requires an account-scoped token; the provided token is scoped
to workspace
<name>" — rather than the generic "Invalid or expired", whichsends users down the wrong diagnostic path (they rotate tokens instead of
narrowing scope).
Environment
railway 4.36.1andrailway 4.37.4(both fail identically; 4.37.4 was the latest release at repro time)brew install railway)RAILWAY_API_TOKEN(the CLI-wide account/workspace var — notRAILWAY_TOKEN, which is the project-token var)@railway/mcp-server(it wraps the CLI and inherits the failure); reproduced calling the CLI directly, so the MCP wrapper is not the causeVerbose output
Run with debug logging, workspace token in env:
Output (token redacted —
RUST_LOG=debugprints the fullAuthorizationheader, so make sure to scrub it before pasting here):
Impact
Blocks adoption of workspace-scoped tokens for any CLI-driven or CLI-wrapped
workflow:
than a full account token on their dev machine.
@railway/mcp-server, IDEintegrations, internal scripts.
project token is too narrow but an account token is broader than desired.
The currently viable fallbacks are:
RAILWAY_TOKEN) — work forrailway up/railway runbut are scoped to a single project + environment.
Neither covers the "scoped to one workspace" use case that workspace tokens
are meant to provide.
Notes for maintainers
available on request — happy to share those via a Central Station Private
Thread so the token/IDs aren't exposed publicly.
Authorizationheader redacted.