Skip to main content

alibi_api/plugins/jwt/
callbacks.rs

1use super::*;
2#[derive(Clone, Debug, Serialize)]
3pub struct JwtSession {
4    pub user: UserView,
5    pub session: SessionView,
6    /// The nested deferred-session response field. Direct completed-response
7    /// hooks observe the original stored snapshot and omit this field.
8    #[serde(rename = "needsRefresh", skip_serializing_if = "Option::is_none")]
9    pub needs_refresh: Option<bool>,
10    /// The verified cache clock seen by a direct get-session response hook.
11    #[serde(rename = "updatedAt", skip_serializing_if = "Option::is_none")]
12    pub updated_at: Option<f64>,
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub version: Option<String>,
15}
16
17#[async_trait]
18pub trait DefineJwtPayload: Send + Sync {
19    async fn define_payload(&self, session: &JwtSession) -> AuthResult<Map<String, Value>>;
20}
21
22#[async_trait]
23pub trait DefineJwtSubject: Send + Sync {
24    async fn subject(&self, session: &JwtSession) -> AuthResult<Option<String>>;
25}
26
27#[async_trait]
28pub trait JwtKeyring: Send + Sync {
29    async fn keys(&self, context: &JwtKeyringContext<'_>) -> AuthResult<Vec<Jwk>>;
30    async fn create_key(&self, key: CreateJwk, context: &JwtKeyringContext<'_>) -> AuthResult<Jwk>;
31}
32
33/// The real endpoint context supplied to application key storage. Server-only
34/// operations have a virtual endpoint path and may have no HTTP request.
35#[derive(Clone, Copy, Debug)]
36pub struct JwtKeyringContext<'a> {
37    pub path: &'a str,
38    pub request: Option<&'a AuthRequest>,
39    pub endpoint: Option<&'a alibi_core::endpoint::EndpointCall>,
40}
41
42/// One property in an application-owned remote signing payload.
43#[derive(Clone, Copy, Debug, PartialEq)]
44pub enum RemoteJwtClaim<'a> {
45    Absent,
46    Undefined,
47    Value(&'a alibi_core::utils::json::JsValue),
48}
49
50/// Claims passed to a configured remote signer, before managed JOSE validation.
51///
52/// `raw_claims` preserves IEEE754 numbers and all supplied JSON values. The
53/// added `iat` and `nbf` properties can be own properties with an undefined
54/// value; use `claim` to distinguish these from absent or null properties.
55/// Undefined properties are omitted from `raw_claims`, matching JSON.stringify.
56#[derive(Clone, Debug)]
57pub struct RemoteJwtPayload {
58    pub(in crate::plugins::jwt) raw_claims: alibi_core::utils::json::JsValue,
59    pub(in crate::plugins::jwt) own_keys: Vec<String>,
60    pub(in crate::plugins::jwt) undefined_claims: Vec<String>,
61}
62
63impl RemoteJwtPayload {
64    #[must_use]
65    pub const fn raw_claims(&self) -> &alibi_core::utils::json::JsValue {
66        &self.raw_claims
67    }
68
69    /// Property names in the order observed by the application signer.
70    #[must_use]
71    pub fn own_keys(&self) -> &[String] {
72        &self.own_keys
73    }
74
75    #[must_use]
76    pub fn claim(&self, name: &str) -> RemoteJwtClaim<'_> {
77        if self.undefined_claims.iter().any(|key| key == name) {
78            RemoteJwtClaim::Undefined
79        } else if let Some(value) = self.raw_claims.get(name) {
80            RemoteJwtClaim::Value(value)
81        } else {
82            RemoteJwtClaim::Absent
83        }
84    }
85}
86
87/// An application-owned signer controls serialization, claim validation and
88/// its returned token. Managed local signing rules are not applied beforehand.
89#[async_trait]
90pub trait SignRemoteJwt: Send + Sync {
91    async fn sign(
92        &self,
93        payload: &RemoteJwtPayload,
94        options: &JwtSignOptions,
95    ) -> AuthResult<String>;
96}