Verify if device authorization credentials are valid. Args: client_id: The OAuth2 client ID. device_code: The device code. Returns: The authenticated account details. Raises: OAuthError: If the device authorization credentials are invalid.
(client_id: UUID, device_code: str)
| 541 | |
| 542 | |
| 543 | def authenticate_device(client_id: UUID, device_code: str) -> AuthContext: |
| 544 | """Verify if device authorization credentials are valid. |
| 545 | |
| 546 | Args: |
| 547 | client_id: The OAuth2 client ID. |
| 548 | device_code: The device code. |
| 549 | |
| 550 | Returns: |
| 551 | The authenticated account details. |
| 552 | |
| 553 | Raises: |
| 554 | OAuthError: If the device authorization credentials are invalid. |
| 555 | """ |
| 556 | # This is the part of the OAuth2 device code grant flow where a client |
| 557 | # device is continuously polling the server to check if the user has |
| 558 | # authorized a device. The following needs to happen to successfully |
| 559 | # authenticate the device and return a valid access token: |
| 560 | # |
| 561 | # 1. the device code and client ID must match a device in the DB |
| 562 | # 2. the device must be in the VERIFIED state, meaning that the user |
| 563 | # has successfully authorized the device via the user code but the |
| 564 | # device client hasn't yet fetched the associated API access token yet. |
| 565 | # 3. the device must not be expired |
| 566 | |
| 567 | config = server_config() |
| 568 | store = zen_store() |
| 569 | |
| 570 | try: |
| 571 | device_model = store.get_internal_authorized_device( |
| 572 | client_id=client_id |
| 573 | ) |
| 574 | except KeyError: |
| 575 | error = ( |
| 576 | f"Authentication error: error retrieving device with client ID " |
| 577 | f"{client_id}" |
| 578 | ) |
| 579 | logger.error(error) |
| 580 | raise OAuthError( |
| 581 | error="invalid_client", |
| 582 | error_description=error, |
| 583 | ) |
| 584 | |
| 585 | if device_model.status != OAuthDeviceStatus.VERIFIED: |
| 586 | error = ( |
| 587 | f"Authentication error: device with client ID {client_id} is " |
| 588 | f"{device_model.status.value}." |
| 589 | ) |
| 590 | logger.error(error) |
| 591 | if device_model.status == OAuthDeviceStatus.PENDING: |
| 592 | oauth_error = "authorization_pending" |
| 593 | elif device_model.status == OAuthDeviceStatus.LOCKED: |
| 594 | oauth_error = "access_denied" |
| 595 | else: |
| 596 | oauth_error = "expired_token" |
| 597 | raise OAuthError( |
| 598 | error=oauth_error, |
| 599 | error_description=error, |
| 600 | ) |
no test coverage detected