claw10_auth/
credential.rs1use chrono::Utc;
2use uuid::Uuid;
3
4use claw10_domain::{Credential, CredentialId, CredentialKind, IdentityId};
5
6use crate::error::AuthError;
7
8pub struct CredentialService;
9
10impl CredentialService {
11 #[must_use]
12 pub fn issue_credential(
13 identity_id: IdentityId,
14 kind: CredentialKind,
15 scope: String,
16 ttl_seconds: i64,
17 ) -> Credential {
18 let now = Utc::now();
19 Credential {
20 id: CredentialId(Uuid::now_v7()),
21 identity_id,
22 kind,
23 scope,
24 issued_at: now,
25 expires_at: now + chrono::Duration::seconds(ttl_seconds),
26 revoked_at: None,
27 }
28 }
29
30 pub fn verify_credential(
31 credential: &Credential,
32 required_scope: &str,
33 ) -> Result<(), AuthError> {
34 if credential.revoked_at.is_some() {
35 return Err(AuthError::CredentialRevoked);
36 }
37
38 if Utc::now() > credential.expires_at {
39 return Err(AuthError::CredentialExpired);
40 }
41
42 if !credential.scope.contains(required_scope) {
43 return Err(AuthError::Unauthorized(format!(
44 "credential scope '{}' does not cover '{}'",
45 credential.scope, required_scope
46 )));
47 }
48
49 Ok(())
50 }
51
52 pub fn revoke_credential(credential: &mut Credential) {
53 credential.revoked_at = Some(Utc::now());
54 }
55}