/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ use crate::{Server, auth::AccessToken}; use serde::{Deserialize, Serialize}; use trc::{AddContext, AuthEvent, EventType}; #[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)] pub struct OAuthIntrospect { #[serde(default)] pub active: bool, #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub scope: Option, #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub client_id: Option, #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub username: Option, #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub token_type: Option, #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub exp: Option, #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub iat: Option, #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub nbf: Option, #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub sub: Option, } impl Server { pub async fn introspect_access_token( &self, token: &str, access_token: &AccessToken, ) -> trc::Result { match self.validate_access_token(None, token).await { Ok(token_info) => Ok(OAuthIntrospect { active: true, username: self .account(access_token.account_id()) .await .caused_by(trc::location!())? .name() .to_string() .into(), token_type: Some("bearer".into()), exp: Some(token_info.expiry as i64), iat: Some(token_info.issued_at as i64), ..Default::default() }), Err(err) if matches!( err.event_type(), EventType::Auth(AuthEvent::Error) | EventType::Auth(AuthEvent::TokenExpired) ) => { Ok(OAuthIntrospect::default()) } Err(err) => Err(err), } } }