Skip to content

Implementation of Google OAuth2.0 in a decoupled Frontend & Backend Web Application

License

Notifications You must be signed in to change notification settings

TitusRobyK/express-google-oauth2.0

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Implementation of Google OAuth2.0 in a decoupled Frontend & Backend.

This project demonstrates on how to integrate Google OAuth2.0 authentication in a decoupled web application. I found it difficult pinpoint an article or a tutorial that demonstrates how to implement google authentication in an application such as this , so I figured I would try it out to save you the peril.

Tech Stack

For the backend server, we use the following

For the frontend client , we are using React with very basic minimal code to demonstrate the overall flow & how all modules come together in tandem.

Architecture

Here is an overview of the architecture diagram / system design diagram

image

Getting Started

React-client and Server logic has been defined in different folders to be clear and clean. My server is running on localhost:5000, whereas the client is running on localhost:3000. (Feel free to define your own port.)

|-- express-google-oauth2.0
|   |-- express-server
|   |   |-- server.js
|   |   |-- package.json
|   |-- react-client
|   |   |-- src
|   |   |   |-- index.js
|   |   |   |-- package.json
  • Setting up Google OAuth Api's in Google Cloud Console

    • Log onto Google Cloud Console

    • Click on Select a project & then New Project

      image

      image

    • Provide a suitable name for the Project & organisation if any :

      image

    • Navigate to API and Services by clicking on the Navigation Menu & then on API's & Services.

      image

    • Now enable Click on OAuth consent screen & provide your scope either as internal (Only available to users within your organisation.) or external

      image

    • Fill in all the requisite fields whichever applicable

      image

    • On click of save & continue , you will be navigated to Scopes

      image

    • As shown above , add the necessary scopes & in our case , its profile, email & openid & subsequently scroll down , click Update

    • Save & Continue to the last page

    • Click on Credentials

      image

    • Click on Create Credentials & then on OAuthClientId as shown in the image provided below

      image

    • Select Web application

      image

    • Add http://localhost:5000/api/v1/auth/google/callback as our redirect URI & then click Create

      image

      image

    • Copy the above ClientId & ClientSecret into the file named config.env under express-server/server/config/ path

    image

  • Setting up MongoDB in your local

    • Download MongoDB from their Community Download Website

    • Post downloading , to setup MongoDB in your OS , Follow the instruction from this website

    • For setting up authentication for the mongoDB Instance , The following procedure first adds a user administrator to a MongoDB instance running without access control and then enables access control.

    • Start MongoDB without access control.

      Start a standalone mongod instance without access control.

       mongod --port 27017 --dbpath /var/lib/mongodb
      
      
    • Connect to the instance by using the following command

       mongo --port 27017 
      
      
    • From the mongo shell, add a user with the userAdminAnyDatabase role in the admin database. For more info , check out the db.createUser Doc

       db.createUser({user: "myname", pwd: "mypass", roles: ["userAdminAnyDatabase"]})
      
    • Re-start the MongoDB instance with access control.

      Shut down the mongod instance. For example, from the mongo shell, issue the following command:

        db.adminCommand( { shutdown: 1 } )
      

      Exit the mongo shell & Start the mongod with access control enabled.

      If you start the mongod from the command line, add the --auth command line option:

        mongod --auth --dbpath /var/lib/mongodb
      

      Connect to mongod instance using the following command

        mongo --port 27017  --authenticationDatabase "admin" -u "myname" -p
      

      Instance will ask the user to input the password, so input the password set in db.createUser step

    • Now formulate the dbconnect MONGODB_URI to be set in the env config file for the express-app.

        mongodb://myname:mypass@127.0.0.1:27017/?authSource=admin
      
  • Running the whole program

    • Clone the repo

    • After performing all the setups mentioned in the above setup

    • Change directory to the express-server & run the following command

      Makesure your mongo instance is running in the background

        npm i
        npm run dev
      

      You can observer that the express-app will start working & the API's will be accessible through http://localhost:5000

    • Change directory to react-client & run the following command

        npm i
        npm run start
      

      You can see that react-client will start working & the page can be accessed through the following http://localhost:3000

Significance of Passport Serializer & Deserialiser

// used to serialize the user for the session
  passport.serializeUser((user, done) => {
    done(null, user.id)
// where is this user.id going? Are we supposed to access this anywhere?
  })

// used to deserialize the user
  passport.deserializeUser((id, done) => {
    User.findById(id, (err, user) => done(err, user))
  })

The user id (you provide as the second argument of the done function) is saved in the session and is later used to retrieve the whole object via the deserializeUser function.

serializeUser determines which data of the user object should be stored in the session. The result of the serializeUser method is attached to the session as req.session.passport.user = {}. Here for instance, it would be (as we provide the user id as the key) req.session.passport.user = {id: 'xyz'}

The first argument of deserializeUser corresponds to the key of the user object that was given to the done function (see 1.). So your whole object is retrieved with help of that key. That key here is the user id (key can be any key of the user object i.e. name,email etc). In deserializeUser that key is matched with the in memory array / database or any data resource.

The fetched object is attached to the request object as req.user

Visual Flow

passport.serializeUser(function(user, done) {
    done(null, user.id);
});              │
                 │ 
                 │
                 └─────────────────┬──→ saved to session
                                   │    req.session.passport.user = {id: '..'}
                                   │
                                   ↓           
passport.deserializeUser(function(id, done) {
                   ┌───────────────┘
                   │
                   ↓ 
    User.findById(id, function(err, user) {
        done(err, user);
    });            └──────────────→ user object attaches to the request as req.user   
});