From 70034d4cb92a7c3c9c0589e15ee47299d41117e6 Mon Sep 17 00:00:00 2001 From: William Carroll Date: Tue, 4 Feb 2020 22:54:47 +0000 Subject: [PATCH] Begin supporting Monzo OAuth 2.0 login flow What's done: - Basic support of the client authorization grant stage of the OAuth login flow: - Open Google Chrome to point the user to Monzo's client authorization page. - Created a web server to retrieve the authorization code from Monzo. What's left: - Pulling the authorization grant (i.e. code) from Monzo's request and exchanging it for an access token and a refresh token, which can be used to make subsequent requests. Unanswered question: - Assuming this is a stateless app, where should I store the access token and refresh token to avoid the authorization flow. I'd like to avoid the client authorization flow because ideally I could run this app as a job that runs periodically throughout the day without requiring my interactions with it. Some interesting notes: - Notice how in the .envrc file, it's possible to make calls to `pass`. This allows me to check in the .envrc files without obscuring their content. It also allows me to consume these values in my app by using `os.Getenv("client_secret")`, which I find straightforward. Overall, I'm quite pleased to have stumbled upon this pattern - assuming that it's secure. --- monzo-ynab/.envrc | 2 ++ monzo-ynab/main.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 monzo-ynab/.envrc create mode 100644 monzo-ynab/main.go diff --git a/monzo-ynab/.envrc b/monzo-ynab/.envrc new file mode 100644 index 000000000..6a45e34bd --- /dev/null +++ b/monzo-ynab/.envrc @@ -0,0 +1,2 @@ +export client_id="$(pass show finance/monzo/client-id)" +export client_secret="$(pass show finance/monzo/client-secret)" diff --git a/monzo-ynab/main.go b/monzo-ynab/main.go new file mode 100644 index 000000000..f5c9e9cbb --- /dev/null +++ b/monzo-ynab/main.go @@ -0,0 +1,41 @@ +// Creating a job to import Monzo transactions into YNAB. +// +// This is going to run N times per 24 hours. + +package main + +import ( + "fmt" + "log" + "net/http" + "os" + "os/exec" +) + +var ( + clientId = os.Getenv("client_id") + clientSecret = os.Getenv("client_secret") +) + +const ( + state = "xyz123" + redirectUri = "http://localhost:8080/authorize" +) + +func handleRedirect(w http.ResponseWriter, r *http.Request) { + fmt.Println(r) + fmt.Fprintf(w, "Ackified") +} + +func authorizeClient() { + url := + fmt.Sprintf("https://auth.monzo.com/?client_id=%s&redirect_uri=%s&response_type=code&state=:state", + clientId, redirectUri, state) + exec.Command("google-chrome", url).Start() +} + +func main() { + authorizeClient() + http.HandleFunc("/authorize", handleRedirect) + go log.Fatal(http.ListenAndServe(":8080", nil)) +}