Skip to main content

max / goingson

2.3 KB · 72 lines History Blame Raw
1 //! Fastmail OAuth2 provider.
2 //!
3 //! Implements OAuth2 with PKCE for Fastmail's JMAP API access.
4 //! Uses ClientIdOnly (no client secret required with PKCE).
5 //!
6 //! See: https://www.fastmail.com/developer/integrating-with-fastmail/
7
8 use crate::oauth::provider::{ClientAuthMethod, OAuthProvider, OAuthProviderConfig};
9
10 /// Fastmail OAuth2 provider.
11 ///
12 /// Uses PKCE with client_id only (no secret required).
13 /// Uses JMAP instead of IMAP.
14 pub struct FastmailProvider {
15 client_id: String,
16 config: OAuthProviderConfig,
17 }
18
19 impl FastmailProvider {
20 /// Creates a new Fastmail OAuth provider.
21 pub fn new(client_id: impl Into<String>) -> Self {
22 Self {
23 client_id: client_id.into(),
24 config: OAuthProviderConfig {
25 auth_url: "https://api.fastmail.com/oauth/authorize".to_string(),
26 token_url: "https://api.fastmail.com/oauth/refresh".to_string(),
27 // No documented RFC 7009 revocation endpoint; disconnect drops
28 // the local tokens without a provider-side revoke (best-effort).
29 revoke_url: None,
30 scopes: vec![
31 "urn:ietf:params:jmap:core".to_string(),
32 "urn:ietf:params:jmap:mail".to_string(),
33 "urn:ietf:params:jmap:submission".to_string(),
34 ],
35 uses_jmap: true,
36 jmap_session_url: Some("https://api.fastmail.com/jmap/session".to_string()),
37 imap_server: None,
38 imap_port: None,
39 smtp_server: None,
40 smtp_port: None,
41 userinfo_url: Some("https://api.fastmail.com/jmap/session".to_string()),
42 email_json_path: vec!["username"], // Fastmail uses "username" for email
43 },
44 }
45 }
46 }
47
48 impl OAuthProvider for FastmailProvider {
49 fn id(&self) -> &'static str {
50 "fastmail"
51 }
52
53 fn display_name(&self) -> &'static str {
54 "Fastmail"
55 }
56
57 fn config(&self) -> &OAuthProviderConfig {
58 &self.config
59 }
60
61 fn client_id(&self) -> &str {
62 &self.client_id
63 }
64
65 fn client_auth_method(&self) -> ClientAuthMethod {
66 // Fastmail uses PKCE, no client secret needed
67 ClientAuthMethod::ClientIdOnly
68 }
69
70 // Uses default exchange_code, refresh_token, get_user_email implementations
71 }
72