Skip to main content

alibi_core/store/contracts/
device.rs

1use crate::{AuthError, AuthResult, CreateDeviceCode, DeviceCode, UpdateDeviceCode};
2use async_trait::async_trait;
3/// Persistence for OAuth device authorization codes.
4#[async_trait]
5pub trait DeviceCodeStore: Send + Sync {
6    /// Persist a newly-issued device code.
7    async fn create_device_code(&self, input: CreateDeviceCode) -> AuthResult<DeviceCode>;
8    /// Atomically persist a grant with application-owned fields.
9    async fn create_device_code_with_fields(
10        &self,
11        input: CreateDeviceCode,
12        fields: serde_json::Map<String, serde_json::Value>,
13    ) -> AuthResult<DeviceCode> {
14        if fields.is_empty() {
15            self.create_device_code(input).await
16        } else {
17            Err(AuthError::not_implemented(
18                "Application device-grant fields are unsupported by this store",
19            ))
20        }
21    }
22    /// Read the durable application fields belonging to a device record.
23    async fn device_code_fields(
24        &self,
25        _id: &str,
26    ) -> AuthResult<serde_json::Map<String, serde_json::Value>> {
27        Ok(serde_json::Map::new())
28    }
29    /// Consume exactly one approved grant matching all application ownership predicates.
30    async fn consume_device_code(
31        &self,
32        _id: &str,
33        _status: &str,
34        _ownership: &serde_json::Map<String, serde_json::Value>,
35    ) -> AuthResult<Option<DeviceCode>> {
36        Err(AuthError::not_implemented(
37            "Atomic application device-grant redemption is unsupported by this store",
38        ))
39    }
40    /// Fetch a device code by its opaque device-facing token.
41    async fn get_device_code_by_device_code(
42        &self,
43        device_code: &str,
44    ) -> AuthResult<Option<DeviceCode>>;
45    /// Fetch a device code by its user-facing verification code.
46    async fn get_device_code_by_user_code(&self, user_code: &str)
47    -> AuthResult<Option<DeviceCode>>;
48    /// Update mutable device-code state such as approval status or poll time.
49    async fn update_device_code(
50        &self,
51        id: &str,
52        update: UpdateDeviceCode,
53    ) -> AuthResult<DeviceCode>;
54    /// Update a device code only when it still has the expected status.
55    ///
56    /// Returns `true` when the compare-and-swap succeeds, or `false` when the
57    /// row was already moved to a different state.
58    async fn update_device_code_if_status(
59        &self,
60        id: &str,
61        current_status: &str,
62        update: UpdateDeviceCode,
63    ) -> AuthResult<bool>;
64    /// Bind a still-pending, still-unclaimed device code to a user.
65    ///
66    /// Returns `true` when this call performed the claim, and `false` when the
67    /// row was already claimed or no longer pending. The status and
68    /// unclaimed checks are part of the write so two concurrent verifiers
69    /// cannot both claim the same code.
70    async fn claim_device_code(&self, id: &str, user_id: &str) -> AuthResult<bool>;
71    /// Delete a device code record.
72    async fn delete_device_code(&self, id: &str) -> AuthResult<()>;
73    /// Delete a device code only when it still has the expected status.
74    ///
75    /// Returns `true` when a matching row was deleted and `false` otherwise.
76    async fn delete_device_code_if_status(&self, id: &str, status: &str) -> AuthResult<bool>;
77}