Skip to content
Clone
9362a10
85 lines 2.6 KB Rust
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<String>,
}
pub async fn callback(
State(service): State<AuthService>,
session: Session,
Query(query): Query<CallbackQuery>,
) -> Result<Response, ApiError> {
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<String, ApiError> {
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()),
}
}