Login with Github

Good afternoon,

I’ve been trying to use Github Issues as a commenting system for a static site created with Hugo and, if I understood correctly, for that I would need a Github Login so I can consume Github API after vistors’ authorization.

I tried to do it on my own, without relying on 3rd-party solutions whatsoever, but Github Docs is enormous and I confess I got lost. Then, a few hours ago, I met Auth0 almost by accident and thought it could help to ease the process.

I read this article and everything worked withing Auth0 Dashboard but how do I really implement it on my site? Every single example in Auth0 docs and the very few I’ve found in other sites are based on NodeJS, Angular, React (and so on). I can’t or, better saying, I don’t want to use NodeJS (nor the alternatives), just plain and simple HTML / JS (jQuery) but I simply can’t find any plausible material to study.

Can anyone help me?

Hi @josuehenrique,

Welcome to the Community!

You may have already found this quickstart, but if not, here is a just JS example app you can take a look at:

Spinning up the quickstart may be helpful, and please let us know if there is a particular spot your getting stuck. Thanks!

Hello, Stephanie, how are you doing? Hope you’re doing well, all things considered

I’ve found this article indeed and it seemed to be what I was looking for, 'til I reached the “Configure credentials” section because, as I said, it’s a static site, having such a file means nothing as what Hugo generates is HTML/CSS/JS and static files like images, fonts and etc.

If I could imagine a pseudo-code, it would be something like this (terminology used loosely, my apologies):

$( '#login_button' ).on( 'click', () => {

  const auth0 = new Auth0({
    "domain": "YOUR_DOMAIN",
    "clientId": "YOUR_CLIENT_ID"
  });

  const auth = auth0.connect( 'github', {
    identifier: `MY_GITHUB_SOCIAL_CONNECTION_ID`
  });

  if( auth ) {
      /* Authorized, do something */
  } else {
    /* Not authorized, do something else */
  }

});

So after clicking the login button visitor would be redirected to Auth0, then to Github, grant the Authorization (or not) then back to my page. Not really sure if that’s what actually happens, but I think you got my meaning.

But all I can find are examples based on NodeJS and alike but nothing for the “old-school” way. I don’t use NodeJS, I don’t even know if what Hugo generates can be used with NodeJS and even if they could be used together, in the end, the project will be hosted on Github Pages which is only HTML/CSS/JS and static files.

Thank you for your time

[EDIT]

I think I managed to make it work… in parts. Following the idea of the pseudo-code I imagined above I came up with this:

<script src="https://cdn.auth0.com/js/auth0/9.11/auth0.min.js"></script>

let auth = new auth0.WebAuth({
  domain: DOMAIN,
  clientID: CLIENT_ID,
  redirectUri: CALLBACK_URL,
});

$( '#login' ).on( 'click', () => {

  auth.authorize({
    connection: 'github',
    scope: 'email read:user user:follow notifications',
    responseType: 'code',
    returnTo: window.location.href
  });

  return false;
});

And, apparently, it’s working. I mean, I click the button, I’m redirected to the Github Authorization page and after authorized, I’m sent back to CALLBACK_URL/?code=<some_random_characters>&state=<more_random_characters> — which I suppose are the information I’ll use to consume Github API, but I’m not sure yet — and when I check Github’s OAuth Apps I see 1 user. :star_struck:

However, I have no ways to return to the page where the visitor (in this case, me, hehe) was at the moment the button was clicked.

After A LOT of reading and abstraction from React/NodeJS fragments I don’t understand a thing, apparently (and I confirmed in API docs later) I could add more parameters to the request (here represented by returnTo) but such parameter isn’t being passed to Github Authorization Page nor to my callback page, like, perhaps, CALLBACK_URL/?code=<some_random_characters>&state=<more_random_characters>&returnTo=PREVIOUS_URL

Then I thought about using popups so, at least, visitors wouldn’t be redirected away from the page they were, but I couldn’t find a working snippet because every single one of them yielded me errors like “popup function is not defined”.

How should I proceed?

My apologies for bumping this topic, but the previous answer was getting too long and this one would just add to it even more.

So, I believe I’m almost there. Since I couldn’t make Auth0 popup work whatsoever, then I made my own (omitted here, plenty of examples around the Web). The window opens and I see the Github Authorization page. After authorized, I’m redirected to my defined callback with both code and state present in the URL. From there I make another request to /oauth/token/ (from my tenent/domain) and successfully get an access_token :star_struck:

This is the code so far:

$( '#login' ).on( 'click', () => {

  const popup    = Request.popup( '/auth' );

  return false;
});

On /auth page:

