Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
GitHub OAuth Busy Developer's Guide

GitHub OAuth Busy Developer's Guide

This is a quick guide to OAuth2 support in GitHub for developers. This is still experimental and could change at any moment. This Gist will serve as a living document until it becomes finalized at

OAuth2 is a protocol that lets external apps request authorization to private details in your GitHub account without getting your password. All developers need to register their application before getting started.

Web Application Flow

  • Redirect to this link to request GitHub access:
  • If the user accepts your request, GitHub redirects back to your site with a temporary code in a code parameter. Exchange this for an access token:

  • You have the access token, so now you can make requests on the user's behalf:

Javascript Flow

Disabled, for now...

Desktop flow

Disabled, for now...


  • (no scope) - public read-only access (includes user profile info, public repo info, and gists).
  • user - DB read/write access to profile info only.
  • public_repo - DB read/write access, and Git read access to public repos.
  • repo - DB read/write access, and Git read access to public and private repos.
  • gist - write access to gists.

Your application can request the scopes in the initial redirection:



technoweenie commented May 30, 2010

If you have questions about the document itself (typos, more references, suggestions, etc), post them here. If you want to discuss GitHub OAuth in general, see the API forum.

Do the access tokens expire? I don't see a refresh token returned.

How should I "check back in" with Github to ensure that the access token is still valid? Will the API calls fail in a clearly defined way when the access token is invalid?


technoweenie commented Jun 2, 2010

Tokens don't have to expire. From what I read about Facebook's implementation, they only send back the access token and an expiration if the offline_access scope is not requested. Right now, GitHub just assumes all apps want offline access.

atmos commented Jun 2, 2010

Are port numbers significant? I registered localhost:9393 and localhost:9292 works too.

@technoweenie: ok, thanks.


technoweenie commented Jun 2, 2010

Ah, I don't think I do much validation of the callback_uri. I should definitely do that. I wasn't exactly sure how the specs wanted to handle that though.

What's wrong with using a port number? I'm using that in one of my tests. I put myapp.local in my /etc/hosts and registered an app here for http://myapp.local:8080/auth/github-callback.

atmos commented Jun 2, 2010

I'm using a port number as well, the problem is that there's no port validation happening on the github side. I'm not familiar enough with oauth to know whether or not it should validate that the port number is correct which is why I asked.

Try running your app on 8181 and you'll see that your keys work there too.


technoweenie commented Jun 2, 2010

I'll probably add uri validation. So if you have

However, I don't think the specs are super clear on what to do in that case.


technoweenie commented Jun 3, 2010

I just added redirect uri validation, as well as support for the desktop flow.

catsby commented Jun 4, 2010

Where does the client secret come into play with the desktop workflow?


technoweenie commented Jun 5, 2010

You're right, this looks like a flaw in the specs. I'll read over them again and see if I missed something. I really don't like how they skip the temporary code process. There's no reason why JS or desktop apps couldn't make a second request to get the access token like the web server flow.

atmos commented Jun 7, 2010

Can we get deploy key access enabled for the oauth side of thigns too? It works with the login/token combo but not with the access_token.


technoweenie commented Jun 7, 2010

It'll probably be after RailsConf. I'm still in the process of auditing those API actions and sprinkling in OAuth support.


technoweenie commented Jun 12, 2010

The user_agent flow (used for js/desktop logins) is disabled for now. I need to figure out how to implement it properly according to spec.


technoweenie commented Jun 15, 2010

Clarified the user/repo/public_repo scopes. The repo and public_repo scopes are implemented for issue api calls, and repo deploy keys.

First of all, this is awesome! My use case is actually one which doesn't involve separating the user from the application, but just interacting with my own account via the API. Ideally I could use the OAuth client credentials flow to trade my API token for an access token?

atmos commented Jun 23, 2010

The normal access token should work just fine for your needs. Perhaps they're going to remove the token based auth in the future but it's probably better to familiarize yourself w/ the API and learn the OAuth side when you're building things for more than just yourself.


technoweenie commented Jun 23, 2010

I'd like to keep access token support around for personal use. There are some things we likely won't ever allow through OAuth, such as managing public keys and passwords. So right now, we don't plan to ever deprecate access tokens :)

If I'm understanding you correctly, this means that I can take my existing API token and use it as an OAuth 2.0 access token? If so, exactly what I was looking for.


technoweenie commented Jun 23, 2010

No, the API accepts your token without OAuth. See the Authentication section in

Think of OAuth as a way for an app to generate a new token for you that only works on that app.

sreeix commented Jun 25, 2010

Any update on the deploy key access to repository?
I tried to add deploy keys using oauth and get a 401

atmos commented Jun 25, 2010

I'm pretty sure you need to invalidate your current token and fetch a new one w/ the repo scope defined.

atmos commented Jul 25, 2010

I'm still seeing issues with fetching a user's public keys and adding deploy keys.


technoweenie commented Jul 28, 2010

Fixed a caching bug related to the tokens :) It wasn't storing the scopes right in memcache. As soon as CI comes back green, I'll deploy and clear existing oauth caches.

atmos commented Jul 29, 2010

Should /repos/pushable be returning unauthorized if you specified the repos scope?

What's the status of this? just gives me a 404


technoweenie commented Aug 17, 2010

It works fine, but still has a lot of rough edges. You need to pass a client_id and redirect_uri to that URL.

strange, I did that using the Oauth2 gem but it doesn't work, it seems to generate the wrong URL.

Manually entering the URL works, so must be something on my end.


