How to verify if the token expired - node.js

I want to verify if the token expired and then send a status and a message
async function verify () {
const ticket = await client.verifyIdToken({
idToken: req.body.token,
audience: CLIENT_ID
})
const payload = ticket.getPayload()
let email = payload['email']
return User
.findOne({
where: { email: email }
})
.then(user => {
if (!user) {
return next(boom.notFound('User not found'))
}
let token = jwt.sign({user}, config.secret, {
expiresIn: 86400 // expires in 24 hours
})
user.token = token
return res.status(200).send(user)
})
}
verify().catch(console.error)}
I've been traying with client.isTokenExpiring() but doesn't catch the error

This is a rough client side answer to your question. I recall in a previous post you linked to here that you were working on Google Web Login so I've answered from client perspective .
I don't have the same code as you for this problem, but in general this is what I did:
Extract the expiration date from the token. Check if the current time is later than or equal to the expiration on the token, then call the reloadAuthReponse method on the auth instance you are using. This will update your token. In fact, I do this every time the computer wakes from sleep.
This snippet includes helper functions from moment.js to compare times, but the general idea follows:
if(now.isSame(exp) || now.isAfter(exp)) {
gapi.auth2.getAuthInstance().currentUser.get().reloadAuthResponse().then(function() {
// do something with the new token
});
}

Related

How to store the login data in session storage and retrieve while commenting using node js

I have built a login API and added a comment API. login details and comment details are stored in a different table in Postgres DB. while commenting on how to retrieve the logged-in username. is there a need to use the session storage? if yes how to use that?
login
const admin = await loginData.findOne({ where: { email } });
if (admin && (await bcrypt.compare(password, admin.password))) {
const token = jwt.sign(
{ admin_id: admin._id, email },
process.env.TOKEN_KEY,
{
expiresIn: "365d",
}
);
admin.token = token;
}
comment
try {
const { comment } = req.body;
const stageComment = await initCommentModel();
const id = req.params.id;
// create comment
await stageComment.create({
comment: comment,
stage_id: id,
});
return res.send("SUCCESS");
} catch (err) {
return res.send(err.stack);
}
well, as i see you use jwt token for login so you comment api should verify token token before to do somehting else.
You have to write middleware in express JS to authetheticate and verify if token is present in header or token is valid or not then you can add the login info into req like req.email = currentloginuser#gmail.com.
you can store that token into session storage or localstorage on front end side.

JsonWebTokenError: invalid signature when verifying the jwt token

