Subject: Re: bug#78366: 30.1; auth-source-xoauth2-plugin conflicts with multiple Google accounts

From: Anush V <[email-masked]>
Date: Mon, 12 May 2025 19:49:14 -0400

> From: Xiyue Deng <[email-masked]>
> Date: Sat, 10 May 2025 20:36:25 -0700
>
> Hi Anush,
>
> Anush V <[email-masked]> writes:
>
>> Hello Emacs maintainers,
>>
>> I have two google mail accounts, the first one uses app passwords to
>> authenticate, and the other uses oauth (because it doesn't support app
>> passwords)
>>
>> When I enable auth-source-xoauth2-plugin-mode, I’m able to send email
>> from second account without any issues.  But i’m unable to send emails
>> from the first account.  When I disable auth-source-xoauth2-plugin i’m
>> able to send email from the first account.
>>
>> I think that enabling xoauth2 shouldn't interfere with other
>> authentication methods, so this could be a bug.
>>
>> Thank you for your time
>>
>> * * *
>>
>> In GNU Emacs 30.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.43,
>> cairo version 1.18.2)
>> System Description: Guix System
>>
>> Configured using:
>>  'configure
>>  CONFIG_SHELL=/gnu/store/m0xdsa8cfq6mq1kxgxmpmpg71la4f0b9-bash-minimal-5.1.16/bin/bash
>>  SHELL=/gnu/store/m0xdsa8cfq6mq1kxgxmpmpg71la4f0b9-bash-minimal-5.1.16/bin/bash --prefix=/gnu/store/lq0nwm8qkj9cmyjm85z3dcqrjnglhcym-emacs-next-pgtk-30.1-rc1-2.7144e84 --enable-fast-install --with-pgtk --with-cairo --with-modules --with-native-compilation=aot --disable-build-details'
>>
>> --
>> Regards,
>> Anush
>>
>>
>
> Thanks for your report!  Ideally auth-source-xoauth2-plugin should only
> be in effect when your auth-source entry has "auth" set to "xoauth2".
> Can you check whether you happen to set that for your auth-source entry
> for the account using app password?  Sharing your auth-source entries
> with your personal information removed would be helpful.
>
> It would also help to share some of the error logs following instruction
> in the "Debugging" section in README.org[1].  Please be careful not to
> share any personal information from the logs.
>
> [1]
> https://gitlab.com/manphiz/auth-source-xoauth2-plugin/-/blob/main/README.org?ref_type=heads

