1use crate::TokenSet;
2use crate::token::StoredTokenSet;
3use origin_domain::{AccountId, AppError, ConnectorId, Result};
4use origin_secrets::{Secret, SecretKey, SecretStore};
5use std::sync::Arc;
6
7#[derive(Debug, Clone)]
12pub struct TokenStore {
13 secrets: Arc<dyn SecretStore>,
14}
15
16impl TokenStore {
17 pub fn new(secrets: Arc<dyn SecretStore>) -> Self {
18 Self { secrets }
19 }
20
21 fn key(connector: &ConnectorId, account: &AccountId) -> SecretKey {
22 SecretKey::new(format!("oauth.{connector}"), account.as_str())
23 }
24
25 pub async fn load(
26 &self,
27 connector: &ConnectorId,
28 account: &AccountId,
29 ) -> Result<Option<TokenSet>> {
30 let Some(secret) = self.secrets.get(&Self::key(connector, account)).await? else {
31 return Ok(None);
32 };
33
34 let stored: StoredTokenSet = serde_json::from_str(secret.expose()).map_err(|error| {
35 AppError::Authentication(format!(
38 "stored credentials for {connector}/{account} are unreadable: {error}"
39 ))
40 })?;
41
42 Ok(Some(stored.into()))
43 }
44
45 pub async fn save(
46 &self,
47 connector: &ConnectorId,
48 account: &AccountId,
49 tokens: &TokenSet,
50 ) -> Result<()> {
51 let encoded = serde_json::to_string(&StoredTokenSet::from(tokens))
52 .map_err(|error| AppError::internal(format!("cannot encode credentials: {error}")))?;
53
54 self.secrets
55 .set(&Self::key(connector, account), Secret::new(encoded))
56 .await
57 }
58
59 pub async fn delete(&self, connector: &ConnectorId, account: &AccountId) -> Result<()> {
62 self.secrets.delete(&Self::key(connector, account)).await
63 }
64}