feat(auth): add 'aqora auth token' for external consumers#187
Conversation
📝 WalkthroughWalkthroughA new Changes
Sequence DiagramsequenceDiagram
participant User as User/CLI
participant AuthCmd as Auth Token<br/>Command
participant Creds as Credentials<br/>Module
participant GraphQL as GraphQL<br/>Client
participant FileSystem as File<br/>System
User->>AuthCmd: Run auth token [--url]
AuthCmd->>AuthCmd: Resolve API URL
AuthCmd->>AuthCmd: Compute credentials path
AuthCmd->>GraphQL: Create unauthenticated client
AuthCmd->>Creds: load_refreshed_credentials()
Creds->>FileSystem: Read cached credentials
alt Credentials present
Creds->>Creds: Check expiration
alt Token expired
Creds->>GraphQL: Refresh token
end
Creds->>FileSystem: Reload/verify credentials
Creds-->>AuthCmd: Return LoadCredentials
AuthCmd->>User: Output access_token
else Credentials absent
Creds-->>AuthCmd: Error: No credentials
AuthCmd->>User: Error: Run 'aqora login'
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/commands/auth/token.rs (1)
19-31: Consider:--urloverlaps with the existing global--url.
GlobalArgsalready exposes--url(used viaglobal.aqora_url()on line 30), so users can already doaqora --url https://... auth token. Adding a second subcommand-level--urlmeans bothaqora --url X auth tokenandaqora auth token --url Xwork, with subcommand winning if both are set. That's functional, but a bit confusing.Two options, in decreasing order of invasiveness:
- Drop the subcommand-level flag entirely and rely on the global
--url.- Keep it, but mention in the help text that it overrides the global
--url, so users passing both understand the precedence.If the rationale is discoverability for external consumers (so
aqora auth token --helpsurfaces the flag), option 2 is fine.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/commands/auth/token.rs` around lines 19 - 31, The Token subcommand defines its own --url flag (Token.url) while the global GlobalArgs already provides a --url used via global.aqora_url() in the token() function, causing overlapping flags; either remove the Token.url field and always use global.aqora_url(), or update the Token.url arg help to explicitly state it overrides the global --url so precedence is clear (and keep the existing match in token() that prefers args.url over global.aqora_url()); reference Token struct, its url field, and the token(args: Token, global: GlobalArgs) -> Result() function where global.aqora_url() is used.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/commands/auth/token.rs`:
- Around line 34-41: The error hint when load_refreshed_credentials(...) fails
is misleading for refresh-related failures; update the error::system call in the
error mapping (the closure passed to load_refreshed_credentials) to use a more
accurate hint message indicating possible expired/revoked session or
network/refresh-token issues (mentioning refresh token expiration or session
revocation and suggesting re-authentication or checking network), rather than
"Check your configuration and try again."; reference load_refreshed_credentials,
refresh_credentials and the error::system invocation so you change the hint text
in that closure.
---
Nitpick comments:
In `@src/commands/auth/token.rs`:
- Around line 19-31: The Token subcommand defines its own --url flag (Token.url)
while the global GlobalArgs already provides a --url used via global.aqora_url()
in the token() function, causing overlapping flags; either remove the Token.url
field and always use global.aqora_url(), or update the Token.url arg help to
explicitly state it overrides the global --url so precedence is clear (and keep
the existing match in token() that prefers args.url over global.aqora_url());
reference Token struct, its url field, and the token(args: Token, global:
GlobalArgs) -> Result() function where global.aqora_url() is used.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1fed5c58-021a-4317-9c4f-e56a88c36455
📒 Files selected for processing (4)
src/commands/auth/mod.rssrc/commands/auth/token.rssrc/commands/mod.rssrc/credentials.rs
| let loaded = load_refreshed_credentials(&path, &url, &client) | ||
| .await | ||
| .map_err(|e| { | ||
| error::system( | ||
| &format!("Failed to load credentials for {url}: {e}"), | ||
| "Check your configuration and try again.", | ||
| ) | ||
| })?; |
There was a problem hiding this comment.
Minor: error hint may mislead for expired/revoked refresh tokens.
load_refreshed_credentials hits the network via refresh_credentials when the cached token is expired, so failures here commonly surface as "refresh token invalid / session revoked / network error" rather than a configuration problem. The current hint "Check your configuration and try again." will send users down the wrong path for the most common case (session expired after being logged in a while).
💡 Suggested wording tweak
.map_err(|e| {
error::system(
&format!("Failed to load credentials for {url}: {e}"),
- "Check your configuration and try again.",
+ "Your session may have expired or the API is unreachable. Try running 'aqora login' again, or check your network/configuration.",
)
})?;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/commands/auth/token.rs` around lines 34 - 41, The error hint when
load_refreshed_credentials(...) fails is misleading for refresh-related
failures; update the error::system call in the error mapping (the closure passed
to load_refreshed_credentials) to use a more accurate hint message indicating
possible expired/revoked session or network/refresh-token issues (mentioning
refresh token expiration or session revocation and suggesting re-authentication
or checking network), rather than "Check your configuration and try again.";
reference load_refreshed_credentials, refresh_credentials and the error::system
invocation so you change the hint text in that closure.
Try the refresh-aware 'aqora auth token' path before falling back to reading credentials.json directly. Older aqora-cli versions that do not yet ship the auth subcommand fall through transparently. When 'aqora auth token' is available, expired access tokens are refreshed automatically via the refresh_token and do not surface as INVALID_AUTHORIZATION errors for the user. This closes the roughly-24-hour footgun documented in the repo's known issues and mirrors the pattern from aqora-io/cli#187 (merged). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This pull request was authored by a coding agent on behalf of @stubbi (jannes@aqora.io).
Motivation
External consumers (aqora-io/skills, CI jobs, other agents, third-party tools) need a stable contract to get a valid aqora access token. Today they have to read
credentials.jsondirectly, which does not trigger the CLI's existing refresh logic, so tokens silently go stale after their short lifetime.This adds
aqora auth token, matching the well-established pattern fromgh auth token,gcloud auth print-access-token, andaws configure export-credentials. One clean contract: print a fresh access token on stdout, refreshing as needed.Context: aqora-io/skills#1 (separate issue, but the skills repo was where this need surfaced).
What this PR does
authcommand group and atokensubcommand under it.aqora auth tokenprints a valid access token on stdout for the current API URL.credentials::load_refreshed_credentialsso refresh is transparent; no new auth code.--url URLflag to target a specific API URL when logged into multiple environments.aqora loginbehavior.What this PR explicitly does not do
aqora auth login,logout, orstatussubcommands. Those are obvious follow-ups but scope creep here.login,shell,lab, or any other existing command.Testing
Build:
cargo build --releaseclean, no new warnings.Clippy:
cargo clippy --all-targetsno new warnings.Live token test against the production API:
Error path: used
--url https://bogus.exampleand confirmed the expected stderr message and exit 1:Reviewer notes
Small surface area. The entire change is wiring plus a call into
credentials::load_refreshed_credentials(previously a private helper, now exported). Suggested follow-ups for a future PR:aqora auth loginas alias,aqora auth logout,aqora auth status.Summary by CodeRabbit
authcommand withtokensubcommand to retrieve and display access tokens--urlparameter to specify a custom API endpoint