I did some debugging.  According to comment “;; A string result is an
error.” in the function smtpmail-try-auth-methods, the function call
(smtpmail-try-auth-method process 'xoauth2 "user" "password") should
return a string when authentication fails.  However, it currently
returns a list instead, which prevents other authentication methods
from being tried.

As requested,

auth source entries.

     # for first account (app password authentication)
     machine imap.gmail.com login <first_email> port 993 password <app password>
     machine smtp.gmail.com login <first_email> port 587 password <app password>

     # second account (xoauth2 authentication)
     machine imap.gmail.com user <second_email> port 993 auth xoauth2 auth-url https://accounts.google.com/o/oauth2/auth token-url https://accounts.google.com/o/oauth2/token client-id <client_id> client-secret <client_secret> redirect-uri http://localhost scope https://mail.google.com
     machine smtp.gmail.com user <second_email> port 587 auth xoauth2 auth-url https://accounts.google.com/o/oauth2/auth token-url https://accounts.google.com/o/oauth2/token client-id <client_id> client-secret <client_secret> redirect-uri http://localhost scope https://mail.google.com

Logs when I send email from account with app password
(auth-source-xoauth2-plugin-mode enabled):

     Gnus is unplugged; really send queue? (y or n) y
     Sending message 1 of 1...
     Sending via mail...
     auth-source-search: found 4 backends matching (:max 1 :host "smtp.gmail.com" :port "587")
     Advising auth-source-search
     auth-source-netrc-parse: using CACHED file data for <path_to_authinfo.gpg>
     auth-source-search-backend: got 1 (max 1) in netrc:<path_to_authinfo.gpg> matching (:max 1 :host "smtp.gmail.com" :port "587")
     Matched auth data: (:host "smtp.gmail.com" :user "<second_email>" :port "587" :auth "xoauth2"
            :auth-url "https://accounts.google.com/o/oauth2/auth"
            :token-url "https://accounts.google.com/o/oauth2/token"
            :client-id
            "<client_id>"
            :client-secret "<client_secret>"
            :redirect-uri "http://localhost" :scope
            "https://mail.google.com")

     :auth set to ‘xoauth2’.  Will get access token.
     Using oauth2 to auth and store token...
     Decrypting <oauth2.plstore>...done
     oauth2 token: #s(oauth2-token
        [#<buffer  plstore
                   <oauth2.plstore>>
                   (("<string1>"
                     :secret-access-token t :secret-refresh-token t
                     :secret-access-response t))
                   nil
                   (("<string1>"
                     :access-token
                     "<string4>"
                     :refresh-token
                     "<string3>"
                     :access-response
                     ((access_token
                       . "<string5>")
                      (expires_in . 3599)
                      (refresh_token
                       . "<string3>")
                      (scope . "https://mail.google.com/")
                      (token_type . "Bearer"))))
                   (("<string1>"
                     :access-token
                     "<string4>"
                     :refresh-token
                     "<string3>"
                     :access-response
                     ((access_token
                       . "<string5>")
                      (expires_in . 3599)
                      (refresh_token
                       . "<string3>")
                      (scope . "https://mail.google.com/")
                      (token_type . "Bearer"))))]
        "<string1>"
        "<client_id>"
        "<client_secret>"
        "<string4>"
        "<string3>"
        "https://accounts.google.com/o/oauth2/token"
        ((access_token
          . "<string5>")
         (expires_in . 3599)
         (refresh_token
          . "<string3>")
         (scope . "https://mail.google.com/") (token_type . "Bearer")))

     Refreshing token...
     Contacting host: accounts.google.com:443
     Saving file <oauth2.plstore>...
     Wrote <oauth2.plstore>
     Refresh successful.
     oauth2 token after refresh: #s(oauth2-token
        [#<buffer  plstore
                   <oauth2.plstore>>
                   (("<string1>"
                     :secret-access-token t :secret-refresh-token t
                     :secret-access-response t))
                   nil
                   (("<string1>"
                     :access-token
                     "<string2>"
                     :refresh-token
                     "<string3>"
                     :access-response
                     ((access_token
                       . "<string5>")
                      (expires_in . 3599)
                      (refresh_token
                       . "<string3>")
                      (scope . "https://mail.google.com/")
                      (token_type . "Bearer"))))
                   (("<string1>"
                     :access-token
                     "<string2>"
                     :refresh-token
                     "<string3>"
                     :access-response
                     ((access_token
                       . "<string5>")
                      (expires_in . 3599)
                      (refresh_token
                       . "<string3>")
                      (scope . "https://mail.google.com/")
                      (token_type . "Bearer"))))]
        "<string1>"
        "<client_id>"
        "<client_secret>"
        "<string2>"
        "<string3>"
        "https://accounts.google.com/o/oauth2/token"
        ((access_token
          . "<string5>")
         (expires_in . 3599)
         (refresh_token
          . "<string3>")
         (scope . "https://mail.google.com/") (token_type . "Bearer")))

     Updating :secret with access-token: <string2>
     Updating auth-source-search results.
     auth-source-search: found 1 results (max 1) matching (:max 1 :host "smtp.gmail.com" :port "587")
     auth-source-search: found 4 backends matching (:host "smtp.gmail.com" :port "587" :user "<first_email>" :max 1 :require nil :create nil)
     Advising auth-source-search
     auth-source-netrc-parse: using CACHED file data for <path_to_authinfo.gpg>
     auth-source-search-backend: got 1 (max 1) in netrc:<path_to_authinfo.gpg> matching (:host "smtp.gmail.com" :port "587" :user "<first_email>" :max 1 :require nil :create nil)
     Matched auth data: (:host "smtp.gmail.com" :user "<first_email>" :port "587"
            :secret
            #[0 "<secret1>"
                [(nil)
                 "<string6>"
                 auth-source--deobfuscate]
                3])

     Updating auth-source-search results.
     auth-source-search: found 1 results (max 1) matching (:host "smtp.gmail.com" :port "587" :user "<first_email>" :max 1 :require nil :create nil)
     smtpmail-send-it: Sending failed: 535-5.7.8 Username and Password not accepted. For more information, go to
     535 5.7.8  https://support.google.com/mail/?p=BadCredentials <string6> - gsmtp

Logs when I send email from account with app password
(auth-source-xoauth2-plugin-mode disabled):

     Auth-Source-Xoauth2-Plugin mode disabled
     Gnus is unplugged; really send queue? (y or n) y
     Sending message 1 of 1...
     Sending via mail...
     auth-source-search: found 1 CACHED results matching (:max 1 :host "smtp.gmail.com" :port "587")
     auth-source-search: found 1 CACHED results matching (:host "smtp.gmail.com" :port "587" :user "<first_email>" :max 1 :require nil :create nil)
     Sending email
     Sending email done
     Sending...done
     No more newsgroups

--
Regards,
Anush