use crate::error::AuthError;
use crate::oauth::get_provider;
use crate::state::global;
use doido_auth_macros::auth_controller;
use doido_controller::axum::http::StatusCode;
use doido_controller::axum::response::{IntoResponse, Redirect, Response};
use doido_core::Result;
use serde::Deserialize;
pub struct AuthOauth;
#[derive(Debug, Deserialize)]
struct OAuthCallbackQuery {
code: String,
#[allow(dead_code)]
state: Option<String>,
}
#[auth_controller]
impl AuthOauth {
pub async fn authorize(ctx: doido_controller::Context) -> Result<Response> {
let provider = ctx.param("provider").unwrap_or("unknown");
let state = global();
let oauth = state
.oauth
.get(provider)
.cloned()
.or_else(|| get_provider(provider))
.ok_or_else(|| AuthError::OAuth(format!("unknown provider {provider}")))?;
let url = oauth.authorize_url(&uuid::Uuid::new_v4().to_string())?;
Ok(Redirect::temporary(&url).into_response())
}
pub async fn callback(ctx: doido_controller::Context) -> Result<Response> {
let provider = ctx.param("provider").unwrap_or("unknown").to_string();
let query: OAuthCallbackQuery = ctx.params()?;
let state = global();
let oauth = state
.oauth
.get(&provider)
.cloned()
.or_else(|| get_provider(&provider))
.ok_or_else(|| AuthError::OAuth(format!("unknown provider {provider}")))?;
let tokens = oauth.exchange_code(&query.code)?;
Ok((StatusCode::OK, doido_controller::axum::Json(tokens)).into_response())
}
}