Oauth2 Part 2
Findings for part 2
Part one here
ApprovalForce
url := a.conf.AuthCodeURL("state", oauth2.AccessTypeOffline, oauth2.ApprovalForce)
this line fixes everything. If you dont use the ApprovalForce
option then a refresh_token isn’t created in the token that is returned.
With this token we can now load the token from a file, check the expiry, and create a new token source from that token to create a new valid token.
Google API hates numbers
Under ‘API & Services’ -> Credentials Tab is where you create the OAuth2 Client Ids. In there you specify what Authorized redirect URI’s you want to use. For whatever reason, probably a good one, they do not like using IP’s. Since we need to test against a remote machine running Nester, that means we need some DNS. More on that later.
Link out to OAuth2 Approval Flow
// openBrowser(url)
fmt.Println(url)
That’s all the code change needed to remove the browser opening and instead print the link to follow and initiate the Auth Flow.
Down the rabbit hole
So those parts above basically solve most of the issues caused by the Go OAuth2 library(or my lack of reading ability). Now we get a refresh token that we store locally to use for auth when needed and after the initial login flow, we just run nester run
on whatever interval we want and that spits our metrics to influxdb. Sweet.
Except, testing this and also setting was a pain in the ass. Now to make this work remotely, we need a public DNS record that points back to our server running the nester cli
. I luckily have a bunch of random domains that I bought over the years and thought it was a perfect time to pull out the poop.software
domain. Ok, easy part done. Now we need an SSL certificate because Google hates fun. Rather than buy a cert or worse, buy a wildcard - I decided on using Let’s Encrypt. Eventually, but probably not, we could add the functionality into the cli tool to expose an endpoint with a cert and grab one with Let’s encrypt blah blah. We’re on a mission to get this working so that’s future me problems.
This time we will just use Caddy as a TLS reverse proxy. It can autogenerate the SSL cert we need for our domain, we just have to add a few steps.
Step 1 - Get Namecheap API credentials
This parts pretty straightforward. Using Namecheap we need to generate some API creds so that Caddy can use those for the Let’s Encrypt calls for our cert. Intro docs are here and they’re easy to follow. At the end of it you should have these 3 things:
- Username
- API Key
- IP Address(What your public IP address is)
If you need an easy way to grab that just run curl icanhazip.com
and go with that.
Step 2 - Custom Build Caddy Server
We can’t just use the default caddy server because we need a way for it to use our Namecheap credentials so that it can create a txt verification record for Let’s Encrypt. This isn’t as bad as it seems, they have some good tooling for it.
You need to go get xcaddy and install that(I used the go install
method). Once you have that installed, you can run:
GOOS=linux GOARCH=amd64 xcaddy build --with github.com/caddy-dns/namecheap
This will output the binary for x86_64 linux
, which is what the server runs. Obviously use whatever env vars for you build environment you need. That command will spit out a binary that’s patched for Namecheap Let’s Encrypt. So move that binary to your server and create a Caddyfile:
nester.poop.software {
reverse_proxy localhost:8080
tls {
dns namecheap {
api_key AWESOME_API_KEY
user MUH_USERNAME
api_endpoint https://api.namecheap.com/xml.response
client_ip IP_ADDRESS_PLZ_DONT_HACK_ME
}
}
}
Pretty simple config here. Top part is our domain name we want the server to listen on. Set to reverse proxy to localhost:8080 which is where the nester
tool listens to receive the token back after sending the code and the user going through the auth flow. The tls
section just copy pasta your api key, username, and ip you setup for namecheap and we should be good.
Cool, so now the flow is this:
- Run
nester run
and it returns a url to open in your browser - You go through the google auth flow which then creates a token with a refresh token.
- The redirect url is now
https://nester.poop.software
which points to a local IP on the network. - That server on that IP is listening on port 443 as a reverse proxy to the nester listener on
localhost:8080
. - Now the return token has a path back to the nester cli to be able to save the token locally.
Step 2.1 - Linux aside
Oh don’t forget to add firewall rules to your server to allow 80/443 inbound:
sudo firewall-cmd --list-all
sudo firewall-cmd --zone=public --permanent --add-service=http
sudo firewall-cmd --zone=public --permanent --add-service=https
sudo firewall-cmd --reload
Also influxDB if you want to get to the server ui:
sudo firewall-cmd --zone=public --permanent --add-port 8086/tcp
sudo firewall-cmd --reload
Step 3 - Setup InfluxDB
Easiest way to get moving is to use docker-compose. I won’t go over any docker stuff here, google around there’s enough info on it. Here’s my compose file:
version: "3"
services:
influxdb:
restart: always
container_name: influxdb2
image: influxdb:2.7
ports:
- "8086:8086"
- "8088:8088"
volumes:
- influxdb-storage:/var/lib/influxdb
environment:
- INFLUXDB_DB=${INFLUXDB_DB}
- INFLUXDB_HTTP_AUTH_ENABLED=${INFLUXDB_HTTP_AUTH_ENABLED}
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=${INFLUXDB_ADMIN_USER}
- DOCKER_INFLUXDB_INIT_PASSWORD=${INFLUXDB_ADMIN_PASSWORD}
- DOCKER_INFLUXDB_INIT_ORG=${INFLUXDB_ORG}
- DOCKER_INFLUXDB_INIT_BUCKET=${INFLUXDB_BUCKET}
#- DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=${INFLUXDB_ADMIN_TOKEN}
- INFLUXDB_LOGGING_LEVEL=debug
- INFLUXDB_DATA_QUERY_LOG_ENABLED=true
volumes:
influxdb-storage:
And my .env
file - This is automatically picked up by docker-compose
#influxdb
INFLUXDB_HTTP_AUTH_ENABLED=true
INFLUXDB_ADMIN_USER=admin
INFLUXDB_ADMIN_PASSWORD=admin
INFLUXDB_DB=nester
INFLUXDB_ORG=nester
INFLUXDB_BUCKET=nester
INFLUXDB_USERNAME=donald
INFLUXDB_PASSWORD=donald
INFLUXDB_ADMIN_TOKEN=donaldadminsecret
Feel free to change those as needed :D
Step 4 - Finish line
So now you’ll have to go into the InfluxDB UI and create a token to use for nester to push to. In the .nester.yaml
file there are fields there to fill in and test it out.
Conclusion
So after this long and ridiculous adventure, we have a tool that can run in a cron, grab data from the Nest API, and push it to an InfluxDb using OAuth2. Now to actually clean this thing up, add some logging, maybe figure out how to deploy all this from Github using Tailscale. Next post will be about nester in general, the design, code, etc.