alibi_plugins/sso/
domain_verification.rs1use super::{
3 AuthContext, AuthResult, AuthSchema, EndpointResponse, JsValue, ServerEndpoint, SessionRequest,
4 SsoPlugin, Value, json,
5};
6impl SsoPlugin {
7 pub fn request_domain_verification_endpoint(
8 provider_id: &str,
9 ) -> AuthResult<ServerEndpoint<Value>> {
10 ServerEndpoint::new("sso", "requestDomainVerification")
11 .with_body(&json!({"providerId":provider_id}))
12 }
13 pub(super) fn domain_identifier(&self, provider_id: &str) -> String {
14 let prefix = if self.config.domain_verification_token_prefix.is_empty() {
15 "better-auth-token"
16 } else {
17 &self.config.domain_verification_token_prefix
18 };
19 format!("_{prefix}-{provider_id}")
20 }
21 pub(super) async fn issue_domain_proof<S: AuthSchema>(
22 &self,
23 provider_id: &str,
24 ctx: &AuthContext<S>,
25 ) -> AuthResult<String> {
26 use base64::Engine as _;
27 let bytes = rand::random::<[u8; 18]>();
28 let token = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(bytes);
29 let now = chrono::Utc::now();
30 _ = ctx
31 .verifications()
32 .create(alibi_core::CreateVerification {
33 identifier: self.domain_identifier(provider_id),
34 value: token.clone(),
35 expires_at: now + chrono::Duration::days(7),
36 })
37 .await?;
38 Ok(token)
39 }
40 pub(super) async fn request_domain<S: AuthSchema>(
41 &self,
42 input: &JsValue,
43 request: &impl SessionRequest,
44 ctx: &AuthContext<S>,
45 ) -> AuthResult<EndpointResponse> {
46 let provider = self.authorized_provider(input, request, ctx).await?;
47 if provider.domain_verified == Some(true) {
48 return Err(alibi_core::AuthError::Api {
49 status: 409,
50 code: Some("DOMAIN_VERIFIED".into()),
51 message: "Domain has already been verified".into(),
52 });
53 }
54 let proof = ctx
55 .verifications()
56 .find(&self.domain_identifier(&provider.provider_id))
57 .await?;
58 let token = if let Some(proof) = proof.filter(|proof| {
59 proof
60 .expires_at()
61 .is_ok_and(|expiry| expiry > chrono::Utc::now())
62 }) {
63 proof.value()?.to_owned()
64 } else {
65 self.issue_domain_proof(&provider.provider_id, ctx).await?
66 };
67 Ok(EndpointResponse::json(&json!({"domainVerificationToken":token}))?.with_status(201))
68 }
69}