Frenchy Front-end Engineer

I'm working on an application in the browser that lets you take notes. I don't want to have the burden to save them on my own server therefore I want to use Github Gists as storage. The challenge is to be able to communicate with the Github API 100% inside the browser.

Login Phase

Phase 0 - Create an application

Before doing anything, you have to create a Github application. It will provide you the client_id and client_secret as well as an admin to put the redirect URL.

Phase 1 - Get authentication code

Using Github API OAuth guide we learn that we have to redirect the user to a page on github server. After the user authorizes the application, the page is redirected to one of our page with a code.

Since we do not want to leave the current page (it would make all the user changes vanish) we must open the page in another context. The first one I tried was an iframe but github has the X-Frame-Options header set that prevents embedding the page in the iframe.

So the other option was to open a new window. With window.open it was really easy to do so. The only tricky part was to actually give back the result to the main window. After digging, I found the following snippet of code that works well: window.opener.postMessage(message, window.location).

Phase 2 - Get access token

We are back in the main window and have the code. We now need to exchange this code for a token. I really wonder why they didn't give us the token already but well, there must be a reason! In order to get the token, we must send a POST request to a page on github.

However another difficulty comes in, this one page does not have a Access-Control-Allow-Origin header set to our domain. So basically, we cannot access it from the browser using AJAX. Since it's a POST request, we cannot even use JSON-P to bypass it.

I did not want to have a server but I am resigned to write a small PHP proxy that will forward the call. I believe that the main reason why they blocked it was because they ask for the client_secret. They don't want us to write it down in our Javascript in plain sight.

Phase 3 - Enjoy!

Now that we have got our token, we can call all the APIs on Github using post and get AJAX requests and they all work fine. One good thing is the fact that the token is permanent. Unless you change the permissions you request or the user revokes your application, every time the user logs in, he will be associated the same token.

You can safely store the token in the user's browser with localStorage in order to keep them logged when they come back to the application. Just make sure to catch 401 Unauthorized error on requests in case the token is no longer valid and ask the user to log in again.

Demo

And here's the demo! The source code is really small and available on github. If you plan to integrate an in-browser login, it can be used as a starting point.

Conclusion

At first glance, the login process seemed to be really straightforward, you just had 2 requests to get your code and token and you are good to go. But doing so in the browser revealed itself to be a lot harder. I'm not satisfied with the process as it involves many different technologies but that's the best I could find. If you handled things differently please tell me 🙂

Also if you had user name / password you could use that instead of OAuth in combination with trick above to work with private APIs.

http://blog.vjeux.com/ Vjeux

The public API can be used without OAuth but if you want to interact with user permissions, you sadly have to use it.
Asking people for their user and password is a solution that would not involve having a server but it's something I would like to avoid at all costs 🙂
Thanks for the reply!

Must i follow the 3 steps in each sign in process? : redirect to github and request for code, get the code and post to github for token , and then ,we can use token to get user's information. I just think this process takes too many steps, works slowly. Can i store the access_token ? I have tested that the code from github can only be used once.

Thus I guess the solution outlined here is the best we can think of. Thanks for finding it out.

Ken Power

thanks, that helped me out of a jam

testic

It seems that this demo is not working...

http://thebacklog.net/ dirkcuys

Thanks for sharing your experience. I was hoping to be able to do everything client side, maybe one day we'll get a client side compatible authentication flow for the web?

Related Posts

September 25, 2011Javascript Object Difference (5)This article is about a difference algorithm. It extracts changes from one version of an object to another. It helps storing a smaller amount of information.
Template
In a project, I have a template object with all the default settings for a widget.
var template = {
[…]

December 26, 2015Challenge: Best JavaScript Setup for Quick Prototyping (25)Yesterday, there was a big discussion on Twitter on how hard it is to start hacking on a js project. One comment by Dan Abramov struck me in particular: "Right: don’t use tools, face a problem, choose a tool or roll your own. Wrong: learn tools that don’t solve your problems, hate the […]

October 30, 2009Javascript – Dynamic Query Throttling (2)Working on the World of Raids Recruitment Tool we wanted automatic saving while editing. There are basically two ways of handling the problem.
Send update everytime something changes. The main advantage of this technique is that you are always up to date. However, it is spamming the […]

August 20, 2011Idea – mouseFreeze – A solution for Browser FPS Games (8)There is an open problem in porting real game into the web browser related to cursor handling.
Problem
Many games such as First-Person Shooters require the mouse to freely move, without the constraints of screen edges. However there is no such API in the browser to make this […]

February 18, 2013XSON – Smallest JSON equivalent in XML (4)It's often said that XML is very verbose and therefore JSON is better. I wanted to challenge that assumption and find the smallest way to represent any JSON value using XML.
table#xson { border-collapse: collapse; margin: 0 auto; }
table#xson td, table#xson th { border: 1px solid […]