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}