Skip to main content

libfw_core/
claims.rs

1//! Bearer-token claims and permissions.
2//!
3//! `libfw` never *issues* tokens; it only parses and validates them. A token
4//! verifier (JWT library, external validation service, …) is expected to
5//! produce a [`TokenClaims`] which is then checked against the requested
6//! path and [`Permission`] by a [`Validator`](crate::auth::Validator).
7
8use serde::{Deserialize, Serialize};
9
10/// Permission dimension of a token.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13pub enum Permission {
14    /// May download / read files.
15    Read,
16    /// May upload / write files.
17    Write,
18}
19
20impl std::fmt::Display for Permission {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        match self {
23            Permission::Read => write!(f, "read"),
24            Permission::Write => write!(f, "write"),
25        }
26    }
27}
28
29/// Parsed, verified token payload used for fine-grained authorization.
30///
31/// All fields except `sub` are optional so that minimal tokens remain
32/// usable (validation is performed by the [`Validator`](crate::auth::Validator)).
33#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
34pub struct TokenClaims {
35    /// Subject — the user or client the token belongs to.
36    pub sub: String,
37    /// Unix timestamp (seconds) at which the token expires.
38    #[serde(default)]
39    pub exp: Option<i64>,
40    /// Permissions granted to this token. Empty means "no permissions".
41    #[serde(default)]
42    pub permissions: Vec<Permission>,
43    /// Path prefixes the token may access. Empty means "no paths allowed".
44    #[serde(default)]
45    pub allowed_paths: Vec<String>,
46}
47
48impl TokenClaims {
49    /// Returns true if `now` (unix seconds) is past `exp`.
50    pub fn is_expired(&self, now: i64) -> bool {
51        self.exp.is_some_and(|exp| now >= exp)
52    }
53
54    /// Returns true if this token grants `perm`.
55    pub fn has_permission(&self, perm: Permission) -> bool {
56        self.permissions.contains(&perm)
57    }
58}