From 92436c8bb9eafcc56219e784f8b374edfb1907a3 Mon Sep 17 00:00:00 2001 From: Daniel Hader Date: Wed, 20 May 2026 22:04:16 -0500 Subject: basic login route with JWT --- src/routes/auth.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/routes/auth.rs (limited to 'src/routes/auth.rs') diff --git a/src/routes/auth.rs b/src/routes/auth.rs new file mode 100644 index 0000000..0b17ef4 --- /dev/null +++ b/src/routes/auth.rs @@ -0,0 +1,66 @@ +use std::time::{SystemTime, UNIX_EPOCH}; + +use axum::extract::{Json, State}; +use axum::response::IntoResponse; +use jsonwebtoken::{encode, Header}; +use serde::{Deserialize, Serialize}; + +use crate::AppState; +use crate::auth::{check_password}; +use super::errors::RouteError; + +#[derive(Deserialize)] +pub struct LoginRequest { + email: String, + password: String, +} + +#[derive(Serialize)] +struct LoginResponse { + token: String, +} + +#[derive(Serialize)] +struct JWTClaims { + sub: String, + exp: usize, + iat: usize, + is_admin: bool, +} + +pub async fn login( + State(state): State, + Json(request): Json +) -> Result { + + let user = match state.database.fetch_user_by_email(&request.email) { + Err(_) => return Err(RouteError::Internal("database action failed".into())), + Ok(None) => return Err(RouteError::UnregisteredEmail(request.email)), + Ok(Some(user)) => user + }; + + match check_password(&request.password, user.password_hash()) { + Err(_) => return Err(RouteError::Internal("failed to check password".into())), + Ok(false) => return Err(RouteError::AuthorizationFailure()), + Ok(true) => {}, + } + + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_err(|_| RouteError::Internal("failed to access system clock".into()))? + .as_secs() as usize; + + let claims = JWTClaims { + sub: user.email().to_owned(), + iat: now, + exp: now + 60 * 60 * 24, + is_admin: false + }; + + let token= encode(&Header::default(), &claims, &state.api_key) + .map_err(|_| RouteError::Internal("failed to encode jwt".into()))?; + + Ok(Json(LoginResponse { token })) +} + + -- cgit v1.2.3