OK I needed to add some extra params otherwise OAuth2 generates some standard URLs. This works for me

  opts = {
    :authorize_url    => '',
    :access_token_url => '',
    :site             => ''    
  @client ||=, GITHUB_SECRET, opts)

melo commented Oct 16, 2010

As a user, will I be able to give read-only access to my stuff?

Thats one of the things that I don't like with Twitter for example: a lot of apps would only need RO, but Twitter gives out RW tokens.

foca commented Nov 23, 2010

Does the API support creating post-receive hooks from there? I can't find documentation, but maybeeeee… :)

atmos commented Nov 23, 2010

@foca - i'm planning on adding that soon if i make the time for it.

fjakobs commented Nov 29, 2010

I'm trying to upload a ssh key with and OAuth access token. I'm attaching the "access_token" as parameter to the URL and send the key in the POST body. It looks right to me but I always get a 401 message back.

Is this API supposed to work with OAuth?

atmos commented Nov 30, 2010

@fjakobs We don't support uploading user's ssh keys with OAuth right now. At this point we're unsure if we'll ever add that feature to the API. Uploading deploy keys does work however.

fjakobs commented Dec 1, 2010

@atmos thanks for the information. Though I think uploading deploy keys has the same security implications as uploading public keys. Both give you read/write access to any repository. Either both should be allowed or both disallowed. What about adding an SSH OAuth scope?


technoweenie commented Dec 1, 2010

@kjakobs: Ah you're totally right about deploy keys! I thought they were readonly for some reason. I'll be removing them today.

I'm not sure we'll ever add support for key management in OAuth:

  • You rarely have to update keys.
  • Keys will be a thing of the past when Smart HTTP support in Git improves.

foca commented Dec 1, 2010

Noooooooooo!!!! :)

We're actually using OAuth to add deploy keys (and hopefully post-receive hooks, if Corey finds the time for that). Could you leave them there? :)

Once they are a thing of the past and there's an alternative, I'd be glad to transition to something different, but I would rather minimize the steps users have to go through, if possible :)



technoweenie commented Dec 1, 2010

Blah, I just realized the API lets you modify org teams and repo collaborators, so any discussion on public key is probably moot.

fjakobs commented Dec 1, 2010

What about reading public keys? It would be incredibly useful for us to be able to check if the user has already uploaded the key manually.

How can I revoke the applications access? I know this is beta, but still, you need to provide us with a way to let the users revoke access.
Edit: Just realized you can do this under 'connections' - this could be clearer.


technoweenie commented Jan 26, 2011

I just added the gist scope for creating gists, and support for accessing git objects on private repos.

jed commented Jan 27, 2011

so is there an API for writing to gists now?

Create a gist is Coming soon on


technoweenie commented Jan 27, 2011

Oh, I guess whoever added it never updated the docs. Just post to with the same fields as the web form. It's kind of weird, so maybe that's why it's not public yet :)

I would like to pull and push repositories using the access token that I get from OAuth so that the user doesn't have to trust our service with key-pairs. Will that ever be possible? At present I guess I need to create and deploy a key-pair on the users behalf and then store the private key in a safe place. The deploy method is
marked deprecated though, and that makes me a bit worried.

What does the future look like for services that want to push on behalf of a user?


technoweenie commented Feb 1, 2011

File a support issue if you have any more questions about OAuth and the API.

what is the expires_in of the GitHub token

antn commented Jul 8, 2013

The "register their application" link should point to, not

w1150n commented Jul 25, 2013

When will we be able to only grant access to specific private repos? Exposing access to all private repos is a deal-killer for us.

Yes, agree with w1150n. Is there any way to select private repos or at least provide a read-only permission for private repos ?? Thanks!

jperl commented Jul 27, 2013

+1 read-only specific private repo

Zeokat commented Mar 5, 2014

Zeokat says, thanks for the code. Deal with Oauth is oauughrrg.

+1 specified repos

Has the workflow changed recently? Trying to post on only gives me a Not Found error.

Same for me. Receive Not Found when trying to post on Does anybody know the reason?

+1 read-only private repo

Is the Javascript flow available now? It was much needed for me.

+1 for javascript flow

chadwithuhc commented Nov 12, 2016

For those getting 404 errors:

I had the same problem and ended up here. This was a solution to my problem:

function requestGithubToken(options, code) {
  let data = new FormData()
  data.append('client_id', options.client_id)
  data.append('client_secret', options.client_secret)
  data.append('code', code)
  fetch(``, {
    method: 'POST',
    body: data
  .then((response) => {
    return response.text()
  .then((paramsString) => {
    let params = new URLSearchParams(paramsString)
    console.log('access_token', params.get('access_token'))

Part of the problem was my data was sent as JSON and not FormData. Then dealing with the response I had to use URLSearchParams to pull out the access token.

+1 for sending as FormData instead of JSON. That should be more prevalent in the doc since everything else I seem to send it encoded JSON.

@chadwithuhc, ugh, thank you, spent a few hours on this (was sending JSON.stringify data too). this should most certainly be somewhere in docs.
FormData worked.

hey nice post but i want to ask something....
imagine that there are admin & client two user of application
admin set up client id and secrete for application then who will set the scope of the token
i mean admin or client ?

srph commented Jul 14, 2017

The FormData workaround for POST to doesn't seem to be working anymore - still getting a 404 pre-flight response. Any ideas why?

jeah... having the same on the preflight... like to know the solution

brianmcallister commented Sep 24, 2017

Remember to set the header Content-Type: application/json if you want to send JSON data.

tscanlin commented Oct 3, 2017

^ Thank you!

Add accept headers to get JSON back too

headers: {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment