feat: oauth authentication#320
Conversation
There was a problem hiding this comment.
0 issues found across 6 files (changes from recent commits).
Requires human review: This PR introduces a new OAuth authentication flow with PKCE, token refresh, and credential migration across multiple commands and core libraries, which is a high-risk change to critical authentication logic that requires human review for security, correctness, and integration with existing API key
Re-trigger cubic
There was a problem hiding this comment.
7 issues found
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Requires human review: Auto-approval blocked by 6 unresolved issues from previous reviews.
Re-trigger cubic
There was a problem hiding this comment.
2 issues found across 5 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
Signed-off-by: Gabriel Miranda <gabrielmfern@outlook.com>
Signed-off-by: Gabriel Miranda <gabrielmfern@outlook.com>
Signed-off-by: Gabriel Miranda <gabrielmfern@outlook.com>
Signed-off-by: Gabriel Miranda <gabrielmfern@outlook.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Gabriel Miranda <gabrielmfern@outlook.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Signed-off-by: Gabriel Miranda <gabrielmfern@outlook.com>
Signed-off-by: Gabriel Miranda <gabrielmfern@outlook.com>
Signed-off-by: Gabriel Miranda <gabrielmfern@outlook.com>
Signed-off-by: Gabriel Miranda <gabrielmfern@outlook.com>
Felipe review (#1): getJwtExp cast the decoded payload without guards, so a malformed access token would throw a cryptic error or store NaN/undefined as the expiry, leaving the credential in an inconsistent state. Validate segment count, JSON payload, and numeric exp, throwing a clear re-login message.
Felipe review (#6): both refreshOAuthGrant and exchangeAuthorizationCode cast the JSON body with `as` after only checking response.ok. A 200 with an unexpected body (proxy error page, partial payload) would be persisted as a grant. Add parseTokenResponse() to validate the required fields and reuse it in both token calls.
Felipe review (#8): the refresh and exchange fetches had no timeout, so a hung connection would make the CLI wait forever. Route both through a shared fetchOAuthToken helper that aborts after 30s (AbortSignal.timeout) and maps TimeoutError / network failures to clear, actionable messages.
Felipe review (#7): the loopback callback always rendered "Authentication complete", even when the provider returned ?error= or omitted code/state. Render a distinct "Authentication failed" page in those cases so the user isn't told success while the terminal reports failure. Promise resolve/reject logic is unchanged.
…nd reuse helper to avoid drift solutions
There was a problem hiding this comment.
0 issues found across 3 files (changes from recent commits).
Requires human review: Implements OAuth authentication with PKCE flow, token refresh, and secure credential storage across the CLI. This is a major architectural change affecting auth, credential management, and API client construction.
Re-trigger cubic
There was a problem hiding this comment.
0 issues found across 2 files (changes from recent commits).
Requires human review: Adds OAuth authentication, a major new feature affecting core login, credential storage, and multiple commands. High risk; requires human review.
Re-trigger cubic
There was a problem hiding this comment.
2 issues found across 2 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
There was a problem hiding this comment.
0 issues found across 5 files (changes from recent commits).
Requires human review: Auto-approval blocked by 2 unresolved issues from previous reviews.
Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
There was a problem hiding this comment.
0 issues found across 2 files (changes from recent commits).
Requires human review: Auto-approval blocked by 3 unresolved issues from previous reviews.
Re-trigger cubic
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Requires human review: This is a major feature adding OAuth authentication (PKCE, token refresh, credential store) affecting core CLI auth, login, doctor, whoami, and client creation. High risk of breakage in authentication, credential management, and backward compatibility.
Re-trigger cubic
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Requires human review: Major new feature (OAuth authentication) with 1990 lines changed across core config, client, and auth logic. High risk and impact.
Re-trigger cubic
this will only work with the staging api for now, but that's fine. the cleint id is hard coded, and, for consistency, I think we should ensure this exact client id also used in the production oauth client for the CLI
I've verified this does indeed work with the non-sending apis
Summary by cubic
Adds OAuth authentication to the CLI with a browser-based PKCE flow, secure secret storage, and unified credential handling (API keys or OAuth) across commands. Updates
login,whoami,doctor, and client auth to support tokens, scopes, and better UX without breaking existing API keys.New Features
resend login: adds “Login with Resend” (opens browser), uses a local loopback callback with state checks, ignores non-callback requests, renders a styled success/failure page, times out after 5 minutes, exchanges the code, closes the local server, and saves the grant per profile. Reports where credentials are stored and, on Linux, hints how to enable secure storage. API key flows remain (open API-keys page or manual entry).credentials.json. Plaintext fallback if no secure storage. Overwriting replaces old secrets, we roll back the keychain secret if the metadata write fails, andstorageis set tosecure_storageorfile.exp;/oauth/tokenresponses are schema‑validated; token requests time out after 30s; refresh happens on demand with a 60s leeway before expiry; transient network/timeout errors are labeled and treated as warnings indoctor. UsesRESEND_BASE_URLandOAUTH_CLIENT_ID.resolveAuthenticationreturns an API key or an OAuth grant;createClient/requireClientuse the right token; maps OAuth scopes (full_access,emails:send) to CLI permissions and blocks unknown scopes with a clear error; errors refer to “credentials,” not just keys.whoamiis local‑only (no refresh), labels OAuth as “Token,” masks values, and reports the correct source (flag,env,config, orsecure_storage);doctoris local‑only for presence and validates the credential against the API, shows OAuth details, treats transient refresh failures as warnings, and fails validation only when the server rejects the credential.Migration
credentials.jsonnow stores atypeper profile and supports OAuth grants; with secure storage, only grant metadata is in the file.resend loginand choose “Login with Resend.”Written for commit 1613285. Summary will update on new commits.