feat: Add OAuth 2.0 Device Flow authentication for OpenHands Cloud backends#381
Conversation
…ckends Implements one-click login for cloud backends using the OAuth 2.0 Device Authorization Grant (RFC 8628). When adding a cloud backend with a known OpenHands Cloud host (*.all-hands.dev, *.openhands.dev), users can click 'Login with OpenHands' to authenticate via browser instead of manually copying their API key. Changes: - Add device-flow-client.ts with startDeviceFlow() and pollForToken() - Add useDeviceFlow React hook for managing auth state in components - Add DeviceFlowAuth component with auth UI states (idle, starting, awaiting_authorization, success, error) - Update BackendForm to show device flow auth for cloud backends - Add i18n translations for all device flow UI strings Closes #379
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- Remove restriction to only known OpenHands Cloud hosts - device flow is now available for all cloud backends (including self-hosted) - Add clear 'OR' divider between login button and manual API key entry - Add link to API key documentation for manual key generation - Add new i18n keys: LOGIN_OR, KEY_DOCS_HINT, KEY_DOCS_LINK
- Login button, OR divider, and manual API key input are now always visible when cloud backend type is selected - Login button is disabled until a valid host URL is entered - Improves UX by showing the full auth options upfront
The kind inference was incorrectly downgrading from 'cloud' to 'local' when typing a host URL that didn't match known OpenHands Cloud patterns. Now the inference only upgrades to 'cloud' when a known pattern is detected, but never downgrades - allowing users to type any custom cloud host URL while keeping the login button visible.
For known OpenHands Cloud hosts (*.all-hands.dev, *.openhands.dev), device flow requests are now routed through the local agent-server's cloud-proxy endpoint. This avoids CORS errors when the browser tries to make direct cross-origin requests to the cloud backend. Self-hosted instances still use direct requests, assuming they have CORS properly configured.
all-hands-bot
left a comment
There was a problem hiding this comment.
OAuth 2.0 Device Flow implementation has RFC 8628 compliance issues, security concerns, and UX problems that need addressing.
1. Device flow now always uses proxy for all hosts (not just known cloud
hosts). This avoids CORS issues for any custom backend that supports
device flow.
2. Fix regression where typing a local address (e.g., 127.0.0.1) would
not switch from cloud to local type. The kind inference now:
- Auto-infers kind from host in add mode (initial behavior)
- Only prevents downgrade when user explicitly clicked the cloud
radio button (not when cloud is just the default)
- Tracks explicit user selection separately from initial default
…liance Security fixes: - Fix isOpenHandsCloudHost() to use URL hostname extraction instead of substring matching, preventing attacks like all-hands.dev.evil.com - Add URL validation in handleStartAuth to check for credential injection - Sanitize error messages to avoid exposing server error details RFC 8628 compliance: - Add required grant_type parameter to token requests - Make verification_uri_complete optional per RFC Section 3.2 - Build verification_uri_complete if not provided by server Robustness improvements: - Validate polling interval to at least 1 second - Cap slow_down interval to MAX_INTERVAL_MS to prevent DoS - Open popup on user click to avoid popup blockers Accessibility: - Add role='status' and aria-live='polite' to status containers - Add role='alert' to error container
|
Addressed PR review feedback in commit 5d1cab8: Security fixes:
RFC 8628 compliance:
Robustness improvements:
Accessibility:
Not addressed (minor/suggestions):
|
all-hands-bot
left a comment
There was a problem hiding this comment.
OAuth 2.0 Device Flow implementation is well-structured with good security practices and comprehensive tests. Found one important issue with abort signal handling that affects cancellation UX.
Address review feedback: the abort signal is now properly passed through makeProxiedRequest to the underlying fetch call, allowing in-flight proxied requests to be cancelled immediately when the user cancels. Co-authored-by: openhands <openhands@all-hands.dev>
all-hands-bot
left a comment
There was a problem hiding this comment.
OAuth 2.0 Device Flow implementation has 3 critical RFC compliance issues and multiple security/reliability concerns that must be addressed before merging. The overall architecture is sound, but implementation details need fixes.
Security fixes: - Add URL validation to prevent XSS via javascript: URLs - Validate verification URLs have https: protocol before use in popup and links - Add type validation for slow_down interval to prevent NaN tight loops RFC 8628 compliance: - Fix slow_down to increment by 5 seconds per Section 3.5 (not double) - Validate interval is number, finite, and positive before using server value Robustness: - Network errors now continue polling instead of failing immediately - Wrap sleep in try-catch for consistent abort handling - Add cleanup effect to close popup on unmount Code cleanup: - Remove dead userSelectedCloud state (was unreachable) - Add defensive programming comment for cancellation check - Fix onSuccess effect to include deviceFlow.reset in deps Tests: - Add DoS protection test (caps interval at 30s) - Add type confusion test (rejects non-numeric interval) - Add RFC 8628 +5s increment test - Add network error retry test - Add unmount cleanup test Co-authored-by: openhands <openhands@all-hands.dev>
|
PR Artifacts Cleaned Up The |
all-hands-bot
left a comment
There was a problem hiding this comment.
LGTM! 🚀
Solid OAuth 2.0 Device Flow implementation. All previous review feedback has been addressed:
✅ RFC 8628 compliance (slow_down +5s increment, grant_type parameter)
✅ Security hardening (URL validation, XSS prevention, abort handling)
✅ Network resilience (continues polling on transient errors)
✅ Type safety (interval validation, DoS protection)
✅ Comprehensive test coverage
✅ Proper cleanup on unmount
[RISK ASSESSMENT]
- [Overall PR]
⚠️ Risk Assessment: 🟢 LOW
Frontend authentication feature with no impact on agent behavior or evaluation performance. Well-tested, follows security best practices, and is scoped to adding a new optional auth method without modifying existing flows.
VERDICT:
✅ Worth merging: Clean implementation with thorough test coverage and proper error handling.
KEY INSIGHT:
The proxied request pattern (routing through local agent-server's cloud-proxy) elegantly solves CORS issues while maintaining security through session-based auth.
The 'noopener' option causes window.open() to return null, which means we lose the reference to the popup and can't update its location when the verification URL becomes available. This was causing a blank page to appear instead of the device flow auth page. Removed 'noopener' from the initial popup open call so we can maintain the reference and update popupRef.current.location.href when the verification URL arrives from the device flow. Co-authored-by: openhands <openhands@all-hands.dev>
Screen.Recording.2026-05-12.at.12.25.53.PM.mov
Fixes APP-1716
Why
Currently, adding an OpenHands Cloud backend requires users to manually navigate to the dashboard, find/generate their API key, and copy it back to the form. This creates unnecessary friction when the cloud service already supports device authorization flow (RFC 8628).
Summary
device-flow-client.tswith OAuth 2.0 Device Flow implementation (startDeviceFlow,pollForToken)useDeviceFlowReact hook for managing auth state transitions (idle → starting → awaiting_authorization → success/error)DeviceFlowAuthcomponent with "Login with OpenHands" button, loading states, browser auto-open, and error handlingBackendFormfor all cloud backends (including self-hosted instances that support device OAuth)Issue Number
Closes #379
How to Test
npm installandnpm run dev/oauth/device/authorizeand/oauth/device/tokenendpoints)Unit tests can be run with:
npm test -- __tests__/api/device-flow-client.test.ts __tests__/hooks/use-device-flow.test.tsVideo/Screenshots
N/A - Feature requires backend OAuth endpoints to fully test. Unit tests cover the client logic.
Type
Notes
/oauth/device/authorizeand/oauth/device/token) must be supported by the cloud backendThis PR was created by an AI agent (OpenHands) on behalf of the user.