Skip to main content

max / goingson

2.9 KB · 84 lines History Blame Raw
1 //! Microsoft/Outlook OAuth2 provider.
2 //!
3 //! Implements OAuth2 for Outlook/Microsoft 365 access via IMAP with XOAUTH2.
4 //! Uses default trait implementations for token exchange.
5 //!
6 //! See: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
7
8 use crate::oauth::provider::{OAuthProvider, OAuthProviderConfig};
9
10 /// Microsoft/Outlook OAuth2 provider.
11 ///
12 /// Uses PKCE for desktop apps (client secret is optional).
13 pub struct MicrosoftProvider {
14 client_id: String,
15 client_secret: Option<String>,
16 config: OAuthProviderConfig,
17 }
18
19 impl MicrosoftProvider {
20 /// Creates a new Microsoft OAuth provider.
21 ///
22 /// # Arguments
23 /// * `client_id` - Azure AD application (client) ID
24 /// * `client_secret` - Optional Azure AD client secret (desktop apps use PKCE instead)
25 pub fn new(client_id: impl Into<String>, client_secret: Option<String>) -> Self {
26 Self {
27 client_id: client_id.into(),
28 client_secret,
29 config: OAuthProviderConfig {
30 auth_url: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize".to_string(),
31 token_url: "https://login.microsoftonline.com/common/oauth2/v2.0/token".to_string(),
32 // Microsoft identity platform has no RFC 7009 revocation endpoint
33 // (only interactive session logout), so disconnect can't revoke.
34 revoke_url: None,
35 scopes: vec![
36 "https://outlook.office.com/IMAP.AccessAsUser.All".to_string(),
37 "https://outlook.office.com/SMTP.Send".to_string(),
38 "offline_access".to_string(),
39 "openid".to_string(),
40 "email".to_string(),
41 "profile".to_string(),
42 ],
43 uses_jmap: false,
44 jmap_session_url: None,
45 imap_server: Some("outlook.office365.com".to_string()),
46 imap_port: Some(993),
47 smtp_server: Some("smtp.office365.com".to_string()),
48 smtp_port: Some(587),
49 userinfo_url: Some("https://graph.microsoft.com/v1.0/me".to_string()),
50 email_json_path: vec!["mail", "userPrincipalName"], // Try mail first, then UPN
51 },
52 }
53 }
54 }
55
56 impl OAuthProvider for MicrosoftProvider {
57 fn id(&self) -> &'static str {
58 "microsoft"
59 }
60
61 fn display_name(&self) -> &'static str {
62 "Microsoft / Outlook"
63 }
64
65 fn config(&self) -> &OAuthProviderConfig {
66 &self.config
67 }
68
69 fn client_id(&self) -> &str {
70 &self.client_id
71 }
72
73 fn client_secret(&self) -> Option<&str> {
74 self.client_secret.as_deref()
75 }
76
77 fn customize_auth_url(&self, url: &mut String) {
78 // Microsoft-specific: response_mode for better security
79 url.push_str("&response_mode=query");
80 }
81
82 // Uses default exchange_code, refresh_token, get_user_email implementations
83 }
84