Monday, March 25, 2024

out-of-band is officially out-of-bounds | Reviving emacs oauth2 with Google APIs

For months, I happily edited blog posts in Emacs using a tiny Blogger client I wrote in Elisp called hbo-blogger.el. hbo-blogger.el was easy to write, thanks in part to oauth2.el, which simplifies authentication against Google's Blogger API.

Things all came crashing down one day when I needed to re-authenticate using Google's OAuth2 server. I executed the following Elisp code, expecting it to open a browser, ask me a few questions, and show me a code I could paste back into Emacs.

(oauth2-auth-and-store
       "https://accounts.google.com/o/oauth2/v2/auth"
       "https://oauth2.googleapis.com/token"
       hbo-blogger-oauth-scope
       hbo-blogger-client-id
       hbo-blogger-client-secret)

However, this time I got an error announcing "Access blocked: Blur's request is invalid." Digging deeper took me to this page: Access blocked: Third-party app is using an unsupported OAuth method.

The issue is that oauth2.el sets up authentication using the redirect URL urn:ietf:wg:oauth:2.0:oob. The 'out-of-band' (oob) redirect URL handler works great when you are performing OAuth in a command-line or, in this case, an Elisp context. However, Google now denies this type of redirect URL.

Without a way to authenticate against the Blogger API, hbo-blogger was useless, and I was forced to go back to editing posts over at blogger.com.

What I needed were two things: support for a redirect URL that Google would be happy with, and a way to call oauth2.el using that new URL.

Good news: I now have both of these components, and if you want, you can have them too.

Setting up a Kosher OAuth2 Redirect Handler

First off, I built out oauth2handler. This is a bit of PHP code that runs on a publicly exposed Linux box. It allows you to set up a 'real' redirect URL without having to write any custom code. It serves as a sort of universal OAuth2 redirect URL.

Annoyingly, setting up oauth2handler takes about 12 steps. However, none of the steps are very hard; you just need to be patient.

With oauth2handler, I had a redirect URL. However, I needed a way to integrate this URL into oauth2.el. You can find the code for doing this over at oauth2handler.el.

Like oauth2handler (and heck, all things OAuth2), there's a heap of things to set up. But, once you've got everything properly defined, performing OAuth authentication is easy. Here's a function I can call to initialize the OAuth process:

;; Grab these values from the Google developer console.
(defvar hbo-blogger-client-id nil)
(defvar hbo-blogger-client-secret nil)

;; These can remain set to their defaults for blogger
(defvar hbo-blogger-oauth-scope
  "https://www.googleapis.com/auth/blogger")
(defvar hbo-blogger-oauth-auth-url
  "https://accounts.google.com/o/oauth2/auth")
(defvar hbo-blogger-oauth-token-url
  "https://www.googleapis.com/oauth2/v3/token")

;; Point this to your oauth2handler URL. For me, this is:
;; (setq hbo-blogger-oauth-redirect-url
;;      "https://code.benjisimon.com/oauth2handler/emacs_hbo")
(defvar hbo-blogger-oauth-redirect-url nil)

(defun hbo-blogger-auth-start ()
  "Start the Oauth2 authentication process in the browser"
  (interactive)
  (oauth2handler-start-auth
   hbo-blogger-oauth-redirect-url
   hbo-blogger-oauth-auth-url
   hbo-blogger-oauth-token-url
   hbo-blogger-oauth-scope
   hbo-blogger-client-id
   hbo-blogger-client-secret))

Running M-x oauth2handler-start-auth opens up a new web browser, and just like the 'oob' style of authentication, it prompts me to grant permission. The final page of oauth2handler displays a blob of JSON, similar to the code that the oob URL produces. I copy that JSON into an Emacs buffer that's been opened for me and hit C-c C-c.

Hitting C-c C-c generates the oauth2.plstore file that oauth2.el expects. From there, oauth2 and by extension hbo-blogger.el work again as they should.

In my .emacs.d/init.el file, I have the following settings and function call:

(require 'hbo-blogger)
(setq hbo-blogger-client-id  "<from the google developer's console>")
(setq hbo-blogger-client-secret "<from the google developer's console>")
(setq hbo-blogger-oauth-redirect-url
      "https://code.benjisimon.com/oauth2handler/emacs_hbo")

(hbo-blogger-auth-setup)

hbo-blogger-auth-setup uses oauth2.el's oauth2-auth-and-store function to set up a valid OAuth2 token. This token is what hbo-blogger.el uses to communicate with Blogger's API.

This whole process has been frustrating and exceedingly delicate. However, now that I've got oauth2handler and the corresponding Elisp code, life is good again. It feels good to be back home (editing in Emacs).

No comments:

Post a Comment