<script type="text/javascript">

  $( document ).ready( () => {

    const request = new Request;
    const auth    = new Authenticator({
      domain:   'MY_DOMAIN',
      client:   'MY_CLIENT',
      secret:   'MY_CLIENT_SECRET',
      callback: 'http://localhost:1313/auth/'
    });

    // Authorization parameters

    const code    = request.getURLParameters( 'code' );
    const state   = request.getURLParameters( 'state' );

    // Authorized, exchanging Access Code for the Access Token

    if( code !== null && state !== null ) {

      const authorizationOptions = auth.getOptions();

      const authenticateOptions = {
        method: 'POST',
        data: {
          grant_type: 'authorization_code',
          client_id: authorizationOptions.client,
          client_secret: authorizationOptions.secret,
          code: code,
          redirect_uri: authorizationOptions.callback
        },
        headers: {
          'content-type': 'application/x-www-form-urlencoded'
        }
      };

      request.load( sprintf( 'https://%s/oauth/token/', authorizationOptions.domain ), authenticateOptions ).done( ( response ) => {

        console.log( response );

        const data = {
          headers: {
            authorization: "token " + response
          }
        };

        request.load( 'https://api.github.com/user', data ).done( ( user ) => {
          console.log( user );
        });

      });

      //window.close();
      return;
    }

    // Prompting the user for Authorization

    auth.getAuthenticator().authorize({
      connection: 'github',
      scope: 'email read:user user:follow notifications',
      responseType: 'code'
    });

  });

</script>

For reference:

  • Authenticator is pretty much a wrapper for auth0.WebAuth as in the previous answer. Of course, there is much more to this (Babel) class — like the accessory method getOptions used in authorizationOptions, that allows me to retrieve all arguments passed to the constructor — but I wanted to keep it simple here.
  • Request is on the same boat, with accessor methods to retrieve an Object with key/value pairs of current URL’s query string (getURLParameters()) and do some caching over AJAX requests. If you really need to see it, I can provide it later
  • sprintf comes from here. I find string interpolation in Javascript awful and Template Literals don’t help as I need to delay the definition of the variables

I believe I’ve covered it all so, although now I have code, state and access_token the last Request.load() in which I would finally consume Github API returns Bad Credentials

I also tried to use only response.access_token instead of the full response JSON received but I’ve got the same answer from Github.

Worth mentioning that this response has empty scope, even though I did define one while making the authorization — also tried to manually fill that information to no avail.

What am I doing wrong and how should I proceed?

Hi @josuehenrique,

Glad to hear you were able to make some progress!

The Access Token you receive from Auth0 is for the https://you-auth0-domain/userinfo endpoint (if you include an audience, then the Access Token will be for your own custom API). You can use this Access Token to retrieve the current user’s profile info.

The Identity Provider’s Access Token is available via the Management API:

Related topic:

I’m sorry, though I can see the relation between my case and the one from the link you mentioned I don’t know what to to do.

What these Identity Provider Access Tokens have to do with Github? Is the token I’m receiving NOT for Github API then? You said I need to set an audience, but where?

Is there any code-snippet I can base myself on? I can’t find anything that’s not related to the technologies I mentioned

Thank you for your time

Yes, that’s correct. The Access Token you receive from Auth0 is for using with Auth0 to get the user’s profile info. You can get the user’s Github Access Token, though.

This article explains how to call an Identity Provider’s API:
https://auth0.com/docs/connections/calling-an-external-idp-api

In your code, instead of making a request to Github’s API, you would have to make a request to your own proxy API.

I realize this is not what you were hoping for, sorry about that! As the docs explain, this is because there is no secure place to keep credentials in a frontend public client.

Thank you for the feedback

If I understood the docs correctly, I would need to change the second request I’m making to /oauth/token to:

const authenticateOptions = {
  method: 'POST',
  data: {
    grant_type: 'client_credentials',
    client_id: authorizationOptions.client,
    client_secret: authorizationOptions.secret,
    audience: sprintf( 'https://%s/api/v2/', authorizationOptions.domain )
  },
  headers: {
    'content-type': 'application/json'
  }
};

request.load( sprintf( 'https://%s/oauth/token/', authorizationOptions.domain ), authenticateOptions ).done( ( response ) => {

    console.log( response );

  });

In order to get something like — example from API Management Test View

{
  "access_token": "BIG_STRING_WITH_AUTH0_TOKEN",
  "token_type": "Bearer"
}

This “big string”, in fact, is much bigger than the token I was getting before

And then I would send this token to Github. Correct?

If so, I can’t, because from my development environment (http://localhost:1313), I’m getting the very same CORS impediment I was getting straight from Github when I tried to do everything without Auth0 and, therefore, I can’t get such token to use.

Worth mentioning that in this link you passed, once again, examples are only from React/Angular which, as I’m saying from the start, I am NOT using and I won’t use because that not only would require me to learn something entirely new I wouldn’t use anywhere else but would also ditch the use of Github Pages as I’m pretty sure NodeJS isn’t available on it.

That is how you would get the Access Token from a backend service, but unfortunately, for a frontend app such as a Github page, you would need to proxy the request. For example, you’d need to build and deploy your own API that makes the client credentials request and returns the token to your frontend app.

Unfortunately, you won’t be able to get the Github Access Token directly from the Management API from your page because the Github page does not have a secure place to store the client secret. The Client Credentials grant is designed for two backend systems (e.g. two APIs).

Further down in the docs, the frontend with proxy approach is explained: Call an Identity Provider API

So everything I read and coded, in the end, won’t ever work purely on the client, without any sort of of server-side programming.

Sigh…

Yeah, I’m sorry about that. You can authenticate using Github, but getting the Github Access Token would require server-side programming.