use auth::server::http::token::TokenRequest; use auth::session::Session; use export::http::{Query, Response, State}; use serde::Deserialize; use crate::auth::errors::ApiError; use crate::auth::session::cookie::redirect_with_cookies; use crate::auth::session::project; use crate::auth::services::AuthService; const JWT_TTL_SECS: i64 = 900; #[derive(Debug, Deserialize)] pub struct CallbackQuery { #[serde(default)] pub redirect: Option, } pub async fn callback( State(service): State, session: Session, Query(query): Query, ) -> Result { let cookie = issue_session_cookie(&service, &session).await?; Ok(redirect_with_cookies( &sanitize_redirect(query.redirect.as_deref()), &[cookie], )) } pub async fn issue_session_cookie( service: &AuthService, session: &Session, ) -> Result { let client = service .state .kenauth .as_ref() .ok_or_else(|| ApiError::internal("identity service is unavailable"))?; let auth = client.service(); let request_id = export::middleware::request_id().unwrap_or_default(); let user_id = auth .require_session(session, Some(request_id.as_str())) .await .map_err(map_identity)?; let public = client.get_user_public(user_id).await.map_err(map_client)?; project::upsert(service, &public).await?; let issued = auth .issue_user_token( session, user_id, TokenRequest::default(), Some(request_id.as_str()), ) .await .map_err(map_identity)?; Ok(token::session_cookie( &service.config().jwt, &issued.token, JWT_TTL_SECS, )) } fn sanitize_redirect(raw: Option<&str>) -> String { match raw.map(str::trim) { Some(value) if value.starts_with('/') && !value.starts_with("//") => value.to_string(), _ => "/app".to_string(), } } fn map_identity(error: auth::server::errors::AuthError) -> ApiError { match error { auth::server::errors::AuthError::Unauthenticated => ApiError::unauthorized(), auth::server::errors::AuthError::Forbidden => ApiError::forbidden(), other => ApiError::internal(other.to_string()), } } fn map_client(error: auth::client::error::KenAuthError) -> ApiError { match error { auth::client::error::KenAuthError::NotFound => ApiError::not_found("user not found"), auth::client::error::KenAuthError::Unauthenticated => ApiError::unauthorized(), other => ApiError::internal(other.to_string()), } }