//! DTOs for OAuth 2.0 Device Authorization Grant (RFC 8628). use serde::{Deserialize, Serialize}; // ============================================================================ // Request DTOs // ============================================================================ /// POST /api/auth/device/authorize — request body #[derive(Debug, Deserialize)] pub struct DeviceAuthorizeRequestDto { /// Human-readable name of the client (e.g. "rclone", "DAVx⁵") #[serde(default = "default_client_name")] pub client_name: String, /// Comma-separated scopes (e.g. "webdav,caldav,carddav") #[serde(default = "default_scopes")] pub scope: String, } fn default_client_name() -> String { "Unknown Client".to_string() } fn default_scopes() -> String { "webdav,caldav,carddav".to_string() } /// POST /api/auth/device/verify — user submits the code from the browser #[derive(Debug, Deserialize)] pub struct DeviceVerifyRequestDto { /// The user_code displayed on the client device pub user_code: String, /// Whether the user approves ("approve") or denies ("deny") pub action: String, } /// POST /api/auth/device/token — client polls for tokens #[derive(Debug, Deserialize)] pub struct DeviceTokenRequestDto { /// The device_code received from the initial authorize call pub device_code: String, /// Must be "urn:ietf:params:oauth:grant-type:device_code" #[serde(default)] pub grant_type: String, } // ============================================================================ // Response DTOs // ============================================================================ /// Response to POST /api/auth/device/authorize (RFC 8628 §3.2) #[derive(Debug, Serialize)] pub struct DeviceAuthorizeResponseDto { /// The device verification code pub device_code: String, /// The end-user verification code (short, human-readable) pub user_code: String, /// The end-user verification URI pub verification_uri: String, /// Optional: verification URI with user_code pre-filled #[serde(skip_serializing_if = "Option::is_none")] pub verification_uri_complete: Option, /// Lifetime in seconds of the device_code and user_code pub expires_in: i64, /// Minimum polling interval in seconds pub interval: i32, } /// Response to POST /api/auth/device/token when authorization is still pending #[derive(Debug, Serialize)] pub struct DeviceTokenPendingDto { pub error: String, #[serde(skip_serializing_if = "Option::is_none")] pub error_description: Option, } /// Response to POST /api/auth/device/token when authorization is complete #[derive(Debug, Serialize)] pub struct DeviceTokenSuccessDto { pub access_token: String, pub token_type: String, pub refresh_token: String, pub expires_in: i64, pub scope: String, } /// GET /api/auth/device/verify — info about the pending device code #[derive(Debug, Serialize)] pub struct DeviceVerifyInfoDto { /// The client name requesting access pub client_name: String, /// Scopes being requested pub scopes: String, /// Whether the user_code is valid and pending pub valid: bool, }