Skip to main content

reifydb_auth/service/
token.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::collections::HashMap;
5
6use reifydb_catalog::{drop_expired_tokens, drop_token, drop_tokens_by_identity, find_token_by_value};
7use reifydb_core::interface::{
8	auth::AuthStep,
9	catalog::token::{Token, TokenId},
10};
11use reifydb_transaction::transaction::Transaction;
12use reifydb_value::value::{datetime::DateTime, identity::IdentityId};
13
14use super::AuthService;
15
16impl AuthService {
17	pub fn validate_token(&self, token: &str) -> Option<Token> {
18		let mut txn = self.engine.begin_query().ok()?;
19
20		if let Ok(Some(def)) = find_token_by_value(&mut Transaction::Query(&mut txn), token) {
21			if let Some(expires_at) = def.expires_at
22				&& expires_at < self.now().ok()?
23			{
24				return None;
25			}
26			return Some(def);
27		}
28
29		self.validate_catalog_token(token)
30	}
31
32	fn validate_catalog_token(&self, token: &str) -> Option<Token> {
33		let provider = self.auth_registry.get("token")?;
34
35		let mut txn = self.engine.begin_query().ok()?;
36		let catalog = self.engine.catalog();
37
38		let auths = catalog.list_authentications_by_method(&mut Transaction::Query(&mut txn), "token").ok()?;
39
40		let creds = HashMap::from([("token".to_string(), token.to_string())]);
41
42		for auth in auths {
43			if let Ok(AuthStep::Authenticated) = provider.authenticate(&auth.properties, &creds)
44				&& let Ok(Some(ident)) =
45					catalog.find_identity(&mut Transaction::Query(&mut txn), auth.identity)
46				&& ident.enabled
47			{
48				return Some(Token {
49					id: 0,
50					token: token.to_string(),
51					identity: ident.id,
52					expires_at: None,
53					created_at: DateTime::default(),
54				});
55			}
56		}
57
58		None
59	}
60
61	pub fn revoke_token(&self, token: &str) -> bool {
62		let def = match self.find_token(token) {
63			Some(def) => def,
64			None => return false,
65		};
66		self.drop_and_commit(def.id)
67	}
68
69	#[inline]
70	fn find_token(&self, token: &str) -> Option<Token> {
71		let mut txn = self.engine.begin_query().ok()?;
72		match find_token_by_value(&mut Transaction::Query(&mut txn), token) {
73			Ok(Some(def)) => Some(def),
74			_ => None,
75		}
76	}
77
78	#[inline]
79	fn drop_and_commit(&self, id: TokenId) -> bool {
80		let mut admin = match self.engine.begin_admin() {
81			Ok(a) => a,
82			Err(_) => return false,
83		};
84
85		if drop_token(&mut admin, id).is_err() {
86			return false;
87		}
88
89		admin.commit().is_ok()
90	}
91
92	pub fn revoke_all(&self, identity: IdentityId) {
93		if let Ok(mut admin) = self.engine.begin_admin()
94			&& drop_tokens_by_identity(&mut admin, identity).is_ok()
95		{
96			let _ = admin.commit();
97		}
98	}
99
100	pub fn cleanup_expired(&self) {
101		if let (Ok(mut admin), Ok(now)) = (self.engine.begin_admin(), self.now())
102			&& drop_expired_tokens(&mut admin, now).is_ok()
103		{
104			let _ = admin.commit();
105		}
106		self.challenges.cleanup_expired();
107	}
108}