Skip to main content

ez_token/services/authentication/
urls.rs

1/// OAuth2 endpoint variants for supported identity providers.
2///
3/// Provides a type-safe way to construct authorization and token endpoint
4/// URLs, avoiding scattered `format!` literals across the codebase.
5#[derive(Debug, PartialEq)]
6pub enum IdentityProvider {
7    /// Microsoft Entra ID (Azure AD).
8    ///
9    /// Requires a tenant ID — a GUID, domain (e.g. `contoso.onmicrosoft.com`),
10    /// or `"common"` for multi-tenant applications.
11    Microsoft {
12        /// The Entra ID tenant identifier.
13        tenant_id: String,
14    },
15
16    /// Auth0.
17    ///
18    /// Requires your Auth0 domain (e.g. `my-org.eu.auth0.com`) and
19    /// audience (e.g. `api://ez-token`).
20    Auth0 {
21        /// The Auth0 domain (e.g. `my-org.eu.auth0.com`).
22        domain: String,
23        /// The API audience identifier (e.g. `api://ez-token`).
24        audience: String,
25    },
26}
27
28impl IdentityProvider {
29    /// Constructs the authorization endpoint URL for this provider.
30    pub fn auth_url(&self) -> String {
31        match self {
32            Self::Microsoft { tenant_id } => format!(
33                "https://login.microsoftonline.com/{}/oauth2/v2.0/authorize",
34                tenant_id
35            ),
36            Self::Auth0 { domain, .. } => format!("https://{}/authorize", domain),
37        }
38    }
39
40    /// Constructs the token endpoint URL for this provider.
41    pub fn token_url(&self) -> String {
42        match self {
43            Self::Microsoft { tenant_id } => format!(
44                "https://login.microsoftonline.com/{}/oauth2/v2.0/token",
45                tenant_id
46            ),
47            Self::Auth0 { domain, .. } => format!("https://{}/oauth/token", domain),
48        }
49    }
50
51    /// Returns the audience if required by this provider.
52    ///
53    /// Auth0 requires an explicit audience parameter to identify the target API.
54    /// Microsoft does not use this parameter.
55    pub fn audience(&self) -> Option<&str> {
56        match self {
57            Self::Microsoft { .. } => None,
58            Self::Auth0 { audience, .. } => Some(audience),
59        }
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn test_microsoft_endpoints() {
69        let provider = IdentityProvider::Microsoft {
70            tenant_id: "common".to_string(),
71        };
72
73        assert_eq!(
74            provider.auth_url(),
75            "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
76        );
77
78        assert_eq!(
79            provider.token_url(),
80            "https://login.microsoftonline.com/common/oauth2/v2.0/token"
81        );
82
83        assert_eq!(provider.audience(), None);
84    }
85
86    #[test]
87    fn test_microsoft_endpoints_with_guid() {
88        let provider = IdentityProvider::Microsoft {
89            tenant_id: "1234567891011121314".to_string(),
90        };
91
92        assert_eq!(
93            provider.auth_url(),
94            "https://login.microsoftonline.com/1234567891011121314/oauth2/v2.0/authorize"
95        );
96
97        assert_eq!(
98            provider.token_url(),
99            "https://login.microsoftonline.com/1234567891011121314/oauth2/v2.0/token"
100        );
101    }
102
103    #[test]
104    fn test_auth0_endpoints() {
105        let provider = IdentityProvider::Auth0 {
106            domain: "my-org.eu.auth0.com".to_string(),
107            audience: "api://ez-token".to_string(),
108        };
109
110        assert_eq!(provider.auth_url(), "https://my-org.eu.auth0.com/authorize");
111
112        assert_eq!(
113            provider.token_url(),
114            "https://my-org.eu.auth0.com/oauth/token"
115        );
116
117        assert_eq!(provider.audience(), Some("api://ez-token"));
118    }
119}