dogy_backend_api/middleware/auth/
core.rs1use jsonwebtoken::{decode, DecodingKey, TokenData, Validation};
3use serde::Deserialize;
4use tracing::debug;
5
6use crate::config::load_config;
7
8use super::error::{Error, Result};
9use super::layer::CurrentUser;
10
11#[allow(dead_code)]
13#[derive(Debug, Deserialize)]
14pub struct Claims {
15 pub role: Option<String>,
18
19 pub sub: String,
21
22 pub iss: String,
24
25 pub jti: String,
27
28 pub exp: usize,
30
31 pub iat: usize,
33
34 pub nbf: usize,
36}
37
38fn decode_jwt(jwt_token: &str) -> Result<TokenData<Claims>> {
40 let config = load_config();
41 debug!("JWT Token: {:?}", jwt_token);
42 debug!("Config: {:?}", config);
43 let decoding_key = DecodingKey::from_rsa_components(
44 config.CLERK_RSA_MODULUS.as_str(),
45 config.CLERK_RSA_EXPONENT.as_str(),
46 )
47 .map_err(|_| Error::InvalidDecodingKey)?;
48
49 decode(
50 jwt_token,
51 &decoding_key,
52 &Validation::new(jsonwebtoken::Algorithm::RS256),
53 )
54 .map_err(|_| Error::InvalidToken)
55}
56
57pub fn authenticate_user(auth_header: &str) -> Result<CurrentUser> {
60 let user_info = decode_jwt(auth_header)?;
61 Ok(CurrentUser {
62 user_id: user_info.claims.sub,
63 role: user_info.claims.role,
64 internal_id: None,
65 })
66}
67
68#[cfg(test)]
69mod test {
70 use crate::middleware::auth::core::authenticate_user;
71 use crate::middleware::auth::layer::CurrentUser;
72 use std::env;
73
74 use super::decode_jwt;
75 use jsonwebtoken::Algorithm;
76
77 #[test]
78 fn test_decode_jwt_ok() {
79 let _ = dotenv::from_filename(".env.test");
80 let jwt_token = env::var("JWT_TOKEN").unwrap();
81
82 let token_data = decode_jwt(jwt_token.as_str()).unwrap();
83 assert_eq!(token_data.header.alg, Algorithm::RS256);
84 assert_eq!(token_data.header.typ, Some("JWT".to_string()));
85 assert_eq!(token_data.claims.sub, "user_2ruHSXCzfIRreR2tpttVQBl512a");
86 assert_eq!(token_data.claims.role, None);
87 }
88
89 #[test]
94 fn test_decode_jwt_invalid_decoding_key_err() {
95 unsafe {
96 env::set_var("DATABASE_URL", "test_url");
97 env::set_var("LANGGRAPH_ASSISTANT_ENDPOINT", "test_url");
98 env::set_var("CLERK_RSA_MODULUS", "invalid_base64@string!");
99 env::set_var("CLERK_RSA_EXPONENT", "test827@0.");
100 }
101
102 let _ = dotenv::from_filename(".env.test");
103 let jwt_token = env::var("JWT_TOKEN").unwrap();
104 let token_data = decode_jwt(jwt_token.as_str());
105 dbg!("Token data: {:?}", &token_data);
106 assert!(
107 matches!(token_data, Err(super::Error::InvalidDecodingKey)),
108 "Expected InvalidDecodingKey error"
109 );
110 }
111
112 #[test]
113 fn test_decode_jwt_invalid_token_err() {
114 let _ = dotenv::from_filename(".env.test");
115 let jwt_token = "invalid_token";
116 let token_data = decode_jwt(jwt_token);
117 dbg!("Token data: {:?}", &token_data);
118 assert!(
119 matches!(token_data, Err(super::Error::InvalidToken)),
120 "Expected InvalidToken error"
121 );
122 }
123
124 #[test]
125 fn test_authenticate_user_ok() {
126 let _ = dotenv::from_filename(".env.test");
127 let jwt_token = env::var("JWT_TOKEN").unwrap();
128
129 let current_user = authenticate_user(jwt_token.as_str()).unwrap();
130 assert_eq!(
131 current_user,
132 CurrentUser {
133 user_id: String::from("user_2ruHSXCzfIRreR2tpttVQBl512a"),
134 role: None,
135 internal_id: None,
136 }
137 );
138 }
139
140 #[test]
141 fn test_authenticate_user_invalid_token_err() {
142 let jwt_token = "invalid_token";
143
144 let _ = dotenv::from_filename(".env.test");
145 let current_user = authenticate_user(jwt_token);
146 assert!(
147 matches!(current_user, Err(super::Error::InvalidToken)),
148 "Expected InvalidToken error"
149 );
150 }
151
152 #[test]
153 fn test_authenticate_user_invalid_decoding_key_err() {
154 unsafe {
155 env::set_var("DATABASE_URL", "test_url");
156 env::set_var("LANGGRAPH_ASSISTANT_ENDPOINT", "test_url");
157 env::set_var("CLERK_RSA_MODULUS", "invalid_base64@string!");
158 env::set_var("CLERK_RSA_EXPONENT", "test827@0.");
159 }
160
161 let _ = dotenv::from_filename(".env.test");
162 let jwt_token = env::var("JWT_TOKEN").unwrap();
163
164 let current_user = authenticate_user(jwt_token.as_str());
165 dbg!("Current user: {:?}", ¤t_user);
166 assert!(
167 matches!(current_user, Err(super::Error::InvalidDecodingKey)),
168 "Expected InvalidDecodingKey error"
169 );
170 }
171}