use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::mfa::{AuthenticationChallenge, AuthenticationChallengeId, Mfa, MfaCode};
use crate::{ResponseExt, WorkOsResult};
#[derive(Debug, Serialize, Deserialize)]
pub struct VerifyChallengeResponse {
pub challenge: AuthenticationChallenge,
#[serde(rename = "valid")]
pub is_valid: bool,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)]
pub struct VerifyChallengeParams<'a> {
#[serde(skip)]
pub authentication_challenge_id: &'a AuthenticationChallengeId,
pub code: &'a MfaCode,
}
#[derive(Debug, Error)]
pub enum VerifyChallengeError {}
#[async_trait]
pub trait VerifyChallenge {
async fn verify_challenge(
&self,
params: &VerifyChallengeParams<'_>,
) -> WorkOsResult<VerifyChallengeResponse, VerifyChallengeError>;
}
#[async_trait]
impl VerifyChallenge for Mfa<'_> {
async fn verify_challenge(
&self,
params: &VerifyChallengeParams<'_>,
) -> WorkOsResult<VerifyChallengeResponse, VerifyChallengeError> {
let url = self.workos.base_url().join(&format!(
"/auth/challenges/{id}/verify",
id = params.authentication_challenge_id
))?;
let verify_response = self
.workos
.client()
.post(url)
.bearer_auth(self.workos.key())
.json(¶ms)
.send()
.await?
.handle_unauthorized_or_generic_error()
.await?
.json::<VerifyChallengeResponse>()
.await?;
Ok(verify_response)
}
}
#[cfg(test)]
mod test {
use serde_json::json;
use tokio;
use crate::mfa::{AuthenticationChallengeId, MfaCode};
use crate::{ApiKey, WorkOs};
use super::*;
#[tokio::test]
async fn it_calls_the_verify_challenge_endpoint() {
let mut server = mockito::Server::new_async().await;
let workos = WorkOs::builder(&ApiKey::from("sk_example_123456789"))
.base_url(&server.url())
.unwrap()
.build();
server
.mock(
"POST",
"/auth/challenges/auth_challenge_01FVYZWQTZQ5VB6BC5MPG2EYC5/verify",
)
.match_header("Authorization", "Bearer sk_example_123456789")
.match_body(r#"{"code":"123456"}"#)
.with_status(201)
.with_body(
json!({
"challenge": {
"object": "authentication_challenge",
"id": "auth_challenge_01FVYZWQTZQ5VB6BC5MPG2EYC5",
"created_at": "2022-02-15T15:26:53.274Z",
"updated_at": "2022-02-15T15:26:53.274Z",
"expires_at": "2022-02-15T15:36:53.279Z",
"authentication_factor_id": "auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ"
},
"valid": true
})
.to_string(),
)
.create_async()
.await;
let verify = workos
.mfa()
.verify_challenge(&VerifyChallengeParams {
authentication_challenge_id: &AuthenticationChallengeId::from(
"auth_challenge_01FVYZWQTZQ5VB6BC5MPG2EYC5",
),
code: &MfaCode::from("123456"),
})
.await
.unwrap();
assert_eq!(
verify.challenge.id,
AuthenticationChallengeId::from("auth_challenge_01FVYZWQTZQ5VB6BC5MPG2EYC5")
)
}
}