MCPcopy Create free account
hub / github.com/OpenHands/OpenHands / DeviceCode

Class DeviceCode

enterprise/storage/device_code.py:20–131  ·  view source on GitHub ↗

Device code for OAuth 2.0 Device Flow. This stores the device codes issued during the device authorization flow, along with their status and associated user information once authorized.

Source from the content-addressed store, hash-verified

18
19
20class DeviceCode(Base):
21 """Device code for OAuth 2.0 Device Flow.
22
23 This stores the device codes issued during the device authorization flow,
24 along with their status and associated user information once authorized.
25 """
26
27 __tablename__ = 'device_codes'
28
29 id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
30 device_code: Mapped[str] = mapped_column(
31 String(128), unique=True, nullable=False, index=True
32 )
33 user_code: Mapped[str] = mapped_column(
34 String(16), unique=True, nullable=False, index=True
35 )
36 status: Mapped[str] = mapped_column(
37 String(32), nullable=False, default=DeviceCodeStatus.PENDING.value
38 )
39
40 # Keycloak user ID who authorized the device (set during verification)
41 keycloak_user_id: Mapped[str | None] = mapped_column(String(255), nullable=True)
42
43 # Timestamps
44 expires_at: Mapped[datetime] = mapped_column(
45 DateTime(timezone=True), nullable=False
46 )
47 authorized_at: Mapped[datetime | None] = mapped_column(
48 DateTime(timezone=True), nullable=True
49 )
50
51 # Rate limiting fields for RFC 8628 section 3.5 compliance
52 last_poll_time: Mapped[datetime | None] = mapped_column(
53 DateTime(timezone=True), nullable=True
54 )
55 current_interval: Mapped[int] = mapped_column(nullable=False, default=5)
56
57 def __repr__(self) -> str:
58 return f"<DeviceCode(user_code='{self.user_code}', status='{self.status}')>"
59
60 def is_expired(self) -> bool:
61 """Check if the device code has expired."""
62 now = datetime.now(timezone.utc)
63 # Handle timezone-naive datetime from database by assuming it's UTC
64 expires_at = self.expires_at
65 if expires_at.tzinfo is None:
66 expires_at = expires_at.replace(tzinfo=timezone.utc)
67 return now > expires_at
68
69 def is_pending(self) -> bool:
70 """Check if the device code is still pending authorization."""
71 return self.status == DeviceCodeStatus.PENDING.value and not self.is_expired()
72
73 def is_authorized(self) -> bool:
74 """Check if the device code has been authorized."""
75 return self.status == DeviceCodeStatus.AUTHORIZED.value
76
77 def authorize(self, user_id: str) -> None:

Calls

no outgoing calls