Harshil Parmar
Harshil Parmar
September 1, 2022

How to Implement GitHub OAuth in Your Node.js App

tutorials, nodejs, auth, github

OAuth is a standard protocol used for authorization. Nowadays, OAuth is primarily used by every website to allow a user to access their resources by using a third-party login.

For example, you can log in with Google, Facebook (Meta), GitHub, etc.C urrently, we're talking about GitHub and trying to get better insight into what, why, and how you can implement it into your Node.js application.

This post will discuss implementing GitHub OAuth in your Node.js app.

What Is Oauth 2.0, Access Token, Callback URL, Client ID, and Client Secret?

  • Oauth 2.0: This is basically authorization workflow and doesn’t mean validating a user’s identity. It only checks whether the user has permission to access the resources. So, basically, Oauth is allowing a user to use the same account for a different web app.
  • Access token: This is nothing but a token by which our app will have access to any third-party Oauth (GitHub in this case) on your behalf.
  • Callback URL: We have to tell the authorization server where to redirect a user once the process is done.
  • Client ID: For any third-party integration, we have to tell the authorization server (e.g., GitHub) to register our app (Node.js). As a result of this, we'll get client ID that we have to send in the future to get an access token, and the authorization server will easily identify the client by that.
  • Client secret: In the process of registering the Oauth application with a server, we'll also get client secret. This will be needed to get an access token.

Node.js App and Github Oauth Flow

GitHub OAuth with-shadow

Here is the OAuth flow that we'll perform in today's blog post. There are a total of three requests, including verifying user identity, getting auth code as query, and using that to get access token eventually.

Register With GitHub

For this, GitHub provides three ways to implement authorization using OAuth here.

There are three flows:

  1. web application flow
  2. device flow
  3. non-web application flow

We're currently focusing on web application flow.

We can use this link to register our app with GitHub.

GitHub OAuth

After registration, you'll see all the details with client ID and client secret.

For getting a client secret, you'll see all the registered details.

GitHub OAuth

Once you click on "Generate a new client secret," you'll have a client secret. Please make sure to copy that and put it in a safe place so we can use it in the future.

Now it's time to create API endpoints. Here, we'll use express framework to make APIs.

npm init --y
npm i express axois

This will create an express project with an axois library for fetching data.

const { default: axios } = require("axios");
const express = require("express");
const path = require("path");
const app = express();

app.get("/", (req, res) => {
    res.sendFile(path.join(__dirname, "public/index.html"))
})

app.listen(8000, () => {
    console.log("its running!!!");
})

Now, in the app.js file, we'll create a homepage route that serves index.html.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>


      .container {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 10%;
      }
      a {
        border: 1px solid black;
        text-decoration: none;
        border-radius: 10px;
        padding: 10px;
        background-color: aliceblue;
      }
    </style>
  </head>

  <body>
    <div class="container">
      <a href="/auth"> Login with Github </a>
    </div>
  </body>
</html>

We just need an anchor tag that redirects us to GitHub for login or authorizes us to use the app via a GitHub login.

app.get("/auth", (req, res) => {
    res.redirect(`https://github.com/login/oauth/authorize?client_id=33a703d019e0d23730ea`);
})

By clicking on "Login with GitHub," we're redirecting the user to the GitHub authorization page. Here, the client ID is used by GitHub to identify Oauth registration.

GitHub OAuth with-shadow

GitHub OAuth

Now, once we click on "authorize username," it'll redirect us back to the callback URL that we registered earlier.

app.get("/callback", (req, res) => {
    axios.post("https://github.com/login/oauth/access_token", {
        client_id: "33a703d019e0d23730ea",
        client_secret: "6f52b07d679f6955317a4fe7983d4b3b6cb0aa2e",
        code: req.query.code
    }, {
        headers: {
            Accept: "application/json"
        }
    }).then((result) => {
        console.log(result.data.access_token)
        res.send("you are authorized " + result.data.access_token)
    }).catch((err) => {
        console.log(err);
    })
})

This callback URL will get Auth code, which is required to get access token. So, we have to make a post request to github.com/login/oauth/access_token by providing the client ID, client secret, and code. As a result, GitHub will send back access_token.

