pax_global_header 0000666 0000000 0000000 00000000064 15056711723 0014521 g ustar 00root root 0000000 0000000 52 comment=2e6b36f3388be0c72b207b04a63776142a00c0c8
auth-source-xoauth2-plugin-0.3.1-2e6b36f3388be0c72b207b04a63776142a00c0c8/ 0000775 0000000 0000000 00000000000 15056711723 0024036 5 ustar 00root root 0000000 0000000 auth-source-xoauth2-plugin-0.3.1-2e6b36f3388be0c72b207b04a63776142a00c0c8/.gitignore 0000664 0000000 0000000 00000000046 15056711723 0026026 0 ustar 00root root 0000000 0000000 *-pkg.el
*-autoloads.el
*.elc
.eldev/
auth-source-xoauth2-plugin-0.3.1-2e6b36f3388be0c72b207b04a63776142a00c0c8/.gitlab-ci.yml 0000664 0000000 0000000 00000000655 15056711723 0026500 0 ustar 00root root 0000000 0000000 .build:
stage: build
script:
- curl -fsSL https://raw.github.com/emacs-eldev/eldev/master/bin/eldev > eldev && chmod a+x eldev
- ./eldev compile
- ./eldev lint
build-28.2:
image: "silex/emacs:28.2-ci"
extends: .build
build-29.4:
image: "silex/emacs:29.4-ci"
extends: .build
build-30.2:
image: "silex/emacs:30.2-ci"
extends: .build
build-master:
image: "silex/emacs:master-ci"
extends: .build
auth-source-xoauth2-plugin-0.3.1-2e6b36f3388be0c72b207b04a63776142a00c0c8/Eldev 0000664 0000000 0000000 00000000456 15056711723 0025025 0 ustar 00root root 0000000 0000000 ;;; -*- mode: emacs-lisp; lexical-binding: t -*-
(eldev-require-version "1.10")
(eldev-use-package-archive 'gnu)
(setf eldev-release-post-release-commit-message "Post-release version bump."
eldev-release-post-release-commit
#'eldev-release-next-snapshot-version-unless-already-snapshot)
auth-source-xoauth2-plugin-0.3.1-2e6b36f3388be0c72b207b04a63776142a00c0c8/NEWS.org 0000664 0000000 0000000 00000000746 15056711723 0025332 0 ustar 00root root 0000000 0000000 Summary of changes to auth-source-xoauth2-plugin
------------------------------------------------
* 0.3
** Add support for predefined credentials
This greatly simplifies the set-up in auth-source (details in
README.org).
* 0.2.1
** Quick fix for the wrong usage of add-to-list
* 0.2
** Workaround smtpmail limitations when handling xoauth2
* 0.1
** Initial release
Thanks Philip Kaludercic for the detailed comments and suggestions!
# Local variables:
# mode: outline
# End:
auth-source-xoauth2-plugin-0.3.1-2e6b36f3388be0c72b207b04a63776142a00c0c8/README.org 0000664 0000000 0000000 00000017205 15056711723 0025511 0 ustar 00root root 0000000 0000000 #+TITLE: Auth-source xoauth2 plugin
#+DATE: 2024-11-08
#+html:
* Introduction
This package provides a global minor mode for enabling support for
xoauth2 authentication with auth-source. OAuth 2.0, which stands for
“Open Authorization”, is a standard designed to allow a website or
application to access resources hosted by other web apps on behalf of
a user. The OAuth 2.0 Authorization Protocol Extensions (xoauth2)
extend the OAuth 2.0 Authentication Protocol and the JSON Web Token
(JWT) to enable server-to-server authentication. More info please
check out [[https://stackoverflow.com/a/76389679/2337550][this stackoverflow answer]].
* Installation
`auth-source-xoauth2-plugin' is on [[https://elpa.gnu.org/packages/auth-source-xoauth2-plugin.html][GNU ELPA]], and you can install it
with `package-install' (see also [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Package-Installation.html][the Emacs document on how to use
package-install]]). Or you can clone the repository from [[https://gitlab.com/manphiz/auth-source-xoauth2-plugin/][GitLab]], or
simply download the ~auth-source-xoauth2-plugin.el~ file and put it
anywhere in your Emacs' `load-path'.
Then add the following lines in your Emacs configuration:
#+BEGIN_SRC emacs-lisp
(require 'auth-source-xoauth2-plugin)
(auth-source-xoauth2-plugin-mode t)
#+END_SRC
or with use-package:
#+BEGIN_SRC emacs-lisp
(use-package auth-source-xoauth2-plugin
:custom
(auth-source-xoauth2-plugin-mode t))
#+END_SRC
After enabling, smtpmail should be supported. To enable this in Gnus
nnimap, you should also set `(nnimap-authenticator xoauth2)' in the
corresponding account settings in `gnus-secondary-select-methods' as
the following:
#+BEGIN_SRC emacs-lisp
(nnimap "account_name"
...
(nnimap-authenticator xoauth2)
...
)
#+END_SRC
To disable, just toggle the minor mode off by calling `M-x
auth-source-xoauth2-plugin-mode' again.
* auth-source settings
When xoauth2 authentication is enabled, it will try to get the
following data from the auth-source entry: `auth-url', `token-url',
`scope', `client-id', `client-secret', `redirect-uri', and optionally
`state'.
There are two ways to set those info:
1. Use a predefined source which has already registered their app to
the service (e.g. thunderbird) and you can just use their public
authentication info, such as `client_id', `client_secret', etc.
2. Register your own app for oauth2 authentication and set those info
yourself.
** Use predefined services
Using a predefined service is very easy. An example `authinfo' entry
(in JSON format as `~/.authinfo.json.gpg') for Gmail will look like
below (you need to fill in the info of your account between "<" and
">"):
#+BEGIN_SRC js
[
...
{
"machine": "",
"login": "",
"port": "imaps",
"auth": "xoauth2",
"auth-source-xoauth2-predefined-service": "google"
},
...
]
#+END_SRC
This will then use the OAuth2 credentials from Thunderbird for
authentication. Currently `google' and `microsoft' are supported from
Thunderbird for use with Gmail and Outlook which the author has
tested. It is possible to add support for more services (e.g. yahoo)
and other sources (e.g. Evolution). Suggestions and patches are
welcome.
Once correctly set up, the plugin will then use `oauth2.el' to
retrieve the access-token with those information, use it to construct
the oauth2 authentication string, and let `auth-source' do the rest.
** Use your own registered app
If you would like more control over your authentication credentials,
you can register your own app on your email service provider for
OAuth2 authentication. The registration process is outside the scope
of this document, but the gist is to make sure that you set the access
control of your app (also `scope') to enable using IMAP and SMTP for
email.
Once that's done, you can fill in the credentials from your app to
achieve the same. For an Gmail account it may look like below:
#+BEGIN_SRC js
[
...
{
"machine": "",
"login": "",
"port": "imaps",
"auth": "xoauth2",
"auth-url": "https://accounts.google.com/o/oauth2/auth",
"token-url": "https://accounts.google.com/o/oauth2/token",
"client-id": "",
"client-secret": "",
"redirect-uri": "https://oauth2.dance/",
"scope": "https://mail.google.com"
},
...
]
#+END_SRC
The rest will work in the same way.
*** Initial set up
Once auth-source is configured correctly, you can proceed to initiate
the connections. Please check out [[file:docs/oauth2-initial-set-up.org][the steps for initial set up]]. Once
everything goes through the plugin will handle the future
authentication automatically.
* Comparison with other xoauth2 implementations
** auth-source-xoauth2
This plugin takes inspirations from [[https://github.com/ccrusius/auth-source-xoauth2][auth-source-xoauth2]] to advice the
auth-source-search backends to add xoauth2 access-token for
authentication. The implementation is independent and reuses many
existing facilities in `auth-source.el', where auth-source-xoauth2
reimplemented most of the required functions itself.
`auth-source-xoauth2-plugin' also makes use of `oauth2.el' and its
storage for storing temporary/ephemeral data tokens, where
`auth-source-xoauth2' implemented its own storage.
* Debugging
In case you encounter any issues, you may consider enabling verbose
messages to help debugging. `auth-source-xoauth2-plugin' uses the
same convention as `auth-source' for outputing verbose messages. You
may do the following:
#+BEGIN_SRC emacs-lisp
(setq auth-source-debug t)
#+END_SRC
and check the =*Message*= buffer for logs. You can enable even more
verbose log by the following:
#+BEGIN_SRC emacs-lisp
(setq auth-source-debug 'trivia)
#+END_SRC
NOTE: \'trivia will include your tokens for authentication in your
=*Message*= buffer so be careful not to share the log with untrusted
entities.
* Bug reporting
Please use `M-x report-emacs-bug' or open an issue on [[https://gitlab.com/manphiz/auth-source-xoauth2-plugin/-/issues][GitLab]] and
include debug info collected following section [[file:README.org::*Debugging][Debugging]].
* Notes on Implementation
`auth-source' uses the `secret' field in auth-source file as password
for authentication, including xoauth2. To decide which authentication
method to use (e.g. plain password vs xoauth2), this plugin inspects
the `auth' field from the auth-source entry, and if the value is
`xoauth2', it will try to gather data and get the access token for use
of xoauth2 authentication; otherwise, it will fallback to the default
authentication method.
This package uses an advice to switch the auth-source search result
from the `password' to the `access-token' it got, which in turn will
be used to construct the xoauth2 authentication string, currently in
nnimap-login and smtpmail-try-auth-method. To enable xoauth2 support
in smtpmail, it adds \'xoauth2 to \'smtpmail-auth-supported (if it is
not already in the list) using `add-to-list' so that xoauth2 is tried
first.
Note that currently `auth-source' requires the searched entry must
have `secret' field set in the entry, which is not necessarily true
when using xoauth2. Therefore in the advice it temporarily disables
checking for `:secret' perform the search in the backend, and ensure
that `secret' contains the generated access-token before returning.
auth-source-xoauth2-plugin.el 0000664 0000000 0000000 00000025715 15056711723 0031436 0 ustar 00root root 0000000 0000000 auth-source-xoauth2-plugin-0.3.1-2e6b36f3388be0c72b207b04a63776142a00c0c8 ;;; auth-source-xoauth2-plugin.el --- Authentication source plugin for xoauth2 -*- lexical-binding: t -*-
;; Copyright (C) 2024-2025 Free Software Foundation, Inc.
;; Author: Xiyue Deng
;; Homepage: https://gitlab.com/manphiz/auth-source-xoauth2-plugin
;; Version: 0.3.1
;; Package-Requires: ((emacs "28.1") (oauth2 "0.18"))
;; This file is not part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see .
;;; Commentary:
;; An auth-source plugin to enable xoauth2 support.
;; This package provides a global minor mode for enabling xoauth2 in
;; auth-source. Once adding information required for xoauth2 authentication in
;; your auth-source file and enabling the global minor mode, one can
;; authenticate through xoauth2 to supported services, e.g. Gmail, etc.
;; See README.org for a more detailed introduction and usages.
;;; Code:
(require 'auth-source)
(require 'cl-lib)
(require 'map)
(require 'oauth2)
(require 'org)
(require 'smtpmail)
(defvar auth-source-xoauth2-plugin-predefined-issuers
'(thunderbird
(google
( :client-id "406964657835-aq8lmia8j95dhl1a2bvharmfk3t1hgqj.apps.googleusercontent.com"
:client-secret "kSmqreRr0qwBWJgbf5Y-PjSU"
:auth-url "https://accounts.google.com/o/oauth2/auth"
:token-url "https://www.googleapis.com/oauth2/v3/token"
:redirect-uri "http://localhost/"
:scope "https://mail.google.com/"
:use-pkce "true" )
microsoft
( :client-id "9e5f94bc-e8a4-4e73-b8be-63364c29d753"
;; :client-secret ""
:auth-url "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
:token-url "https://login.microsoftonline.com/common/oauth2/v2.0/token"
:redirect-uri "http://localhost"
:scope "https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send offline_access"
:use-pkce "true" ))))
(defvar auth-source-xoauth2-plugin-default-predefined-source "thunderbird"
"The default predefined issuers provider.")
(defun auth-source-xoauth2-plugin--get-predefined-credentials (source provider)
"Helper function to get the predefined credentials of PROVIDER from SOURCE."
(plist-get (plist-get auth-source-xoauth2-plugin-predefined-issuers
(intern source))
(intern provider)))
(defun auth-source-xoauth2-plugin--search-backends (orig-fun &rest args)
"Perform `auth-source-search' and set password as access-token when requested.
Calls ORIG-FUN which would be `auth-source-search-backends' with
ARGS to get the auth-source-entry. The substitution only happens
if one sets `auth' to `xoauth2' in your auth-source-entry. It is
expected that `token_url', `client_id', `client_secret', and
`refresh_token' are properly set along `host', `user', and
`port' (note the snake_case)."
(auth-source-do-trivia "[xoauth2-plugin] Advising auth-source-search")
(let (check-secret)
(when (memq :secret (nth 5 args))
(auth-source-do-trivia
(concat "[xoauth2-plugin] Required fields include :secret. As we are "
"requesting access token to replace the secret, we'll "
"temporary remove :secret from the require list and check that "
"it's properly set to a valid access token later."))
(setf (nth 5 args) (remove :secret (nth 5 args)))
(setq check-secret t))
(let ((orig-res (apply orig-fun args))
res)
(dolist (auth-data orig-res)
(auth-source-do-trivia "[xoauth2-plugin] Matched auth data: %s"
(pp-to-string auth-data))
(let ((auth (plist-get auth-data :auth))
(user (plist-get auth-data :user)))
(when (and (equal auth "xoauth2")
;; When sending mails, some auth-source query results from
;; some smtpmail authentication methods don't contain the
;; :user field (meanwhile queries from Gnus seems to always
;; include :user). When using predefined provider
;; credentials, only the :user field is different to
;; distinguish among different accounts, which is
;; unfortunately missing in certain cases. Fortunately,
;; smtpmail may set smtpmail-smtp-user to the user value
;; when X-Message-SMTP-Method is properly set. Therefore
;; additionally, assuming X-Message-SMTP-Method is set
;; correctly, we need to check whether smtpmail-smtp-user
;; is the same as :user to be sure.
(if smtpmail-smtp-user
(progn
(auth-source-do-trivia
"[xoauth2-plugin] user: %s, smtpmail-smtp-user: %s"
user smtpmail-smtp-user)
(string= smtpmail-smtp-user user))
t))
(auth-source-do-debug
(concat "[xoauth2-plugin] account \"%s\" has :auth set to "
"`xoauth2'. Will get access token.")
user)
(map-let (:auth-source-xoauth2-predefined-service
(:auth-source-xoauth2-predefined-source
auth-source-xoauth2-predefined-source
auth-source-xoauth2-plugin-default-predefined-source))
auth-data
(when auth-source-xoauth2-predefined-service
(auth-source-do-trivia
(concat "[xoauth2-plugin] Using service \"%s\" with "
"credentials provided by source \"%s\"")
auth-source-xoauth2-predefined-service
auth-source-xoauth2-predefined-source)
(setq auth-data
(org-combine-plists
auth-data
(auth-source-xoauth2-plugin--get-predefined-credentials
auth-source-xoauth2-predefined-source
auth-source-xoauth2-predefined-service)))))
(map-let (:host
:user
:auth-url
:token-url
:scope
:client-id
:client-secret
:redirect-uri
:state
:use-pkce)
auth-data
(auth-source-do-debug
"[xoauth2-plugin] Using oauth2 to auth and store token...")
(let ((token (oauth2-auth-and-store
auth-url token-url scope client-id client-secret
redirect-uri state user host use-pkce)))
(auth-source-do-trivia "[xoauth2-plugin] oauth2 token: %s"
(pp-to-string token))
(auth-source-do-debug "[xoauth2-plugin] Refreshing token...")
(oauth2-refresh-access token host)
(auth-source-do-debug "[xoauth2-plugin] Refresh successful.")
(auth-source-do-trivia
"[xoauth2-plugin] OAuth2 token after refresh: %s"
(pp-to-string token))
(let ((access-token (oauth2-token-access-token token)))
(auth-source-do-trivia
"Updating :secret with access-token: %s" access-token)
(setq auth-data
(plist-put auth-data :secret access-token))
;; Fill fields that may help 3rd party usage,
;; e.g. offlineimap.
(setq auth-data
(plist-put auth-data :auth-url auth-url))
(setq auth-data
(plist-put auth-data :token-url token-url))
(setq auth-data
(plist-put auth-data :client-id client-id))
(setq auth-data
(plist-put auth-data :client-secret client-secret))
(setq auth-data
(plist-put auth-data :access-token
(oauth2-token-access-token token)))
(setq auth-data
(plist-put auth-data :refresh-token
(oauth2-token-refresh-token token))))))))
(auth-source-do-debug "[xoauth2-plugin] auth-data after processing: %s"
(pp-to-string auth-data))
(unless (and check-secret
(not (plist-get auth-data :secret)))
(auth-source-do-debug
"[xoauth2-plugin] Updating auth-source-search results.")
(push auth-data res)))
res)))
(defvar auth-source-xoauth2-plugin--enabled-xoauth2-by-us nil
"Non-nil means `smtpmail-auth-supported' was set by us.")
(defun auth-source-xoauth2-plugin--enable ()
"Enable auth-source-xoauth2-plugin."
(unless (memq 'xoauth2 smtpmail-auth-supported)
;; smtpmail considers smtp request with a return value less than 400 to be
;; successful, but for Gmail when an xoauth2 request fails it returns 334
;; server challenge, and waiting for a subsequent request with the correct
;; credentials which will never happen. Putting 'xoauth2 as the last entry
;; in smtpmail-auth-supported so that it is tried last. See also
;; https://debbugs.gnu.org/78366.
(add-to-list 'smtpmail-auth-supported 'xoauth2 t)
(setq auth-source-xoauth2-plugin--enabled-xoauth2-by-us t))
(advice-add #'auth-source-search-backends :around
#'auth-source-xoauth2-plugin--search-backends))
(defun auth-source-xoauth2-plugin--disable ()
"Disable auth-source-xoauth2-plugin."
(when (and auth-source-xoauth2-plugin--enabled-xoauth2-by-us
(memq 'xoauth2 smtpmail-auth-supported))
(setq smtpmail-auth-supported (delq 'xoauth2 smtpmail-auth-supported))
(setq auth-source-xoauth2-plugin--enabled-xoauth2-by-us nil))
(advice-remove #'auth-source-search-backends
#'auth-source-xoauth2-plugin--search-backends))
;;;###autoload
(define-minor-mode auth-source-xoauth2-plugin-mode
"Toggle auth-source-xoauth2-plugin-mode.
Enable auth-source-xoauth2-plugin-mode to use xoauth2
authentications for emails."
:global t
:group 'auth-source
(if auth-source-xoauth2-plugin-mode
(auth-source-xoauth2-plugin--enable)
(auth-source-xoauth2-plugin--disable)))
(provide 'auth-source-xoauth2-plugin)
;;; auth-source-xoauth2-plugin.el ends here
auth-source-xoauth2-plugin-0.3.1-2e6b36f3388be0c72b207b04a63776142a00c0c8/docs/ 0000775 0000000 0000000 00000000000 15056711723 0024766 5 ustar 00root root 0000000 0000000 auth-source-xoauth2-plugin-0.3.1-2e6b36f3388be0c72b207b04a63776142a00c0c8/docs/oauth2-gmail-1.png 0000664 0000000 0000000 00000223464 15056711723 0030136 0 ustar 00root root 0000000 0000000 PNG
IHDR D+n sRGB, gAMA a cHRM z&