huskarl 0.9.1

A modern OAuth2 client library.
Documentation
# Device authorization grant

[`DeviceAuthorizationGrant`](crate::grant::device_authorization::DeviceAuthorizationGrant)
(RFC 8628) is used for devices with limited input capabilities, such as smart
TVs or CLI tools. The device displays a short code and URL for the user to
visit on a separate device, then polls the token endpoint until authorization
completes or the code expires.

## 1. Set up your HTTP client and client authentication

See [Setting up an HTTP client and client
authentication](crate::_docs::guide::setup) for the shared setup the rest of
this page assumes. Device authorization is commonly used by public clients (CLI
tools, smart TVs) that use `NoAuth`; confidential clients pass their
credentials instead.

## 2a. Set up the grant with authorization server metadata

Note: `builder_from_metadata` returns `None` if the server does not advertise
a device authorization endpoint.

```rust
use huskarl::{
    core::{client_auth::NoAuth, server_metadata::AuthorizationServerMetadata},
    grant::device_authorization::DeviceAuthorizationGrant,
};
# async fn setup_grant() -> Result<(), Box<dyn std::error::Error>> {
# let client = huskarl_reqwest::ReqwestClient::builder()
#     .build()
#     .await?;

let metadata = AuthorizationServerMetadata::fetch()
    .http_client(&client)
    .issuer("https://my-issuer")
    .call()
    .await?;

let grant: DeviceAuthorizationGrant =
    DeviceAuthorizationGrant::builder_from_metadata(&metadata)
        .expect("server does not support device authorization")
        .client_id("client_id")
        .http_client(client)
        .client_auth(NoAuth)
        .build();
# Ok(())
# }
```

## 2b. Alternative: Set up the grant without metadata

```rust
use huskarl::{
    core::client_auth::NoAuth, grant::device_authorization::DeviceAuthorizationGrant,
};
# async fn setup_grant() -> Result<(), Box<dyn std::error::Error>> {
# let client = huskarl_reqwest::ReqwestClient::builder()
#     .build()
#     .await?;

let grant: DeviceAuthorizationGrant = DeviceAuthorizationGrant::builder()
    .device_authorization_endpoint("https://my-server/device_authorization".parse()?)
    .token_endpoint("https://my-server/token".parse()?)
    .client_id("client_id")
    .http_client(client)
    .client_auth(NoAuth)
    .build();
# Ok(())
# }
```

## 3. Start the device authorization flow

```rust
use huskarl::{
    core::client_auth::NoAuth,
    grant::device_authorization::{DeviceAuthorizationGrant, StartInput},
};
# async fn start_flow(
#     grant: &DeviceAuthorizationGrant,
# ) -> Result<(), Box<dyn std::error::Error>> {

let start_output = grant.start(StartInput::scope(bon::vec!["read", "write"])).await?;

// Display to the user — they visit the URL and enter the code on another device.
println!("Visit: {}", start_output.verification_uri);
println!("Code: {}", start_output.user_code);
# Ok(())
# }
```

## 4. Poll for completion

```rust
use huskarl::{
    core::client_auth::NoAuth,
    grant::device_authorization::{DeviceAuthorizationGrant, StartOutput},
    token::AccessToken,
};
# async fn poll_flow(
#     grant: &DeviceAuthorizationGrant,
#     start_output: StartOutput,
# ) -> Result<(), Box<dyn std::error::Error>> {

let mut pending_state = start_output.pending_state;
let response = grant.poll_to_completion(&mut pending_state, None).await?;
let token: &AccessToken = response.access_token();
# Ok(())
# }
```