DEV Community

Cover image for Bypassing GitHub's OAuth flow
Paulo Renato
Paulo Renato

Posted on

Bypassing GitHub's OAuth flow

Cover image credit goes to the Author of the blog, Tedy Katz

In this article from Teddy Katz we can understand how Github OAuth can be bypassed by abusing the HTPP HEAD requests, and how the culprit his in part a feature of the framework being used, that implements a behaviour for making easier the developer life, but that can backfire.

TLDR

Same endpoint for the Authorization page and Authorize button

Interestingly, the endpoint URL for the “Authorize” button is /login/oauth/authorize, which happens to be the same as the URL for the authorization page itself. GitHub figures out which response to send based on the HTTP request method (GET requests return the HTML authorization page, and POST requests grant permissions to the app).
This behavior switch actually happens within application code. The router forwards both GET and POST requests to the same controller:

Abusing the HEAD requests to Bypass Github OAuth flow

What happens if we send an authenticated HEAD request to https://github.com/login/oauth/authorize? We’ve concluded that the router will treat it like a GET request, so it will get sent to the controller. But once it’s there, the controller will realize that it’s not a GET request, and so the request will be handled by the controller as if it was an authenticated POST request. As a result, GitHub will find the OAuth app specified in the request, and grant it access to the authenticated user’s data.

Why is this even possible?

Naturally, people writing web apps usually don’t want to take the time to implement behavior for HEAD requests. Getting a product that works is understandably considered more important than compliance with niche parts of the HTTP spec. But in general, it’s nice if HEAD requests can be processed correctly, provided that app developers don’t have to deal with them manually. So Rails (along with some other web frameworks) implements a clever hack: it tries to route HEAD requests to the same place as it would route GET requests. Then it runs the controller code, and just omits the response body.

Let's Discuss

Do you will start looking into how HTTP HEAD requests are handled by your framework of choice?

Top comments (0)