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::{
13	error::Error,
14	value::{datetime::DateTime, identity::IdentityId},
15};
16
17use super::AuthService;
18
19impl AuthService {
20	pub fn validate_token(&self, token: &str) -> Result<Option<Token>, Error> {
21		let mut txn = self.engine.begin_query()?;
22
23		if let Some(def) = find_token_by_value(&mut Transaction::Query(&mut txn), token)? {
24			if let Some(expires_at) = def.expires_at
25				&& expires_at < self.now()?
26			{
27				return Ok(None);
28			}
29
30			let catalog = self.engine.catalog();
31			let enabled = catalog
32				.find_identity(&mut Transaction::Query(&mut txn), def.identity)?
33				.is_some_and(|identity| identity.enabled);
34			if !enabled {
35				return Ok(None);
36			}
37
38			return Ok(Some(def));
39		}
40
41		self.validate_catalog_token(token)
42	}
43
44	fn validate_catalog_token(&self, token: &str) -> Result<Option<Token>, Error> {
45		let Some(provider) = self.auth_registry.get("token") else {
46			return Ok(None);
47		};
48
49		let mut txn = self.engine.begin_query()?;
50		let catalog = self.engine.catalog();
51
52		let auths = catalog.list_authentications_by_method(&mut Transaction::Query(&mut txn), "token")?;
53
54		let creds = HashMap::from([("token".to_string(), token.to_string())]);
55
56		for auth in auths {
57			if let Ok(AuthStep::Authenticated) = provider.authenticate(&auth.properties, &creds)
58				&& let Some(ident) =
59					catalog.find_identity(&mut Transaction::Query(&mut txn), auth.identity)?
60				&& ident.enabled
61			{
62				return Ok(Some(Token {
63					id: 0,
64					token: token.to_string(),
65					identity: ident.id,
66					expires_at: None,
67					created_at: DateTime::default(),
68				}));
69			}
70		}
71
72		Ok(None)
73	}
74
75	pub fn revoke_token(&self, token: &str) -> Result<bool, Error> {
76		let Some(def) = self.find_token(token)? else {
77			return Ok(false);
78		};
79		self.drop_and_commit(def.id)?;
80		Ok(true)
81	}
82
83	#[inline]
84	fn find_token(&self, token: &str) -> Result<Option<Token>, Error> {
85		let mut txn = self.engine.begin_query()?;
86		find_token_by_value(&mut Transaction::Query(&mut txn), token)
87	}
88
89	#[inline]
90	fn drop_and_commit(&self, id: TokenId) -> Result<(), Error> {
91		let mut admin = self.engine.begin_admin()?;
92		drop_token(&mut admin, id)?;
93		admin.commit()?;
94		Ok(())
95	}
96
97	pub fn revoke_all(&self, identity: IdentityId) -> Result<(), Error> {
98		let mut admin = self.engine.begin_admin()?;
99		drop_tokens_by_identity(&mut admin, identity)?;
100		admin.commit()?;
101		Ok(())
102	}
103
104	pub fn cleanup_expired(&self) -> Result<(), Error> {
105		self.challenges.cleanup_expired();
106
107		let mut admin = self.engine.begin_admin()?;
108		drop_expired_tokens(&mut admin, self.now()?)?;
109		admin.commit()?;
110		Ok(())
111	}
112}