How to use Google oAuth with Node.js backend and Angular frontend? - node.js

I am using Node.js on backend and creates a token for a user each time logins. angularx-social-login package makes it very easy to integrate Google OAuth with Angular but how to use it with API? After successful login the Google returns user information with token. I was thinking to send this information to backend and login the user but for that I need to create a route which accepts email address and logins user. And this will return JWT token which is not secure. By secure I mean, anyone can access the route without Google Authentication and generate token.
I am looking for ideas how developers achieved this.

I found google-auth-library client package for Node.js managed by Google.
Here is the follow:
Login user with Angular
Send the idToken to backend
Validate token and response to Angular
Node.js:
exports.googleLogin = function(req, res, next) {
//verify the token using google client
return googleClient
.verifyIdToken({
idToken: req.body.token,
audience: config.google.clientID
})
.then(login => {
//if verification is ok, google returns a jwt
var payload = login.getPayload();
var userid = payload['sub'];
//check if the jwt is issued for our client
var audience = payload.aud;
if (audience !== config.google.clientID) {
throw new Error(
'error while authenticating google user: audience mismatch: wanted [' +
config.google.clientID +
'] but was [' +
audience +
']'
);
}
//promise the creation of a user
return {
name: payload['name'], //profile name
pic: payload['picture'], //profile pic
id: payload['sub'], //google id
email_verified: payload['email_verified'],
email: payload['email']
};
})
.then(user => {
return res.status(200).json(user);
})
.catch(err => {
//throw an error if something gos wrong
throw new Error(
'error while authenticating google user: ' + JSON.stringify(err)
);
});
};

Related

Recognizing first user login (Node.js/JWT)

I've developed an authentication system who consists on Node.js/Express and JWT.
I need to recognize the first time a user logs on and show him a message relevant only on that one time.
How can I do it?
This is the auth middleware i'm using to verify the user:
const auth = (req, res, next) => {
const token = req.header("x-auth-token")
if (!token) return res.status(401).json({ msg : "No token, authorization failed" })
try {
const decoded = jwt.verify(token, config.get("jwtSecret"))
req.user = decoded
next()
}
catch {
res.status(400).json({ msg : "Token is not valid" })
}
}
For this approach, you should let User to login with Basic Authentication for the first time (Email/Username + Password). After you validate that the user is the valid user on the backend, then you should store his _id in JWT and send him that JWT. On each next request, that user should send that JWT, and you can use your JWT authentication (but for initial login, you should go with Basic Authentication).

How to receive a cookie on reactjs from nodejs

I'm attempting to create a login where login data is sent to the nodejs server and if that login data is correct the server will send a JWT token through "res.cookie", what I would like to know is how will the reactjs client receive this cookie and also clear this cookie.
app.post('/login', (req, res) => {
const userData = {
email: req.body.email,
password: req.body.password
}
if(userData.email === email && userData.password === password){
const payload = { email };
const token = jwt.sign(payload, secret, {
expiresIn: '1h'
});
console.log(token)
res.cookie('token', token, { httpOnly: true })
.sendStatus(200);
}else{
res.send('incorrect params')
}
console.log(userData)
})
Here are the steps that need to happen.
User types their username and password and clicks sign in
Server receives credentials and validates them.
Server then creates a JWT for the users session and the server creates a cookie that contains the value of the jwt
the server simply returns and the cookie will be delivered as long as it is part of the response object.
hit control/command + i and view the cookie in chrome under your applications tab on the dev tools.
Also you probably want to use the nodejs https://www.npmjs.com/package/cookie-parser package to make your life easier.

How to send Bearer token to client and then call token from client

I have done a tutorial trying to get my head around JWT tokens. I seem to have got my head around the token creation as well as using the token to allow or disallow access to a route.
This all works great using postman, but in postman I enter the token under authorization. My question is:
1. how do I send the token to the client so it is saved on that client side.
2. How does the client return the token when they try to access a route?
I need to understand how this happens when NOT using postman. I am sure its pretty simple.
Do I just send
`res.header('Authorization', 'Bearer', + token);`
`res.header('Authorization', 'Bearer' + token);`
But can I send this with other stuff like a message / data etc?
Then when the user tries to access a protected route later, How do I access this header. IOW how is it stored client-side?
This is what I have thus far:
`//login route`
`app.post('/login', async function(req, res, next) {
const { name, password } = req.body;
if (name && password) {
let user = await getUser({ name: name });
if (!user) {
res.status(401).json({ message: 'No such user found' });
}
if (user.password === password) {
// from now on we'll identify the user by the id and the id is the
// only personalized value that goes into our token
let payload = { id: user.id };
let token = jwt.sign(payload, jwtOptions.secretOrKey);
res.json({ msg: 'ok', token: token });
} else {
res.status(401).json({ msg: 'Password is incorrect' });
}
}
});`
`// protected route
app.get('/protected', passport.authenticate('jwt', { session: false }), function(req, res) {
console.log('REQUEST HEADERS ON PROTECTED::',req.headers.authorization)
res.json('Success! You can now see this without a token.');
});`
The console.log under protected route gives me:
"REQUEST HEADERS ON PROTECTED:: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNTU2NjI3NTczfQ.gAU2VzpUpXHpcgM6_n8gf7D-xLCS59tK6K2RIlIk-L4" but I gather this is because I used the authorization in postman.
I recently worked with jwt auth using react as my front end and hapi.js as backend. To save the token on the client side, you can use localstorage like this:
You have to save this on the user login component.
localStorage.setItem('token', res.data.token);
And then, to access this token on the protected router, use this :
let token = localStorage.getItem('token');
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
I hope this may help you to solve your problem on the client side.

