From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id A24A61FF141 for ; Tue, 05 May 2026 10:34:19 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id BCA8D1B750; Tue, 5 May 2026 10:33:39 +0200 (CEST) From: Arthur Bied-Charreton To: pve-devel@lists.proxmox.com, pbs-devel@lists.proxmox.com Subject: [PATCH docs/manager/proxmox{,-perl-rs,-widget-toolkit,-backup} v5 00/27] fix #7238: Add XOAUTH2 authentication support for SMTP notification targets Date: Tue, 5 May 2026 10:32:21 +0200 Message-ID: <20260505083248.36450-1-a.bied-charreton@proxmox.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.619 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [smtp.rs,lib.rs,pbs.rs,mod.rs,proxmox.com,xoauth2.rs,test.rs,proxmox-daily-update.rs,pve.rs,notify.rs,common.rs,notifications.pm] URI_TRY_3LD 1 "Try it" URI, suspicious hostname Message-ID-Hash: YA5ZMXINJ6AFKVBWNTH42KJUR3LCUTAT X-Message-ID-Hash: YA5ZMXINJ6AFKVBWNTH42KJUR3LCUTAT X-MailFrom: abied-charreton@jett.proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This series adds XOAUTH2 support for SMTP notification targets in PVE and PBS, motivated by Microsoft's upcoming deprecation of basic authentication for SMTP [0]. Google and Microsoft are supported as OAuth2 providers. The main challenge is the OAuth2 refresh tokens management. The implementations differ from provider to provider, and for Microsoft specifically, the token needs to be writable by proxmox-notify, since Microsoft 365/Copilot/... OAuth2 rotates it at every use. This series solves this by introducing state files, managed entirely in proxmox-notify. Each SMTP endpoint gets its own. Tokens are refreshed proactively in PVE's and PBS's respective daily update jobs under a notification config lock, in order to prevent concurrent config/state file updates. Provider-specific stuff: * Google: The token is refreshed in-place, meaning its lifetime is extended at every use without it being *actually* rotated [1]. The token in the state file does not change. Only the last_refreshed timestamp is updated in daily update jobs. * Microsoft: The token is rotated by Microsoft at each request, and each token has a fixed lifetime of 90 days [2]. While the recommendation is to persist the newly issued token right away, we would need to hold a lock each time a notification is sent in order to do so safely, and the rotation does not invalidate the old token. After some off-list discussion (thanks to all involved), we landed on only persisting the rotated token once a day, under a full notifications config lock. For access token requests in proxmox-notify, the oauth2 crate is used with a custom proxmox-http backend, which makes it easier to take proxy configs into account and avoids pulling in reqwest. Endpoints performing the initial authorization code -> refresh token exchange are added to PVE and PBS. It is not possible to do this directly from the UI, because Microsoft rejects browser-originated token requests. This series requires the following version requirement bumps: * proxmox-perl-rs -> bumped proxmox-notify * pve-manager -> bumped proxmox-widget-toolkit and proxmox-perl-rs * proxmox-backup -> bumped proxmox-widget-toolkit and proxmox-notify The UI part of the OAuth2 flow is opt-in for consumers, the widget toolkit may be bumped without bumping all products directly. Note that this introduces a breaking change in the proxmox-notify API. Changes since RFC: https://lore.proxmox.com/pve-devel/20260213160415.609868-1-a.bied-charreton@proxmox.com/ Changes since v1: https://lore.proxmox.com/pve-devel/20260325131444.366808-1-a.bied-charreton@proxmox.com/ Changes since v2: https://lore.proxmox.com/pve-devel/20260415070220.100306-1-a.bied-charreton@proxmox.com/ Changes since v3: https://lore.proxmox.com/pve-devel/20260421115957.402589-1-a.bied-charreton@proxmox.com/ Changes since v4: pve-docs, proxmox-backup/docs: * Remove the `/etc/hosts` hack for Google redirect URIs * Use example.com as example domain * Improve wording and fix typo * Document that from-address is used as SMTP authentication identity proxmox-notify: * Do not persist new refresh tokens while sending notification * Replace unwrap with `if let Some(...)` in State::save * Improve some doc comments * Create state files' parent directories with different options than the state file itself proxmox-backup,pve-manager: * Lock notifications config when updating notifications state in daily update jobs * Move initial authorization code -> refresh token exchange to the backend instead of hitting provider endpoints directly from the browser (Azure AD rejects browser-originated token requests) proxmox-widget-toolkit: * Reject before making the refresh token request if the authorization window does not return an authorization code * Delete `oauth2-refresh-token` if empty to prevent sending Some(""), which would overwrite an existing refresh token * Add refreshTokenUrl config field to SmtpEditPanel [0] https://techcommunity.microsoft.com/blog/exchange/updated-exchange-online-smtp-auth-basic-authentication-deprecation-timeline/4489835 [1] https://developers.google.com/identity/protocols/oauth2#expiration [2] https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens#token-lifetime proxmox: Arthur Bied-Charreton (9): add oauth2 and ureq to workspace dependencies notify: smtp: introduce xoauth2 module notify: smtp: introduce state management notify: smtp: factor out transport building logic notify: smtp: update API with OAuth2 parameters notify: smtp: add API to exchange authorization code for refresh token notify: smtp: infer auth method for backwards compatibility notify: smtp: add state handling logic notify: smtp: add XOAUTH2 authentication support Cargo.toml | 2 + proxmox-http/Cargo.toml | 2 +- proxmox-notify/Cargo.toml | 16 +- proxmox-notify/debian/control | 66 ++-- proxmox-notify/src/api/common.rs | 19 ++ proxmox-notify/src/api/smtp.rs | 203 ++++++++++-- proxmox-notify/src/context/mod.rs | 13 + proxmox-notify/src/context/pbs.rs | 24 ++ proxmox-notify/src/context/pve.rs | 26 +- proxmox-notify/src/context/test.rs | 23 ++ proxmox-notify/src/endpoints/smtp.rs | 236 ++++++++++++-- proxmox-notify/src/endpoints/smtp/xoauth2.rs | 310 +++++++++++++++++++ proxmox-notify/src/lib.rs | 40 ++- proxmox-openid/Cargo.toml | 2 +- 14 files changed, 885 insertions(+), 97 deletions(-) create mode 100644 proxmox-notify/src/endpoints/smtp/xoauth2.rs proxmox-perl-rs: Arthur Bied-Charreton (3): pve-rs: notify: smtp: add OAuth2 parameters to bindings pve-rs: notify: add binding for triggering state refresh pve-rs: notify: add binding for initial OAuth2 refresh token exchange common/src/bindings/notify.rs | 102 +++++++++++++++++----------------- 1 file changed, 50 insertions(+), 52 deletions(-) proxmox-widget-toolkit: Arthur Bied-Charreton (3): utils: add OAuth2 flow handlers utils: oauth2: add callback handler notifications: add opt-in OAuth2 support for SMTP targets src/Utils.js | 130 ++++++++++++++++ src/panel/SmtpEditPanel.js | 266 ++++++++++++++++++++++++++++++--- src/window/EndpointEditBase.js | 2 + 3 files changed, 374 insertions(+), 24 deletions(-) pve-manager: Arthur Bied-Charreton (5): notifications: smtp: api: add XOAUTH2 parameters notifications: add endpoint for initial OAuth2 refresh token exchange pveupdate: refresh notification targets' OAuth2 state login: handle OAuth2 callback fix #7238: notifications: smtp: add XOAUTH2 support PVE/API2/Cluster/Notifications.pm | 179 ++++++++++++++++++++++++++---- bin/pveupdate | 13 +++ www/manager6/Utils.js | 11 ++ www/manager6/Workspace.js | 2 + 4 files changed, 182 insertions(+), 23 deletions(-) proxmox-backup: Arthur Bied-Charreton (6): notifications: add XOAUTH2 parameters to endpoints notifications: add endpoint for initial OAuth2 refresh token exchange login: handle OAuth2 callback fix #7238: notifications: smtp: add XOAUTH2 support daily-update: refresh OAuth2 state for SMTP notification endpoints notifications: add OAuth2 section to SMTP targets docs docs/notifications.rst | 89 ++++++++++++++++++++++- src/api2/config/notifications/mod.rs | 1 + src/api2/config/notifications/smtp.rs | 101 +++++++++++++++++++++++++- src/bin/proxmox-daily-update.rs | 11 +++ www/Application.js | 4 +- www/OnlineHelpInfo.js | 8 ++ www/Utils.js | 2 + 7 files changed, 210 insertions(+), 6 deletions(-) pve-docs: Arthur Bied-Charreton (1): notifications: add OAuth2 section to SMTP targets docs notifications.adoc | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) Summary over all repositories: 30 files changed, 1789 insertions(+), 202 deletions(-) -- Generated by murpp 0.11.0