Implementation:OpenHands OpenHands DeviceCodeStore
| Knowledge Sources | |
|---|---|
| Domains | Authentication, OAuth, RFC_8628, Storage |
| Last Updated | 2026-02-11 21:00 GMT |
Overview
Concrete tool for managing the full device code lifecycle including code generation, creation, authorization, and denial, provided by the OpenHands enterprise storage layer.
Description
The DeviceCodeStore class provides the data access and business logic layer for the RFC 8628 Device Authorization Grant flow. It sits above the DeviceCode ORM model and encapsulates all database interactions and code generation logic.
The generate_user_code method creates a short, human-friendly alphanumeric code that is displayed to the user during the device authorization flow. The code is formatted for easy manual entry (e.g., ABCD-1234) and is guaranteed to be unique within the set of active (non-expired) device codes.
The generate_device_code method creates a longer, cryptographically random opaque string used by the client application for polling the token endpoint. This code is not shown to the user and serves as the primary lookup key for the device authorization session.
The create_device_code method orchestrates the creation of a new device authorization session. It calls generate_user_code and generate_device_code to produce the two codes, creates a new DeviceCode ORM record with PENDING status and a configured expiration time, persists it to the database, and returns both codes along with the verification URI and polling interval.
The authorize_device_code method is called when a user approves the authorization on the web-based verification page. It looks up the device code by user code, validates that it is still pending and not expired, and delegates to the DeviceCode.authorize method to transition it to the AUTHORIZED state with the user's identity.
The deny_device_code method is called when a user explicitly rejects the authorization request. It looks up the device code by user code and delegates to the DeviceCode.deny method to transition it to the DENIED state.
Usage
Use DeviceCodeStore in the device authorization API endpoints. The device authorization endpoint calls create_device_code to start the flow. The verification page endpoint calls authorize_device_code or deny_device_code based on user action. The token polling endpoint queries the device code status directly via the DeviceCode model.
Code Reference
Source Location
- Repository: OpenHands
- File: enterprise/storage/device_code_store.py
- Lines: 1-167
Signature
class DeviceCodeStore:
def generate_user_code(self) -> str:
...
def generate_device_code(self) -> str:
...
async def create_device_code(
self,
client_id: str,
scope: str | None = None,
) -> dict:
...
async def authorize_device_code(
self,
user_code: str,
user_id: str,
) -> bool:
...
async def deny_device_code(
self,
user_code: str,
) -> bool:
...
Import
from enterprise.storage.device_code_store import DeviceCodeStore
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| client_id | str |
Yes | The OAuth client ID requesting device authorization (for create_device_code) |
| scope | str or None |
No | Requested OAuth scopes; None for default scopes (for create_device_code)
|
| user_code | str |
Yes | The short user-facing code entered on the verification page (for authorize_device_code and deny_device_code) |
| user_id | str |
Yes | The ID of the user granting authorization (for authorize_device_code) |
Outputs
create_device_code:
| Name | Type | Description |
|---|---|---|
| device_code | str |
The opaque device code for the client to use when polling the token endpoint |
| user_code | str |
The short code to display to the user for entry on the verification page |
| verification_uri | str |
The URL where the user should navigate to enter the user code |
| expires_in | int |
Number of seconds until the device code expires |
| interval | int |
Recommended polling interval in seconds |
authorize_device_code / deny_device_code:
| Name | Type | Description |
|---|---|---|
| success | bool |
True if the operation succeeded; False if the user code was not found, already used, or expired
|
Usage Examples
from enterprise.storage.device_code_store import DeviceCodeStore
store = DeviceCodeStore(db_session=session)
# Step 1: Client requests device authorization
device_auth = await store.create_device_code(
client_id="openhands-cli",
scope="read write",
)
# Returns: {
# "device_code": "dc-a1b2c3d4e5f6...",
# "user_code": "ABCD-1234",
# "verification_uri": "https://app.openhands.ai/device",
# "expires_in": 900,
# "interval": 5,
# }
# Step 2: User visits verification_uri and enters user_code
# On approval:
success = await store.authorize_device_code(
user_code="ABCD-1234",
user_id="user-123",
)
# On denial:
success = await store.deny_device_code(user_code="ABCD-1234")