How to protect routes on a client server with JWT generated from my RESTful backend API?

I was attempting to build a signup/signin application using Nodejs. By looking at the articles, I came to know that it's a good structure to design your app so that your backend is actually a RESTful API and your client accesses that API. (Both client & server running on different servers, whereas the client is just a plain old static file server).
Now things went smooth until I had to sign users in. When the API endpoint (/signin) with the specific data is accessed, the data is validated against the database and if Okay, I am signing a JSON Web Token and passing it along to the client.
But the problem is that with this, I can only secure routes on my API i.e. I can only enforce that a user must be signed in to access a specific backend API endpoint.
But what can I do to enforce the same thing on my client with this JWT? For example, if in my client I have dashboard.html and I want it only accessible to signed in users, a user can go ahead and get a JWT generated. But how does this JWT come into play about restricting client routes?
My Signin Route:
app.post('/signin', (req, res) => {
var data = req.body;
if (!exists(data.username) || !exists(data.password))
return res.status(422).json({
message: 'All fields are required'
});
const users = db.get('users');
users
.findOne({
username: data.username,
password: shajs('sha256').update(data.password).digest('hex')
})
.then((user) => {
if (user) {
jwt.sign({
_id: user._id,
username: user.username
}, 'keyboard_cat', {
expiresIn: '1h'
}, (err, tok) => {
return res.status(200).json({
message: 'OK',
token: tok
});
});
return;
}
return res.status(200).json({
message: 'Invalid Username or Password.'
})
});
});
You can use conditional render on the front-end side. You can fire an api with the api token (generated from '/signin' api) which will tell you wether the api token is valid or not whenever you enter the route.
On the basis of the response from the server about the token you can decide which page to render (normal one or the unauthorised page).
There is also a better approach, send the api token in every route in the header, and if the token is malformed or invalid return 401 error from backend. Catch this error globally(or you can use response interceptor which is provided by axios) and then do conditional rendering.

Firebase 3.0 Tokens : [Error: Invalid claim 'kid' in auth header.]

I'm trying to create JWT tokens in node.js for use with the REST api in firebase, but when I try to use them, I get the error "Error: Invalid claim 'kid' in auth header."
This is my code
http.createServer(function (req, res) {
var payload = {
uid: "bruh"
};
var token = jwt.sign(payload, sact["private_key"], {
algorithm: 'RS256',
issuer: sact["client_email"],
subject: sact["client_email"],
audience: 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
expiresIn: '3600s',
jwtid: sact["private_key_id"],
header: {
"kid": sact["private_key_id"]
}
});
res.writeHead(200);
res.end("It worked. (" + token + ")");
}).listen(port);
These are my requires
var http = require('http');
var jwt = require('jsonwebtoken');
Please use returnSecureToken: true, with correct Spellings
I hope it will solve the problem of Invalid claim 'kid' in the auth header.
This is an issue because you're generating a Firebase ID token, not an access token for the Firebase REST API.
To generate a REST API token I would use the legacy Firebase Token Generator library which still works perfectly well (but only generates REST tokens, not general purpose access tokens).
Note that your Firebase Database secret is now located under the gear icon in the top left of the console.
So I had this error and I've fixed it. Now here is the solution:
You'll need to retrieve the ID-token using an additional function. Here is the function you can use:
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
// Send token to your backend via HTTPS
// ...
}).catch(function(error) {
// Handle error
});
I implemented it somewhat like this:
//google OAuth login handler
const googleLoginHandler = () => {
const provider = new firebase.auth.GoogleAuthProvider();
firebase.auth()
.signInWithPopup(provider)
.then((result) => {
/** #type {firebase.auth.OAuthCredential} */
setgoogleAuthStatus(true)
// The signed-in user info.
const userId = result.user.uid;
const displayName = result.user.displayName;
const email = result.user.email;
//This is the function for getting the ID-Token
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then((idToken) => {
// Send token to your backend via HTTPS
console.log(idToken)
}).catch((error) => {
// Handle error
console.log(error.message)
alert(error.message)
});
console.log(result)
}).catch((error) => {
console.log(error)
// Handle Errors here.
alert(error.message)
})
}
The id token you get by this method can be used to access the firebase real-time database and other firebase services.
check out these links for more details:
https://firebase.google.com/docs/auth/admin/verify-id-tokens#retrieve_id_tokens_on_clients
https://firebase.google.com/docs/database/rest/auth#firebase_id_tokens

Resources