GitHub OAuth with-shadow

Once you're authorized, you'll get the access token that we're currently printing on the screen. Now it's up to you to determine how you want to use that access token to get information about the user.

const { default: axios } = require("axios");
const express = require("express");
const path = require("path");
const app = express();

app.get("/", (req, res) => {
    res.sendFile(path.join(__dirname, "public/index.html"))
})

app.get("/auth", (req, res) => {
    res.redirect(`https://github.com/login/oauth/authorize?client_id=33a703d019e0d23730ea`);
})

app.get("/callback", (req, res) => {
    axios.post("https://github.com/login/oauth/access_token", {
        client_id: "33a703d019e0d23730ea",
        client_secret: "6f52b07d679f6955317a4fe7983d4b3b6cb0aa2e",
        code: req.query.code
    }, {
        headers: {
            Accept: "application/json"
        }
    }).then((result) => {
        console.log(result.data.access_token)
        res.send("you are authorized " + result.data.access_token)
    }).catch((err) => {
        console.log(err);
    })
})

app.listen(8000, () => {
    console.log("its running!!!");
})

OAuth token is revoked whenever it's pushed to a public repository or public gist

Next Topics to Look Into

1. Token expiration: Oauth token can be revoked in the following of ways:

  • Pushed publicly: Oauth token is revoked whenever it's pushed to a public repository or public gist.
  • Lack of use: If the Oauth token hasn't been used in one year, GitHub will automatically revoke it.
  • Revoked by user: An Oauth token revocation from the user account settings will revoke any associated token with a third-party app.
  • Revoked by Oauth app: The owner of the Oauth app can revoke authorizations of the app by deleting an app authorization. Additionally, individual tokens can be deleted.
  • Issue of excess tokens: If a third-party Oauth app creates more than 10 tokens for the same user/scopes, the oldest tokens with a similar scope/user will be revoked.

2. Scope: Scope allows us to limit access for OAuth tokens. Furthermore, users can control what things they want to share with third-party apps. There are several scopes available, including repo, public_repo, gist, user, project, etc.

If there's no scope specified, the Oauth app can only access public information from the user's profile with read-only access.

In this post, we’ve learned how to implement GitHub OAuth in a Node.js app

Conclusion

In this post, we've learned how to implement GitHub Oauth in a Node.js app. This small tutorial described what, why, and how we can successfully connect our Node.js app to use the GitHub account of our users. I hope this post gives you an initial push to use complex OAuth 2.0 in your application. Now you can connect to any app, such as Google, Facebook, Slack, Apple, and many more, that provides OAuth service.

To stay updated with our latest content, please subscribe to our email updates or follow us on Twitter at @runmedev! Also, check out Runme, a VS Code Extension that lets you run commands in READMEs with a click instead of tedious copy&pasting into a terminal.

Let us know what you think. Bye for now! 👋

This post was written by Harshil Parmar. Harshil is a software developer with around 2 years of experience currently studying at Humber College, Toronto. He has worked on Angular, React, Node,Php. He also does open source contributions and freelance. He loves to write about JS technologies and update his knowledge by keep researching and learning new stuff related to anything JS..

Also check out

10 Things You Didn't Know Markdown Could Do
May 16, 2023
10 Things You Didn't Know Markdown Could Do

Read this blog post and find 10 incredible tips that you probably didn’t know and can help you with workflows and local development.

BranchGPT: The AI-Powered Solution to Branch Names
May 10, 2023
BranchGPT: The AI-Powered Solution to Branch Names

Generate a branch name that follows your personal convention with BranchGPT. Blurt out what you're working on, and let AI do the rest. It's perhaps more fun than practical, but isn't that true for many things "AI" these days?

The Hitchhiking Contributor’s Guide to Onboarding Docs in CI/CD
May 3, 2023
The Hitchhiking Contributor’s Guide to Onboarding Docs in CI/CD

All kidding aside, why don’t we continuously integrate our repo's onboarding workflows? It's obvious and easy. Here's a GitHub Action to do the heavy-lifting.

© 2023 Stateful Inc. All rights reserved.