In this post, you will see how to build a react app with Github login & nodejs backend. It is common to come across react libraries social logins for Google, Facebook etc that provide the app with the ability to login using oauth, without the need to interact with a custom backend. In most cases when you are building an app, the front-end will talk to a custom backend, hence it is important to understand the end to end flow of how social logins work in the context of an app. This post presents code samples of a reactjs app that allows using Github credentials to login with two separate repositories. The reactjs front-end is a custom app that talks to a separate nodejs app that’s the backend.

Github oauth

The solution presented in this repo, uses the Github Oauth2 API. To run the code presented in this repo, you would need to register a new app in Github console and obtain the Github client id and Github client secret. Make a note of the redirect url that you specify here to use it in the next section.

React app with Github oauth login & nodejs backend

Create a simple nodejs app with the following files.

NodeJS backend

package.json

{
  "name": "user-session",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^1.3.6",
    "cors": "^2.8.5",
    "dotenv": "^16.0.3",
    "express": "^4.18.2"
  }
}

.env file

GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=

and finally the index.js file with two endpoints, one to handle the redirect url you specified when creating an app on Github and the other endpoint to return the user details.

const express = require("express");
const axios = require("axios");
var cors = require("cors");
require("dotenv").config();

const CLIENT_ID = process.env.GITHUB_CLIENT_ID;
const CLIENT_SECRET = process.env.GITHUB_CLIENT_SECRET;

const GITHUB_URL = "https://github.com/login/oauth/access_token";

const app = express();

app.use(cors({ credentials: true, origin: true }));

app.get("/oauth/redirect", (req, res) => {
  axios({
    method: "POST",
    url: `${GITHUB_URL}?client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&code=${req.query.code}`,
    headers: {
      Accept: "application/json",
    },
  })
    .then((response) => {
      const token = response.data.access_token;
      res.redirect(
        `http://localhost:3000?access_token=${response.data.access_token}`
      );
    })
    .catch((err) => {
      console.log("********************ERROR********************");
      console.log(`Error occured ${err}`);
    });
});

app.get("/user/data", (req, res) => {
  const token = req.headers["authorization"];
  axios({
    method: "GET",
    url: ` https://api.github.com/user`,
    headers: {
      Authorization: token,
    },
  })
    .then((resp) => {
      res.statusCode = 200;
      res.send(resp.data);
    })
    .catch((err) => {
      console.log(err);
    });
});

const PORT = 8080;
app.listen(PORT, () => {
  console.log(`Listening at port ${PORT}`);
});

That should handle creating a simple nodejs based backend for your react app. Next create the reactjs front-end app.

ReactJS front-end

Create a reactjs app with the following package.json file

package.json

