Skip to main content

modo/auth/apikey/
types.rs

1use serde::Serialize;
2
3/// Input for [`super::ApiKeyStore::create`].
4///
5/// All fields except `expires_at` are required. Pass `None` for
6/// `expires_at` to create a non-expiring key.
7pub struct CreateKeyRequest {
8    /// Tenant this key belongs to. Required.
9    pub tenant_id: String,
10    /// Human-readable name for the key.
11    pub name: String,
12    /// Scopes this key grants. Framework stores, app defines meaning.
13    pub scopes: Vec<String>,
14    /// Expiration timestamp (ISO 8601). `None` for lifetime tokens.
15    pub expires_at: Option<String>,
16}
17
18/// One-time result from [`super::ApiKeyStore::create`].
19///
20/// Contains the raw token that must be shown to the user exactly once.
21/// The raw token is not retrievable after creation.
22#[derive(Debug, Clone, Serialize)]
23pub struct ApiKeyCreated {
24    /// ULID primary key.
25    pub id: String,
26    /// Full raw token. Show once, never retrievable after creation.
27    pub raw_token: String,
28    /// Human-readable name.
29    pub name: String,
30    /// Scopes this key grants.
31    pub scopes: Vec<String>,
32    /// Tenant this key belongs to.
33    pub tenant_id: String,
34    /// Expiration timestamp (ISO 8601), or `None` for lifetime.
35    pub expires_at: Option<String>,
36    /// Creation timestamp (ISO 8601).
37    pub created_at: String,
38}
39
40/// Public metadata extracted by [`super::ApiKeyLayer`] middleware.
41///
42/// Available as an axum extractor in handlers (implements
43/// [`FromRequestParts`](axum::extract::FromRequestParts) and
44/// [`OptionalFromRequestParts`](axum::extract::OptionalFromRequestParts)).
45/// Does not contain the key hash or revocation timestamp.
46#[derive(Debug, Clone, Serialize)]
47pub struct ApiKeyMeta {
48    /// ULID primary key.
49    pub id: String,
50    /// Tenant this key belongs to.
51    pub tenant_id: String,
52    /// Human-readable name.
53    pub name: String,
54    /// Scopes this key grants.
55    pub scopes: Vec<String>,
56    /// Expiration timestamp (ISO 8601), or `None` for lifetime.
57    pub expires_at: Option<String>,
58    /// Last time this key was used (ISO 8601).
59    pub last_used_at: Option<String>,
60    /// Creation timestamp (ISO 8601).
61    pub created_at: String,
62}
63
64/// Full stored record used by [`super::ApiKeyBackend`] implementations.
65///
66/// Contains the hash and revocation fields that are stripped when
67/// converting to [`ApiKeyMeta`] via [`into_meta`](Self::into_meta).
68#[derive(Clone)]
69pub struct ApiKeyRecord {
70    /// ULID primary key.
71    pub id: String,
72    /// `hex(sha256(secret))`.
73    pub key_hash: String,
74    /// Tenant this key belongs to.
75    pub tenant_id: String,
76    /// Human-readable name.
77    pub name: String,
78    /// Scopes as `Vec<String>` (serialized as JSON in DB).
79    pub scopes: Vec<String>,
80    /// Expiration timestamp (ISO 8601), or `None` for lifetime.
81    pub expires_at: Option<String>,
82    /// Last use timestamp (ISO 8601).
83    pub last_used_at: Option<String>,
84    /// Creation timestamp (ISO 8601).
85    pub created_at: String,
86    /// Revocation timestamp (ISO 8601), or `None` if active.
87    pub revoked_at: Option<String>,
88}
89
90impl ApiKeyRecord {
91    /// Convert to public metadata, stripping hash and revocation fields.
92    pub fn into_meta(self) -> ApiKeyMeta {
93        ApiKeyMeta {
94            id: self.id,
95            tenant_id: self.tenant_id,
96            name: self.name,
97            scopes: self.scopes,
98            expires_at: self.expires_at,
99            last_used_at: self.last_used_at,
100            created_at: self.created_at,
101        }
102    }
103}