Skip to main content

simple_oauth/common/
oidc.rs

1use crate::{
2    SimpleOAuthError, SimpleOAuthProvider,
3    types::{OidcDiscovery, OidcUserInfo, UserInfo},
4};
5
6#[derive(Debug, Clone)]
7pub struct Oidc {
8    auth_endpoint: String,
9    token_endpoint: String,
10    userinfo_endpoint: String,
11}
12
13impl Oidc {
14    pub fn from_config(config: OidcDiscovery) -> Self {
15        Self {
16            auth_endpoint: config.authorization_endpoint,
17            token_endpoint: config.token_endpoint,
18            userinfo_endpoint: config.userinfo_endpoint,
19        }
20    }
21
22    /// Discover the OIDC config from the given URL. This will fail
23    /// if the discovery document is missing a token or userinfo endpoint.
24    pub async fn discover(
25        http_client: &reqwest::Client,
26        discovery_url: &str,
27    ) -> Result<Self, SimpleOAuthError> {
28        let discovery = http_client
29            .get(discovery_url)
30            .send()
31            .await?
32            .error_for_status()?
33            .json::<OidcDiscovery>()
34            .await?;
35
36        Ok(Self {
37            auth_endpoint: discovery.authorization_endpoint,
38            token_endpoint: discovery.token_endpoint,
39            userinfo_endpoint: discovery.userinfo_endpoint,
40        })
41    }
42}
43
44impl SimpleOAuthProvider for Oidc {
45    fn authorize_url(&self) -> &str {
46        &self.auth_endpoint
47    }
48
49    fn token_url(&self) -> &str {
50        &self.token_endpoint
51    }
52
53    fn user_info_url(&self) -> &str {
54        &self.userinfo_endpoint
55    }
56
57    fn default_scopes(&self) -> &'static [&'static str] {
58        &["openid", "profile"]
59    }
60
61    fn extract_user_info(&self, val: serde_json::Value) -> Result<UserInfo, serde_json::Error> {
62        let user_info: OidcUserInfo = serde_json::from_value(val)?;
63
64        Ok(UserInfo {
65            id: user_info.sub,
66            name: user_info.name,
67            username: user_info.preferred_username,
68            email: user_info.email,
69            email_verified: user_info.email_verified,
70            avatar_url: user_info.picture,
71            groups: user_info.groups,
72        })
73    }
74}