I'm implementing an web app that contains a chatbot that will remind the user on his upcoming google calendar events. I have successfully generated a jwt token when the user authorizes, but, I'm getting this error "JsonWebTokenError: invalid signature" when I verify the token. I'm still new to these concepts so I would really appreciate any help.
Here is where I signed my token:
let iss = 'GoogleCalender'
let sub = 'example#gmail.com'
let aud = 'xxxxxxxxxxxxxx'
let exp = '24h'
let sighOptions = {
issuer: iss,
subject: sub,
audience: aud,
expiresIn: exp,
algorithm: "RS256"
}
app.get('/landingPage', (req, res) => {
const token = jwt.sign({ user: 'iman' }, privateKey , sighOptions);
res.cookie('token', token,{ httpOnly: true });
res.sendFile(path.join(__dirname, "./landingPage.html"));
});
And here is where I verify the token:
let verifyOptions = {
issuer: iss,
subject: sub,
audience: aud,
maxAge: exp,
algorithms: "RS256"
}
function verifyToken(req,res,next){
const baererHeader = req.headers['authorization']
if(typeof baererHeader !== 'undefined'){
const baerer = baererHeader.split(' ')
const baererToken = baerer[1]
req.token = baererToken
next()
}
else{
res.sendStatus(403)
}
}
app.post('/landingPage',verifyToken, express.json(),(req,res)=>{
token = req.token
jwt.verify(token, publicKey, verifyOptions, (err,authData) =>{
const calendar = google.calendar({version: 'v3' , auth:createConnection()});
const agent = new dfff.WebhookClient({
request : req,
response : res
})
if(err) {
console.log(err)
function welcome(agent){
agent.add("Hi, Im helen, Please log in so i can remind you on your upcoming events")
}
}
else{
function welcome(agent){
agent.add("Hi, I'm Rem. Please click on remind me button if you want to be reminded on your upcoming events!")
} )
});
Is there any thing I'm doing wrong??
It's good that you're using a pair of private and public keys. It's better to use asymmetric signing than symmetric.
In your code I can see that you're sending the JWT token in a httpOnly cookie, but then in the landingPage you read it from the Authorization header. Not sure how is that supposed to work. Are you sure you're sending the right JWT to the /landingPage endpoint?
If you want to use this JWT that you issued yourself to access a user's data in a Google Calendar then it will not work. To access this data you need an access token issued by Google. Have a look at Google's documentation to check how to obtain an access token from them which will allow you to call the calendar API. You can still use the token that you are creating as a way of protecting your own endpoints. So: the user will need your token to be able to call your endpoint, and then a token from Google will be used to call the calendar API.

How can I get the id of the user that makes a request

How can I get the id of the user that creates a new article. I have created my auth middleware already with JWT. Here is my create article code.
exports.createArticle = (req, res) => {
const { title, article } = req.body;
const query = {
text: 'INSERT INTO article (title, article) VALUES ($1, $2) RETURNING *',
values: [title, article],
};
pool
.query(query)
.then((response) => {
const { id, created_on } = response.rows[0];
res.status(201).json({
message: 'Article successfully posted',
articleId: id,
createdOn: created_on,
title,
});
})
.catch((error) => {
res.status(400).json({
error,
});
});
};
If you are creating a payload that has the user's id in it, and then passing it to jwt.sign() then you can get the id of the user, once you authenticate the user's request by validating token that is being sent with the request.
Steps:
Note:
this are just a simple steps for better understanding,
ignore syntax or anything too specific to errors etc.
User sends log-in request.
you validate the credentials and send a token to the client side.
payload = { userId: userId , //rest info}
toekn = jwt.sign(payload, "key")
// send the token back, your methods may vary
User request for article creation and you receive token in the request, cookies, header or any other mechanism that you use
you use middleware to authenticate the request with token
jwt.verify(token, "key", (err, decodedUserInfo) => {
//dont proceed if err just throw error
//this decodedInfo has all the info that you have in payload while creating the token in step 2.
req.user = decodedUserInfo;
next();
}
as your req object has user info now, once your middleware is passed, you can use this info in your further operations.
You can get that from the JWT claims. Here is a list of standard claims: JWT Claims.
Subject, email, name or nickname would be suitable, depending on your case.
If you need an internal id, such as a database primary key - then use the subject id to link to that internal id. It is not considered good practice to leak out internal references to the outside.
How to get the subject id:
const jwt = require("jsonwebtoken");
// this is just for test, get a real verified token from your middleware
const testToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
const token = jwt.decode(testToken);
let subjectId = token.sub; // then lookup and insert into database
You can find out more by reading the OpenID Connect specification here: OpenID Connect Specification section 2.2 for the ID Token part.

How to secure JWT token and refresh token in nodejs/angular

i am new in node js. I am building a simple notes taking app and wanted to use JWT tokens for authentication and to secure my API's. On research i came to know that i need to create two tokens:
access token (short expire time like 10 minutes)
refresh token (longer expire time 30 days)
My config file
"secret": "*************",
"refreshTokenSecret": "*************",
"port": 5000,
"tokenLife": 900,
"refreshTokenLife": 86400
Code for middleware
const jwt = require('jsonwebtoken')
const config = require('./config')
module.exports = (req,res,next) => {
const token = req.body.token || req.query.token || req.headers['x-access-token']
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, config.secret, function(err, decoded) {
if (err) {
return res.status(401).json({"error": true, "message": 'Unauthorized access.' });
}
req.decoded = decoded;
next();
});
} else {
// if there is no token
// return an error
return res.status(403).send({
"error": true,
"message": 'No token provided.'
});
}
}
Here is the response
access token can be saved in local storage. but articles said save refresh token as http-only cookie.
i need the answer of following points (Keeping in mind that i am just a beginner):
How to store refresh token as http-only cookie (any node-js code
example would be a great help)?
How to secure it on client side and should I save refresh token to database?
Is there any other better solution to secure my API's?
You can use an http-only cookie using the following:
public authenticateUser(user: User, res: Response) {
const authJwtToken = this.generateJWT({
email: user.email,
uuid: user.uuid
});
const cookieOptions = {
maxAge: 3600000,
secure: true,
httpOnly: true
};
res.cookie('access_token', authJwtToken, cookieOptions);
}
// you can then res.send({...}) or wtv
Not that there is nothing from preventing you to store more than one cookie so I can't see a reason why not storing both of them in the same manner.
Now whether you will store it on the database depends on what you want to achieve.
Generally it is not required but note that in that case the server cannot in any way invalidate a single JWT. (You could in theory change the signing key but this would invalidate all of them).
In case you want to be able to achieve functionality such as 'log me out of all devices' you would need to store the JWTs issued for each user in a database (preferably an in-memory one such as Redis or Memcached) and do a second check with the extra information on whether they have been invalidated or not - even though such functionality is typically achieved using sessions instead of JWT
See this example how i secured my getByRefId api in nodjs :
In routes file :
router.get("/refId/:refId", helper.auth, groupController.getByRefId);
helper.auth is function :
auth: (req, res, next) => {
var token = req.body.token || req.headers['authorization'] || req.headers['Authorization'];
if (token.startsWith('Bearer ')) {
// Remove Bearer from string
token = token.slice(7, token.length).trimLeft();
}
if (token) {
jwt.verify(token, 'MY_SECRET', function (err, decoded) {
if (err) {
console.error('JWT Verification Error', err);
return res.status(403).send(err);
} else {
req.payload = decoded;
return next();
}
});
} else {
res.status(403).send('Token not provided');
}
}
This use jwt = require('jsonwebtoken') library you can install it in nodejs project

Saving JWT token to local storage

I want to save a JWT token into local storage in order to authenticate routes. My code is below but when this route is hit the browser just sits on loading and then says this page isnt working. Removing the localStorage.setItem() makes it work. Im wondering why this is happening. Thanks.
} else {
bcrypt.compare(password, user.password).then(Matched => {
if (Matched) {
//Create the payload for JWT to code
const payload = { id: user.id, name: user.name, email: user.email };
jwt.sign(
payload,
keys.JWT_KEY,
{ expiresIn: 3600 },
(err, token) => {
**localStorage.setItem("token", token);
res.redirect("/");**
}
);
} else {
Because localStorage.setItem("token", token) doesn't exist in nodejs, so the app will crash on this line and res.redirect("/"); is never executed, so the response is never sent back and your browser hangs while waiting for the response.
To fix it, send token back to client using res.json({ token: token }); and run localStorage.setItem("token", token); in the browser.

Resources