Setting up Google OAuth on Minikube
Minikube is an easy-to-use, high-fidelity Kubernetes distribution that can be run locally. It’s super useful for developing, testing and working with Kubernetes locally.
However, since minikube is running locally instead of on a cloud provider, certain provider-specific features do not work out of the box. More so, setting up some 3rd party services like OAuth can require some tweaking to get them to work locally.
I’ll discuss the challenge with one of such service, Google OAuth and a solution to it.
This, in itself, requires no introduction but the challenge of setting it up for local development in minikube does. Before I point out the problem, let’s quickly set up a simple app that uses Google OAuth for authentication.
In the spirit of full disclosure, I also used this project as an excuse to try out the Crystal programming language. You can check out the code here.
The overview of the Google OAuth process is:
- Redirect user to Google’s OAuth 2.0 server. The OAuth 2.0 server authenticates the user and obtains consent from the user for your application to access the user’s data
- Google’s OAuth 2.0 server redirects the user back to your application along with a single-use authorization code
- Exchange this authorization code for an access token
- Use the access token to call Google APIs
Let’s run the app to confirm all is well at this stage. If you cloned the repo, be sure to have crystallang installed and run
shards install within the repo folder to install the app dependencies. To start the app run
crystal run src/simple-auth.cr
Click the login button to try out the authentication flow after which you should end at a page with your picture and username.
Note that you would need to create web application credentials and export the client_id and client_secret as environment variables. I’ve added a
start.sh script which you can update with the values of your client id and secret. Then you can start the app:
chmod +x start.sh ./start.sh
Now to the problem
For web server requests, Google OAuth requires a list of all the callback URLs.
This is the path in your application that users are redirected to after they have authenticated with Google.
For simple web apps, specifying say, localhost is enough but not so with dockerized web apps. To understand this, let’s proceed to dockerize our app and run it in kubernetes.
The following steps assume you have docker and minikube installed and running.
Let’s set up minikube so that we can reuse minikube’s built-in Docker daemon; this allows us to build our image directly inside minikube’s docker daemon and not that on the host machine.
eval $(minikube docker env)
Next we build the image
docker build — tag xovox/simple-auth:0.0.1 .
Then we create a kubernetes deployment
kubectl run simple-auth --image=xovox/simple-auth --port=3000 --env="OAUTH_CLIENT_ID=[your client id here]" --env="OAUTH_CLIENT_SECRET=[your secret here]"
This creates a new deployment named simple-auth. The deployment creates a ReplicaSet which creates a pod from the image specified. So all we need to do is tell it the image we want to run and what port the container is expecting traffic on.
Next, we expose our deployment using a service
kubectl expose deployment simple-auth --port=3000 --target-port=3000 --type=NodePort
This will expose our service on a high level port across all nodes (default to 30000–32767).
Now let’s checkout our efforts by visiting our running app on the browser. Minikube provides a handy command for accessing services exposed via a node port:
minikube service [service-name]
minikube service simple-auth
This opens the service in the browser. Alternatively, you can append —-url to have the service address printed to the console.
If we try to log in now, we get an error that nothing is running on localhost.
This is true, and if you check the source code here it expects a HOST env variable which is used to build the callback URL and when not provided, as is this case now, it defaults to
localhost. To fix this, let’s get the minikube URL for the service
minikube service simple-auth --url and set it as an env variable for the deployment.
The URL for the service on my machine is
192.168.99.100:30144. Note that it might differ on your machine.
Delete the deployment
kubectl delete deployment simple-auth
Redeploy providing the env variable
kubectl run simple-auth --image=xovox/simple-auth --port=3000 --env="HOST=192.168.99.100:30144" --env="OAUTH_CLIENT_ID=[your client id here]" --env="OAUTH_CLIENT_SECRET=[your secret here]"
kubectl apply -f minikube/deployment.yaml
Now we have a different error when trying to log in and that is the error we are going to solve.
At first the obvious solution would be to add service URL to the OAuth list of callback URLs but amongst the many dissatisfactions with this approach, the most deterring is that, unfortunately, Google isn’t happy with it. Yup, it’s no no to private IPs. More so adding the IP to the OAuth list results in an error:
The solution would be to setup an entry in our /etc/hosts file to route requests to a static hostname, e.g simple-auth.me, to our cluster. Let’s set this up
echo "$(minikube ip) simple-auth.me" | sudo tee -a /etc/hosts
This adds a mapping from simple-auth.me to your minikube IP in your /etc/hosts file.
Then setup ingress on your minikube setup. You can follow the process outlined here.
Here's the ingress file
We should able to visit simple-auth.me and view the login page.
Finally, let’s add simple-auth.me to our callback URL listing in google console and update the HOST env variable for our deployment.
This setup is not exclusive to only Google OAuth. It’s pretty useful for any 3rd party (OAuth) service that requires a fixed host address in your apps requests.
I’ve included the deployment scripts for this in the repo. Do you have another suggestion, for testing OAuth locally? Lemme know in the comments.