OpenHands / OpenHands/enterprise
OAuth Email Verification Trap: Users Can Change to Unverified Emails
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 4
- Forks
- 2
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 101
Description
OAuth Email Verification Trap: Users Can Change to Unverified Emails
Problem Description
When users authenticate via OAuth (GitHub/Google), their email is initially verified by the OAuth provider. However, the system allows users to change their email address to any arbitrary email in the Enterprise Server UI. When they do this:
- The new email is set as their account email
email_verifiedis set tofalse- A verification email is sent to the new address
- The user interface provides no way to resend this verification email
If the user misses the verification email (spam folder, typo in address, etc.), they become stuck in a state where:
- Their account shows
email_verified: false - They cannot verify their email because there's no resend button in the UI
- Depending on the client (Agent Canvas), they may lose access to features
This creates a permanent trap - once a user changes their email and misses the verification, they have no self-service recovery path.
Additional Complexity: GitHub Multiple Email Addresses
GitHub allows users to have multiple email addresses, each with independent verification status. Users can:
- Add multiple emails to their GitHub account
- Set any email as "primary"
- Change which email is primary at any time
The primary email is what GitHub returns during OAuth, along with its verification status. This creates scenarios where:
- A user's GitHub primary email is unverified → OAuth returns
email_verified: false - A user changes their GitHub primary email → their OpenHands email verification status changes on next login
- A user has verified emails in GitHub that aren't being used in OpenHands
Currently, OpenHands doesn't capture or expose the user's other GitHub emails, limiting their flexibility.
Current Behavior
OAuth Login Flow:
1. User authenticates with GitHub
2. GitHub returns user info including:
- email: user's primary email in GitHub
- email_verified: verification status of that primary email
3. OpenHands stores this email and verification status
4. User has access to the system
Email Change Flow (via Enterprise Server UI):
1. User navigates to settings and changes email
2. Backend sets email_verified = false in both:
- Keycloak (emailVerified: false)
- OpenHands database (email_verified: false)
3. Verification email is sent to new address
4. User must click verification link to restore email_verified = true
The Problem:
- No UI exists to resend the verification email
- User cannot recover if they miss the initial email
- Admin intervention may be required to fix stuck accounts
Proposed Solution (High Level)
Option 1: Capture All OAuth Provider Emails
When a user authenticates via OAuth:
- Fetch all their emails from the OAuth provider (e.g., GitHub's
/user/emailsAPI) - Store all verified emails from the provider
- Let users switch between their verified OAuth emails
- Only allow switching to emails that are already verified by the provider
- Keep manual email changes for users who want to use non-GitHub emails (with verification)
Benefits:
- Leverages OAuth provider's email verification
- Gives users flexibility to choose which GitHub email to use
- Prevents the unverified email trap for OAuth users
- Stays in sync with GitHub when users add/remove/verify emails there
Option 2: Add Email Verification Recovery UI
At minimum, add UI elements to:
- Show current email verification status clearly
- Provide a "Resend Verification Email" button
- Allow users to revert to a previously verified email
Benefits:
- Simpler implementation
- Provides escape hatch for trapped users
- Works for both OAuth and password authentication users
Recommended: Combination Approach
- Implement Option 1 (capture OAuth emails) for OAuth users
- Add resend verification UI for manual email changes
- This provides both prevention and recovery
Impact for Agent Canvas
Agent Canvas currently disables navigation links when email_verified === false. This is more strict than the Enterprise Server backend (which allows all API operations regardless of email verification status).
The combination of:
- No email verification recovery UI in either Enterprise Server or Agent Canvas
- Agent Canvas blocking navigation for unverified emails
- Users being able to change to unverified emails
Creates a situation where OAuth users can accidentally lock themselves out of Agent Canvas features by changing their email address.
Related Code Locations
- Email change endpoint:
/workspace/OpenHands/enterprise/server/routes/email.py - OAuth login flow:
/workspace/OpenHands/enterprise/server/routes/auth.py(around line 400) - User settings model:
/workspace/OpenHands/enterprise/storage/user_settings.py - Token manager (fetches OAuth user info):
/workspace/OpenHands/enterprise/server/auth/token_manager.py
User Impact
Current State:
- Users who change their email and miss verification are permanently stuck
- No self-service recovery mechanism exists
- Requires manual database/Keycloak intervention to fix
Desired State:
- Users can choose from their verified OAuth emails without re-verification
- If users add custom emails, they have clear visibility and recovery options
- No permanent trap states exist in the system
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with enterprise/server/routes/email.py and enterprise/server/routes/auth.py around the OAuth flow, then inspect storage/user_settings.py and server/auth/token_manager.py. Clarify which proposed recovery approach is selected; done should prevent users from being permanently stuck and provide a self-service path for unverified email accounts.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- authentication
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100