fire_auth_token/
structs.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::sync::Arc;
use time::OffsetDateTime;
use tokio::sync::RwLock;

/// Update FirebaseAuth to use Arc and RwLock for shared state
#[derive(Debug, Clone)]
pub struct SharedState {
    pub keys: PublicKeysResponse,
    pub expiry: OffsetDateTime,
}


/// Represents the header of a Firebase ID token as specified in the documentation
#[derive(Debug, Deserialize, Serialize)]
pub struct FirebaseTokenHeader {
    /// Algorithm used for the token signature (must be "RS256")
    pub alg: String,
    /// Key ID corresponding to the public key used for signature verification
    pub kid: String,
}

/// Represents the payload of a Firebase ID token as specified in the documentation
#[derive(Debug, Deserialize, Serialize)]
pub struct FirebaseTokenPayload {
    /// Expiration time (in seconds since UNIX epoch)
    pub exp: i64,
    /// Issued at time (in seconds since UNIX epoch)
    pub iat: i64,
    /// Audience (must be your Firebase project ID)
    pub aud: String,
    /// Issuer (must be "https://securetoken.google.com/<projectId>")
    pub iss: String,
    /// Subject (must be the uid of the user or device)
    pub sub: String,
    /// Authentication time (must be in the past)
    pub auth_time: i64,
}

/// Response from Google's public key endpoint
#[derive(Debug, Deserialize, Clone)]
pub struct PublicKeysResponse {
    /// Map of key IDs to their corresponding public key certificates
    pub keys: HashMap<String, String>,
}

/// Configuration for Firebase Authentication
#[derive(Debug, Clone)]
pub struct FirebaseAuthConfig {
    /// Firebase project ID
    pub project_id: String,
    /// Base URL for public key metadata
    pub public_keys_url: String,
}

/// Represents a verified Firebase user
#[derive(Debug, Clone)]
pub struct FirebaseAuthUser {
    /// User's unique ID (from sub claim)
    pub uid: String,
    /// Time when the token was issued
    pub issued_at: OffsetDateTime,
    /// Time when the token expires
    pub expires_at: OffsetDateTime,
    /// Time when the user was authenticated
    pub auth_time: OffsetDateTime,
}

/// Main struct for Firebase Authentication operations
#[derive(Debug)]
pub struct FirebaseAuth {
    /// Configuration for Firebase Authentication
    pub config: FirebaseAuthConfig,
    /// Cached public keys with their expiration time
    pub cached_public_keys: Arc<RwLock<Option<SharedState>>>,
}

/// Custom error types for Firebase Authentication
#[derive(Debug)]
pub enum FirebaseAuthError {
    InvalidTokenFormat,
    TokenExpired,
    InvalidSignature,
    InvalidIssuer,
    InvalidAudience,
    InvalidSubject,
    InvalidAuthTime,
    HttpError(String),
    JwtError(String),
}

// Implement Display trait for FirebaseAuthError
impl fmt::Display for FirebaseAuthError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            FirebaseAuthError::InvalidTokenFormat => write!(f, "Invalid token format"),
            FirebaseAuthError::TokenExpired => write!(f, "Token expired"),
            FirebaseAuthError::InvalidSignature => write!(f, "Invalid signature"),
            FirebaseAuthError::InvalidIssuer => write!(f, "Invalid issuer"),
            FirebaseAuthError::InvalidAudience => write!(f, "Invalid audience"),
            FirebaseAuthError::InvalidSubject => write!(f, "Invalid subject"),
            FirebaseAuthError::InvalidAuthTime => write!(f, "Invalid authentication time"),
            FirebaseAuthError::HttpError(msg) => write!(f, "HTTP request failed: {}", msg),
            FirebaseAuthError::JwtError(msg) => write!(f, "JWT error: {}", msg),
        }
    }
}

// Implement Error trait for FirebaseAuthError
impl Error for FirebaseAuthError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        None
    }
}

// Type alias for Result with FirebaseAuthError
pub type FirebaseAuthResult<T> = Result<T, FirebaseAuthError>;