Zapier and the OAuth2.0 Mountain

Background

Zapier is effectively a task runner. Integrating with them would put FlowMojo in a marketplace of other productivity applications. I think it will really fuel adoption. To get in the door with Zapier, I need to become an OAuth provider.

You can create a Zapier Application for your WebApp and give that to Zapier. Then, your users that also have Zapier accounts can go to Zapier and choose to make a ‘Zap’ with the Zapier Application you created. When your user decides to make a Zap that involves your application, Zapier will initiate an OAuth2.0 Authorization flow. Basically, you need to dance like a Google or Dropbox to play nice with Zapier.

After the Zap is created, Zapier will call it every 15 minutes on behalf of the user. The Zap is an ‘instance’ of the Zapier Application you created for your users and this instance is provided with the necessary credentials to act on behalf of one of your users.

Choices

There are a ton of ways to approach an OAuth2.0 flow, but given that the original author of OAuth wants nothing to do with it and has said that it is a bad protocol, I don’t want to put my brain power in to learning the internals. I don’t think OAuth2 is going away, but the points he made lead me to believe that I am not really capable of making a secure implementation. I need to favor functionality over exploration on this one.

I am going to go with Hydra. This is a standalone service that I can run as a docker container or binary on my EC2 instance. After suffering for a while, I went with the binary solution, though I still have all my container configuration should I want to go that route before I put this feature to bed.

Hydra

Hydra is an authorization server that might solve this for us.

This is a state machine representing the same flow.

A verbal explanation stolen and searched/replaced from Hydra Gitbook for our specific usecase:

  1. Peter wants to give Zapier access to his FlowMojo. Peter is the resource owner.
  2. The Authorization Server (Hydra) is responsible for managing the access request for Zapier. Hydra handles the communication between the resource owner, the consent endpoint, and the client. Hydra is the authorization server. In this case, FlowMojo would be the one who uses Hydra.
  3. Zapier is the client and was issued an id and a password by Hydra. Zapier uses these credentials to talk with Hydra.
  4. FlowMojo has a database and a frontend that allow their users to login, using their username and password. This is what an Identity Provider does.
  5. The User Agent is Peter’s FireFox.
  6. The Consent App is a frontend app that asks the user if he is willing to give Zapier access to his pictures stored on FlowMojo. It is responsible to tell Hydra if the user accepted or rejected the request by Zapier. The Consent App uses the Identity Provider to authenticate peter, for example by using cookies or presenting a user/password login view.

Sample App Implants

A consent app in the world of Hydra is the thing you login to. Think this:

There are two sample consent apps. Only the express one is on ory’s DockerHub :(

So I basically just took the consent app from the go example and worked it in to my project. That was pretty straight forward. They use gorilla too for routing so I was able to spin up another server and host the app like they did on 4445. Their documentation did not mention that you needed to run the sample application on port 4445, so that was a little frustrating.

After I proved that I could get my app to play like their app (communicate with a local instance of Hydra on 4444), I decided that I needed my production environment to work to proceed with the development of routes in the go app.

Push Many Things Directly to Production

I’m just going to make an unordered list of the things I had to do:

  • Create a migration for Hydra to ensure the table existed in my DB.
  • Make sure pressly/goose ran migrations from the Ansible context.
  • Upgrade to Go 1.9.2
  • Install Go Dep (because it’s finally ready).
  • dep init the project.
  • Run dep ensure in the Ansible context.
  • Create a systemd file for Hydra because I’m not running it as a docker container.

Go to Bed

This is where I’m leaving off today. What is left is to work the routes of the consent app in to my app and present clean endpoints to a service that wants to use them. My consent app will be mushed in to my main app but I’m not afraid of monoliths right now.

Gotchas

Environment

As of writing, the latest Hydra image is v0.10.10. I will be using that for the tutorial.

HTTPS Termination

I’m going to need to consider this… :(

HTTPS_ALLOW_TERMINATION_FROM: Whitelist one or multiple CIDR address ranges and allow them to terminate TLS connections. Be aware that the X-Forwarded-Proto header must be set and must never be modifiable by anyone but your proxy / gateway / load balancer. Supports ipv4 and ipv6. Hydra serves http instead of https when this option is set. Example: HTTPS_ALLOW_TERMINATION_FROM=127.0.0.1/32,192.168.178.0/24,2620:0:2d0:200::7/32=

Maybe not :)

Elastic Load Balancing stores the protocol used between the client and the load balancer in the X-Forwarded-Proto request header and passes the header along to your server.