use crate::auth_di;
use crate::protocols::auth::{ChallengeRequest, ChallengeResponse};
use crate::session::TokenResult;
use crate::trust_tasks::TASK_AUTH_AUTHENTICATE_0_1;
pub async fn challenge_response_di(
base_url: &str,
client_did: &str,
private_key_multibase: &str,
vta_did: &str,
) -> Result<TokenResult, Box<dyn std::error::Error>> {
let http = crate::http::rest_client();
let challenge_url = format!("{base_url}/auth/challenge");
let challenge_resp = http
.post(&challenge_url)
.header("Trust-Task", crate::trust_tasks::TASK_AUTH_CHALLENGE_0_1)
.json(&ChallengeRequest {
did: client_did.to_string(),
})
.send()
.await
.map_err(|e| format!("could not connect to VTA at {challenge_url}: {e}"))?;
if !challenge_resp.status().is_success() {
let status = challenge_resp.status();
let body = challenge_resp.text().await.unwrap_or_default();
return Err(format!("challenge request failed ({status}): {body}").into());
}
let challenge: ChallengeResponse = challenge_resp.json().await.map_err(|e| {
format!("unexpected challenge response from VTA at {challenge_url} (is this a VTA?): {e}")
})?;
let body = auth_di::sign_authenticate_doc(
client_did,
private_key_multibase,
vta_did,
&challenge.challenge,
&challenge.session_id,
)
.await?;
let auth_url = format!("{base_url}/auth/");
let auth_resp = http
.post(&auth_url)
.header("content-type", "application/json")
.header("Trust-Task", TASK_AUTH_AUTHENTICATE_0_1)
.body(body)
.send()
.await
.map_err(|e| format!("could not connect to VTA at {auth_url}: {e}"))?;
let status = auth_resp.status();
if !status.is_success() {
let body = auth_resp.text().await.unwrap_or_default();
return Err(format!("authentication failed ({status}): {body}").into());
}
let auth_text = auth_resp
.text()
.await
.map_err(|e| format!("failed to read auth response from VTA: {e}"))?;
let auth_data =
auth_di::parse_auth_response(&auth_text).map_err(|e| format!("{e} (VTA at {auth_url})"))?;
let access_expires_at = auth_data.access_expires_at_epoch().ok_or_else(|| {
format!(
"VTA returned unparseable session.issuedAt: '{}'",
auth_data.session.issued_at
)
})?;
Ok(TokenResult {
access_token: auth_data.tokens.access_token,
access_expires_at,
})
}