{
  "name": "oauth2-node-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "axios": "^1.3.6",
    "react": "^18.2.0",
    "react-bootstrap": "^2.7.4",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

.env file

REACT_APP_GITHUB_CLIENT_ID=

Remember to use end variables in a ReactJS app, the env variables must be prefixed with REACT_APP_. and finally the App.js file

import Button from "react-bootstrap/Button";
import { useEffect, useState } from "react";
import axios from "axios";
import "./App.css";

function App() {
  const [loggedIn, setLoggedIn] = useState(false);
  const [user, setUser] = useState(null);
  const [githubUrl, setGithubUrl] = useState("");
  useEffect(() => {
    const token = new URLSearchParams(window.location.search).get(
      "access_token"
    );
    axios
      .get("http://localhost:8080/user/data", {
        headers: {
          Authorization: "token " + token,
        },
      })
      .then((res) => {
        setUser(res.data);
        setLoggedIn(true);
      })
      .catch((error) => {
        console.log(error);
      });
      const gitHubUrl = `https://github.com/login/oauth/authorize?client_id=${process.env.REACT_APP_GITHUB_CLIENT_ID}&redirect_uri=http://localhost:8080/oauth/redirect`;
      setGithubUrl(gitHubUrl);
  }, []);

  return (
    <div className="App text-center container-fluid">
      {!loggedIn ? (
        <>
          <img
            className="mb-4"
            src="https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
            width="150"
          ></img>
          <h1 className="h3 mb-3 font-weight-normal">Sign in with GitHub</h1>
          <Button
            type="primary"
            className="btn"
            size="lg"
            href={githubUrl}
          >
            Sign in
          </Button>
        </>
      ) : (
        <>
          <h1>Welcome!</h1>
          <p>
            This is a simple integration between OAuth2 on GitHub with Node.js
          </p>

          <div>
            {[...Array(1)].map((e, i) => (
              <div style={{ maxWidth: "25%", margin: "auto" }}>
                <div>
                  <img src={`${user.avatar_url}`} />
                </div>
                <div>
                  <div>{user.name}</div>
                  <div>{user.bio}</div>
                  <a href={user.html_url}>GitHub Profile</a>
                </div>
              </div>
            ))}
          </div>
        </>
      )}
    </div>
  );
}

export default App;

Look at the url called when logging in to react app,

https://github.com/login/oauth/authorize?client_id=${process.env.REACT_APP_GITHUB_CLIENT_ID}&redirect_uri=http://localhost:8080/oauth/redirect
  1. You initiate a request to login using Github from the front-end via this url https://github.com/login/oauth/authorize
  2. You pass in the GithubClientId that you got when creating it on the Github dashboard
  3. Then you have specified the redirect_uri which is a get endpoint in the nodejs app
  4. Hence once the user logs in via their Github credentials, it will redirect to the node backend
  5. After that the nodejs app with redirect back to the client by specifying the access_token after login
  6. This will trigger the useEffect react hook where we you call /user/data endpoint to get user details

Note: Remember both nodejs backend and reactjs front-end must be running while you are testing this.

React app with Github oauth login & node backend – source code

You can find all my code in this Github repository that you can clone and follow the instructions on how to setup and run the apps in the repository. Here’s a sample of the readme file in the repo.

How to run it?

The repository readme provides clear instructions on how to setup and run the app e.g.

You would need to run both the front-end and the backend individually.

How to start the backend

cd user-session
npm install 
vim .env
# add variables GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET
## press ESC :wq
node index.js

In the above process once you install the libs

  • create a .env file
  • copy the id, secret from your Github dashboard where you registered your app
  • assign those values to your github variables in the .env file
  • save the .env file

Note: I use vim, as it’s my preference but you can use any text editor

How to start the front-end

cd user-session-client
yarn install 
vim .env
# add variables GITHUB_CLIENT_ID
## press ESC :wq
yarn start

In the above process once you install the libs

  • create a .env file
  • copy the id from your Github dashboard where you registered your app
  • assign the client id to your github variables in the .env file
  • save the .env file

Note: I use vim, as it’s my preference but you can use any text editor

Conclusion

In this post you saw how to build a modern web app that uses microservices architecture. Using Github for social login while is not complex, it has a few different moving parts to watch out for while building an app with it. Have a look at my repository node_react_github_oauth and let me know if you have any questions for me.

If you find any of my posts useful and want to support me, you can buy me a coffee 🙂

https://www.buymeacoffee.com/bhumansoni

While you are here, maybe try one of my apps for the iPhone.

Products – My Day To-Do (mydaytodo.com)

Have a read of some of my other posts on AWS

Deploy NodeJS, Typescript app on AWS Elastic beanstalk – (mydaytodo.com)

How to deploy spring boot app to AWS & serve via https – My Day To-Do (mydaytodo.com)

Some of my other posts on Javascript …

What is Javascript event loop? – My Day To-Do (mydaytodo.com)

How to build a game using Vanilla Javascript – My Day To-Do (mydaytodo.com)

Vanilla Javascript: Create Radio Buttons (How-To) – Bhuman Soni (mydaytodo.com)

Java Spring Boot & Vanilla Javascript solution – My Day To-Do (mydaytodo.com)

Vanilla Javascript: Create Radio Buttons (How-To) – Bhuman Soni (mydaytodo.com)


0 Comments

Leave a Reply

Avatar placeholder