Skip to main content

pubky_common/auth/
grant_session_responses.rs

1//! Grant-based session response types.
2//!
3//! These types represent the response from `POST /auth/grant/session` and grant management
4//! endpoints when using grant-based authentication. Shared between homeserver
5//! (serializes) and SDK (deserializes).
6
7use serde::{Deserialize, Serialize};
8
9use crate::{
10    auth::jws::{ClientId, GrantId},
11    capabilities::Capability,
12    crypto::PublicKey,
13};
14
15/// Response from `POST /session` for grant-based authentication.
16///
17/// # JSON representation
18/// ```json
19/// {
20///   "token": "base64url-encoded-random-bearer",
21///   "session": { ... }
22/// }
23/// ```
24#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
25pub struct GrantSessionResponse {
26    /// The opaque bearer token.
27    pub token: String,
28    /// Session metadata.
29    pub session: GrantSessionInfo,
30}
31
32/// Summary of an active grant returned by `GET /auth/grant/sessions`.
33///
34/// Used by Ring's session management UI to show all authorized apps for a user.
35#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
36pub struct GrantInfo {
37    /// Grant identifier (revocation target).
38    pub grant_id: GrantId,
39    /// Application identifier (domain string).
40    pub client_id: String,
41    /// Capabilities this grant authorizes, formatted as a comma-separated string.
42    pub capabilities: String,
43    /// Issued-at timestamp (Unix seconds).
44    pub issued_at: u64,
45    /// Expiry timestamp (Unix seconds).
46    pub expires_at: u64,
47}
48
49/// Session metadata returned alongside the bearer.
50///
51/// Timestamps are Unix seconds (not microseconds).
52#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
53pub struct GrantSessionInfo {
54    /// Homeserver that issued this session.
55    pub homeserver: PublicKey,
56    /// User this session belongs to.
57    pub pubky: PublicKey,
58    /// Application identifier.
59    pub client_id: ClientId,
60    /// Authorized capabilities for this session.
61    pub capabilities: Vec<Capability>,
62    /// Grant ID this session was minted from.
63    pub grant_id: GrantId,
64    /// When the bearer token expires (Unix seconds).
65    pub token_expires_at: u64,
66    /// When the underlying Grant expires (Unix seconds).
67    pub grant_expires_at: u64,
68    /// When this session was created (Unix seconds).
69    pub created_at: u64,
70}
71
72#[cfg(test)]
73mod tests {
74    use crate::crypto::Keypair;
75
76    use super::*;
77
78    #[test]
79    fn grant_session_response_serde_roundtrip() {
80        let hs_kp = Keypair::random();
81        let user_kp = Keypair::random();
82
83        let response = GrantSessionResponse {
84            token: "eyJhbGciOiJFZERTQSIs.payload.signature".to_string(),
85            session: GrantSessionInfo {
86                homeserver: hs_kp.public_key(),
87                pubky: user_kp.public_key(),
88                client_id: ClientId::new("franky.pubky.app").unwrap(),
89                capabilities: vec![Capability::root()],
90                grant_id: GrantId::generate(),
91                token_expires_at: 1700003600,
92                grant_expires_at: 1763136000,
93                created_at: 1700000000,
94            },
95        };
96
97        let json = serde_json::to_string(&response).unwrap();
98        let parsed: GrantSessionResponse = serde_json::from_str(&json).unwrap();
99        assert_eq!(response, parsed);
100    }
101}