Photo by Pankaj Patel on Unsplash
Google/github login with react-redux doesn't have to be hard. Part-2
Table of contents
This blog is second part of Part 1. Lets get started.
Configuring Firebase in your application
- Create new folder under src called “config”. Then create a new file called “firebase.config.js” paste the details earlier which you have copied.
import { getApp,getApps,initializeApp } from "firebase/app";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: "Your Api key",
authDomain: "Your Auth Domain",
projectId: "Your Project ID",
storageBucket: "fir-auth-9af82.appspot.com",
messagingSenderId: "384037070653",
appId: "1:384037070653:web:92ccb6b9b04b69eb45c754"
};
// Initialize Firebase
const app = getApps.length>0 ? getApp() : initializeApp(firebaseConfig)
export {app}
Now we will add the Firebase config to Login Component.
import React from 'react'
import { FcGoogle } from "react-icons/fc"
import { FaGithub } from "react-icons/fa";
import {app} from "../config/firebase.config"
import {getAuth, GoogleAuthProvider} from "firebase/auth"
import { useNavigate } from 'react-router-dom';
const Login = () => {
//Get details from app regarding user
const firebaseAuth = getAuth(app)
const googleProvider = new GoogleAuthProvider()
const navigate = useNavigate()
const loginWithGmail = async () => {
//Refer docs if possible
//console.log("Google");
await signInWithPopup(firebaseAuth, googleProvider).then((userCred) => {
// This gives you a Google Access Token. You can use it to access the Google API.
if (userCred) {
//console.log(userCred);
//Obserever to see the state changed
firebaseAuth.onAuthStateChanged(cred => {
cred.getIdToken().then(token => {
//console.log(token);
//Now pass the backedn to token
})
})
}
// ...
}).catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
// The email of the user's account used.
const email = error.customData.email;
// The AuthCredential type that was used.
const credential = GoogleAuthProvider.credentialFromError(error);
// ...
});
}
return (
.....
<div className='cursor-pointer w-full px-6 py-3 bg-white rounded-md gap-3 flex items-center justify-center hover:shadow-md' onClick={loginWithGmail}>
<FcGoogle className="text-4xl"/>
<p className='text-lg font-semibold text-gray-600'>Sign in with Google</p>
</div>
<div className='cursor-pointer w-full px-6 py-3 bg-white rounded-md gap-3 flex items-center justify-center hover:shadow-md'>
<FaGithub className="text-4xl"/>
<p className='text-lg font-semibold text-gray-600'>Sign in with Github</p>
</div>
</div>
</div>
)
}
As you can see there is Token we get, which needs to get send back to backend. Lets create a backend for it.
Create a server folder in root directory. In the terminal window, move to server folder.
firebase init
In your server folder, Firebase setup will be done. Open Firebase console, go to Project settings. Go under Service accounts tab. Click on Generate new Private key.
The Downloaded JSON file should be placed in sever/function folder. Rename the file to serviceAccountKey.json Under server dir/folder install
npm i express cors
Copy the following code in server/functions/index.js
const functions = require("firebase-functions");
const admin = require("firebase-admin")
const serviceAccount = require("./serviceAccountKey.json")
const express = require("express")
const cors = require("cors")
const app= express()
app.use(cors({origin:true}))
app.use(express.json())
admin.initializeApp({
credential:admin.credential.cert(serviceAccount),
})
//Handling user Routes
const userRoute = require("./routes/auth")
//If request comes from "/api/users", navigate to userRoute
app.use("/api/users",userRoute)
//To run sever
exports.app = functions.https.onRequest(app)
In terminal move to , server/functions and run
npm run server
Make sure write correct name of json file serviceAccountKey.json
There will be url : your_url
If you have any POSTMAN or ThunderClient extension or Rapid API extension feel free to use it.
By selecting GET method: your_url*/api/users/loginValidate*
Add the Italic part in URL.
Run now frontend part, make sure run simultaneously both backend as well as frontend. For frontend come under root directory. Run:
yarn start
In the Frontend terminal install axios,
npm i axios
In the src folder, create api/index.js
- index.js
import axios from "axios";
const baseUrl = 'http://127.0.0.1:5001/fir-auth-9af82/us-central1/app'
export const validateGoogleToken = async (token) => {
try {
const res = await axios.get(`${baseUrl}/api/users/loginValidate`,{
headers:{
Authorization : `Bearer ${token}`,
}
})
return res.data
} catch (error) {
console.log("Something went wrong.!!",error);
return null
}
}
- Move to server/functions/routes/auth.js
const router = require("express").Router()
const admin = require("firebase-admin")
router.get("/loginValidate", async (req,res) => {
//res.send("Hello auth.js")
if (!req.headers.authorization) {
return res.status(500).send({msg:"Invalid token"})
}
// console.log(req.headers.authorization.slice(7));
const token = req.headers.authorization.slice(7)
//return res.status(200).json(token)
try {
const decoderValue = await admin.auth().verifyIdToken(token)
//console.log(decoderValue);
if (!decoderValue) {
return res.status(500).send({msg:`Un-Authorized Access`})
}else{
res.status(200).send({
success:true,
data:decoderValue
})
}
} catch (error) {
return res.status(500).send({msg:`Error : ${error}`})
}
})module.exports = router
Go to Login Component in frontend, in loginWithGmail, add…
const loginWithGmail = async () => {
//Refer docs if possible
//console.log("Google");
await signInWithPopup(firebaseAuth, googleProvider).then((userCred) => {
// This gives you a Google Access Token. You can use it to access the Google API.
if (userCred) {
//console.log(userCred);
//Obserever to see the state changed
firebaseAuth.onAuthStateChanged(cred => {
cred.getIdToken().then(token => {
//console.log(token);
//Now pass the backedn to token
validateGoogleToken(token).then((data)=>{
console.log("Token...",data);
})
})
})
}
// ...
}).catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
// The email of the user's account used.
const email = error.customData.email;
// The AuthCredential type that was used.
const credential = GoogleAuthProvider.credentialFromError(error);
// ...
});
}
Create a Reducer
- Create src/context folder
Create a files called StateProvider.js ,reducer.js ,initialState.js
- StateProvider.jsx
import { createContext,useContext,useReducer } from "react";
export const StateContext = createContext()
export const StateProvider = ({reducer,initialState,children}) => (
<StateContext.Provider value={useReducer(reducer,initialState)}>
{children}
</StateContext.Provider>
)
export const useStateValue = () => useContext(StateContext)
- initialState.js
export const initialState = {
user:null
}
- reducer.js
export const actionType = {
SET_USER :"SET_USER"
}
const reducer = (state,action) => {
console.log("Action...",action);
console.log("State...",state);
switch (action.type) {
case actionType.SET_USER:
return {
...state,
user:action.user
}
default:
return state;
}
}
export default reducer
In index.js do following changes
<React.StrictMode>
<Router>
<StateProvider initialState={initialState} reducer={reducer}>
<App />
</StateProvider>
</Router>
</React.StrictMode>
- To store the data in ContextProvider
- Login.jsx
.....
import { useStateValue } from '../context/StateProvider';
import { actionType } from '../context/reducer';
....
const [{user},dispatch] = useStateValue()
const loginWithGmail = async () => {
//Refer docs if possible
//console.log("Google");
await signInWithPopup(firebaseAuth, googleProvider).then((userCred) => {
// This gives you a Google Access Token. You can use it to access the Google API.
if (userCred) {
//console.log(userCred);
//Obserever to see the state changed
firebaseAuth.onAuthStateChanged(cred => {
cred.getIdToken().then(token => {
//console.log(token);
//Now pass the backedn to token
validateGoogleToken(token).then((data)=>{
//console.log("Token...",data);
dispatch({
type:actionType.SET_USER,
user:data.data
})
})
})
})
}
// ...
}).catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
// The email of the user's account used.
const email = error.customData.email;
// The AuthCredential type that was used.
const credential = GoogleAuthProvider.credentialFromError(error);
// ...
});
}
- In App.js write similar code to authenticate user
import { useEffect } from "react";
import { Route, Routes } from "react-router-dom";
import Home from "./container/Home";
import Login from "./container/Login";
import {app} from "./config/firebase.config"
import {getAuth} from "firebase/auth"
import { validateGoogleToken } from "./api";
import { useStateValue } from './context/StateProvider';
import { actionType } from "./context/reducer";
function App() {
const firebaseAuth = getAuth(app)
const [{user},dispatch] = useStateValue()
useEffect(() => {
firebaseAuth.onAuthStateChanged(userCred => {
if (userCred) {
userCred.getIdToken().then(token => {
validateGoogleToken(token).then(res => {
dispatch({
type:actionType.SET_USER,
user:res.data
})
})
})
}
})
}, [])
return (
<div className="w-screen min-h-screen flex items-center justify-center">
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/login" element={<Login/>}/>
</Routes>
</div>
);
}
export default App;
In Home.jsx
import React from 'react'
import { useStateValue } from '../context/StateProvider'
import {getAuth} from "firebase/auth"
import {app} from "../config/firebase.config"
import { actionType } from '../context/reducer'
import { useNavigate } from 'react-router-dom'
const Home = () => {
const [{user},dispatch] = useStateValue()
const firebaseAuth = getAuth(app)
const navigate = useNavigate()
const logoutUser = () => {
firebaseAuth.signOut().then(() => {
dispatch({
type:actionType.SET_USER,
user:null
})
navigate("/login",{
replace:true
})
})
}
return (
<div className="w-screen h-screen flex items-center justify-center">
<img src={user?.picture} alt="picturek"/>
<p>{user?.name}</p>
<p onClick={logoutUser}>........Signout..........</p>
</div>
)
}
export default Home
Github Login
Go to Github Component
<div className='cursor-pointer w-full px-6 py-3 bg-white rounded-md gap-3 flex items-center justify-center hover:shadow-md' onClick={loginWithGitHub}>
<FaGithub className="text-4xl"/>
<p className='text-lg font-semibold text-gray-600'>Sign in with Github</p>
</div>
const loginWithGitHub = async () => {
await signInWithPopup(firebaseAuth,gitProvider).then((data)=>{
//console.log(data);
const cred = GithubAuthProvider.credentialFromResult(data)
const token = cred.accessToken
dispatch({
type:actionType.SET_USER,
user:cred.user
})
navigate("/")
}).catch((err)=>{
console.log("error",err);
})
}
Now the Web app will work with both Google as well as Github. I hope this blog had provided some insightful knowledge. For better knowledge do refer documentation of firebase. Thank you so much.