use super::types::{Claims, JwtHandler, TokenType};
use crate::utils::error::gateway_error::{GatewayError, Result};
use jsonwebtoken::{Header, Validation, decode, encode};
use std::time::{SystemTime, UNIX_EPOCH};
use tracing::debug;
use uuid::Uuid;
impl JwtHandler {
pub async fn create_password_reset_token(&self, user_id: Uuid) -> Result<String> {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|e| GatewayError::internal(format!("System time error: {}", e)))?
.as_secs();
let claims = Claims {
sub: user_id,
iat: now,
exp: now + 3600, iss: self.issuer.clone(),
aud: "password_reset".to_string(),
jti: Uuid::new_v4().to_string(),
role: "".to_string(),
permissions: vec![],
team_id: None,
session_id: None,
token_type: TokenType::PasswordReset,
};
let header = Header::new(self.algorithm);
let token = encode(&header, &claims, &self.encoding_key).map_err(GatewayError::from)?;
debug!("Created password reset token for user: {}", user_id);
Ok(token)
}
pub async fn verify_password_reset_token(&self, token: &str) -> Result<Uuid> {
let mut validation = Validation::new(self.algorithm);
validation.set_issuer(&[&self.issuer]);
validation.set_audience(&["password_reset"]);
let token_data =
decode::<Claims>(token, &self.decoding_key, &validation).map_err(GatewayError::from)?;
if !matches!(token_data.claims.token_type, TokenType::PasswordReset) {
return Err(GatewayError::auth("Invalid token type for password reset"));
}
Ok(token_data.claims.sub)
}
pub async fn create_email_verification_token(&self, user_id: Uuid) -> Result<String> {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|e| GatewayError::internal(format!("System time error: {}", e)))?
.as_secs();
let claims = Claims {
sub: user_id,
iat: now,
exp: now + 86400, iss: self.issuer.clone(),
aud: "email_verification".to_string(),
jti: Uuid::new_v4().to_string(),
role: "".to_string(),
permissions: vec![],
team_id: None,
session_id: None,
token_type: TokenType::EmailVerification,
};
let header = Header::new(self.algorithm);
let token = encode(&header, &claims, &self.encoding_key).map_err(GatewayError::from)?;
debug!("Created email verification token for user: {}", user_id);
Ok(token)
}
pub async fn verify_email_verification_token(&self, token: &str) -> Result<Uuid> {
let mut validation = Validation::new(self.algorithm);
validation.set_issuer(&[&self.issuer]);
validation.set_audience(&["email_verification"]);
let token_data =
decode::<Claims>(token, &self.decoding_key, &validation).map_err(GatewayError::from)?;
if !matches!(token_data.claims.token_type, TokenType::EmailVerification) {
return Err(GatewayError::auth(
"Invalid token type for email verification",
));
}
Ok(token_data.claims.sub)
}
pub async fn create_invitation_token(
&self,
user_id: Uuid,
team_id: Uuid,
role: String,
) -> Result<String> {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|e| GatewayError::internal(format!("System time error: {}", e)))?
.as_secs();
let claims = Claims {
sub: user_id,
iat: now,
exp: now + 604800, iss: self.issuer.clone(),
aud: "invitation".to_string(),
jti: Uuid::new_v4().to_string(),
role,
permissions: vec![],
team_id: Some(team_id),
session_id: None,
token_type: TokenType::Invitation,
};
let header = Header::new(self.algorithm);
let token = encode(&header, &claims, &self.encoding_key).map_err(GatewayError::from)?;
debug!(
"Created invitation token for user: {} team: {}",
user_id, team_id
);
Ok(token)
}
pub async fn verify_invitation_token(&self, token: &str) -> Result<(Uuid, Uuid, String)> {
let mut validation = Validation::new(self.algorithm);
validation.set_issuer(&[&self.issuer]);
validation.set_audience(&["invitation"]);
let token_data =
decode::<Claims>(token, &self.decoding_key, &validation).map_err(GatewayError::from)?;
if !matches!(token_data.claims.token_type, TokenType::Invitation) {
return Err(GatewayError::auth("Invalid token type for invitation"));
}
let team_id = token_data
.claims
.team_id
.ok_or_else(|| GatewayError::auth("Missing team ID in invitation token"))?;
Ok((token_data.claims.sub, team_id, token_data.claims.role))
}
}