- This project is developed to show different ways of authentication strategies in a NodeJS backend API
- These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.
-
Clone the repository
git clone https://github.com/AbegaM/NodeJS-Authentication-Template.git -
Install the NPM packages
npm install
-
All environment variables are added in the dotenv.example file, you need to first create a .env file and you need to add the parameters below
SERVER_PORT SERVER_SECRET GITHUB_CLIENT_ID GITHUB_CLIENT_SECRET GITHUB_REDIRECT_URL GITHUB_SIGNUP_STATE GITHUB_SIGNIN_STATE
SERVER_PORT
- Port of the server in which the server will run on
SERVER_SECRET
- A secret value which is used by the backend to create a JWT token, it can be a combination of string and integer
GITHUB_CLIENT_ID
- A client ID which is generated by Github, which will be used to create an OAuth authentication, follow this tutorial to generate a client ID
GITHUB_CLIENT_SECRET
- A client secret which is generated by Github
GITHUB_REDIRECT_URL
- A callback URL which is used by Github to fire a request to your server
GITHUB_SIGNUP_STATE
- A string value which you use to create a secure communication when users signin with Github
GITHUB_SIGNIN_STATE
- A string value which you use to create a secure communication when users signup with Github
-
Run the code in development environment
npm run dev -
Run the code in production environment
npm run start
- The goal of this project is to create different authentication methods in a NodeJS application, and as we know there are many ways we can implement authentication in a NodeJS app and this can be
- Token based authentication
- Cookie based authentication
- Two factor authentication (2FA)
- Passport based authentication
- OAuth
- Auth0
-
This protocol was never been created to implement authentication, originally it was designed to authorize two different applications.
-
As an example, lets take Heroku, as we know Heroku is a hosting service which is used to host web applications, if you have used this service before you have seen that it implements a continuous deployment by pulling your latest code from your Github account, this means every time you push your code to your main branch Heroku can be triggered and can build your latest code to a production environment.
-
For this to happen you need to allow Heroku to access your account on behalf of you, and giving a third party application your credentials would not be a good idea, so this is when OAuth comes to the picture, using OAuth your Heroku account can get a privilege to pull the latest code from your Github account.
-
The diagram shows how your Heroku account can access your Github account on behalf of you, here is how the flow works
- The user gets to his Heroku account and will connect Github for CI/CD
- The Heroku app will send a request to Githubs OAuth authorization server, to access the account
- The Github OAuth server asks if the user is Heroku can access the account
- If the user approved the request then Github will provide an access token for Heroku to access the Github API
-
Note that the Heroku service will only be given a limited access of the Github resource and in this cane it can only pull the latest code from your main branch
- We can use the OpenID connect standard to create an application in which our users can signup and signin using Github.
-
If we don't want to create a signup feature for our users, we can let the users to be registered using their Github account, here is the flow
-
The user will send a signup request to our backend API
GET http://localhost:7000/api/auth/signup/github -
When the users send a GET request to the above API, our app will redirect the users to Githubs OAuth server
https://github.com/login/oauth/authorize -
Github will get our request and it will ask the user to allow our application to access the Github API
-
When the user authorizes our app, Github automatically first a GET request to our callback URL
GET https://localhost:7000/api/auth/callback/github -
When a request is fired to our callback API, the controller checkes if the users Github ID is registered in the PouchDB database and if it is already registered it will throw an error but if the users is not registered it will save the users Github information in the PouchDB local database.
// server/service/oauth/github.js const githubCallback = async ({ data, param, query }) => { const githubUser = await getUserDataFromGithubApi(query.code); const user = await db.find({ type: "user", "github.id": githubUser.id }); if (query.state === env.github.signupState) { const token = await registerUser(user, githubUser); return { action: "send", data: { token } }; } else { const token = await login(user); return { action: "send", data: { token } }; } }; const registerUser = async (user, githubUser) => { if (user.length > 0) { throw new Error("This user is already registered with Github"); } const userInfo = { type: "user", github: { id: githubUser.id, name: githubUser.name, email: githubUser.email, }, google: { id: "", name: "", email: "" }, facebook: { id: "", name: "", email: "" }, twitter: { id: "", name: "", email: "" }, }; const { id } = await db.save(userInfo); const token = await helper.generateToken({ id }, "48H"); return token; }; const login = async (user) => { if (user.length === 0) { throw new Error( "You can't login with Github, please signup with Github first" ); } const token = await helper.generateToken({ id: user[0]._id }, "48H"); return token; };
-
As seen in the code, the githubCallback function is triggered by Github and when it is triggered it first gets the users information from the Github API and the function will execute either the regisiter function or the login function
-

