I am using speakeasy library to generate one time OTP https://www.npmjs.com/package/speakeasy
var token = speakeasy.totp({
secret: secret.base32,
encoding: 'base32',
step:300
});
console.log(token);
var verified = speakeasy.totp.verify({
secret: secret.base32,
encoding: 'base32',
token: token
});
console.log(verified);
But when i add the step parameter value to 300 (expire token after 5 minutes)i will get false on console.log(verified)
So whats the correct way to increase the token expiration time?
Please try with the time option. With the time option, you can get a time-based token for a custom time.
var token = speakeasy.totp({
secret: secret.base32,
encoding: 'base32',
time: 1453667708 // specified in seconds
});
Hope it will help you!
Related
I'm using JWT - jsonwebtokens in Nodejs.
I'm creating a token and want to throw an error if the token expires. My token is created successfully and I'm checking the token expiry in middleware of Apis in Expressjs. Then token is sent from Angular in headers and the expiration is checked in middleware.
This is how I'm creating the token:
var token = jwt.sign({
id: id,
expiresIn: '2m'
},
'mysecretkey'
);
This is how my middlware looks like:
var token = req.headers['authorization']
var idToken = token.split(' ')[1]
if(token) {
jwt.verify(idToken, 'myscretkey', (err, decoded) => {
if(err) {
return res.status(400).send('Session expired')
}
next()
})
}
This is what I'm receiving in decoded:
dec: {
id: 'an id',
expiresIn: '2m',
iat: 1596744770
}
In this case, my token is not expiring even after 2 minutes.
How can I achieve this?
In your code you added expiresIn as part of the payload. But there expiresIn has no meaning and you need to use the standard expclaim for expiration:
jwt.sign({
id: 'an id',
exp: Math.floor(Date.now() / 1000) + (60 * 2),
iat: Math.floor(Date.now())
}, 'secret')
in this example it's 2 minutes.
You can also calculate:
(60 * minutes), (3600 * hours) or (86400 * days) for minutes, hours or days.
expiresIn can be used as an option to the sign method as shown in Shivam Soods answer. I think that's the reason for your confusion.
If you want to work with hours or minutes using expiresIn you need to declare it after your secret like this
let token = jwt.sign(id,'mysecretkey',{ expiresIn: '1h'});
Read more about it here
hi guys hope every thing is going ok
i have a weird problem with speakseasy
every thing if going ok on my local machine when i uploaded to the iis the verify function always gets false
app.post("/verifySecret", async (req, res) => {
let data = await getSecret(req.body.email);
if (data == undefined) {
res.send({
"status": 404,
"message": "Email account not registered"
});
return;
}
let valid = {
"valid": speakeasy.totp.verify({
secret: data.secret,
encoding: "base32",
token: req.body.token,
window: 0
}),
"secret":data.secret,
"token":req.body.token
};
res.send(valid);
});
i checked every thing the secret key come from database the token is working on my local machine but on iis not attached two photos at the same time
first trial at iis machine
second trial at my local machine
both at the same time
I've been following the documentation on how to create an OAuth token for Salesforce Einstein. I have my private key and able to create the JWT token (code on bottom) yet when I try the CURL command as outlined in the documentation (step 4) with the token I've retrieved I get INVALID JWT Assertion error.
Documentation : https://metamind.readme.io/docs/generate-an-oauth-token-using-your-key
This is how I'm creating the signed JWT
require('dotenv').config();
const jwtToken = require('jsonwebtoken');
const payload =
{
"sub": "<EINSTEIN_PLATFORM_SERVICES_USERNAME>",
"aud": "https://api.einstein.ai/v2/oauth2/token",
"exp": <EXPIRATION_SECONDS_IN_UNIX_TIME>
}
const token = jwtToken.sign(payload, process.env.EINSTEIN_KEY, {algorithm : 'RS256'});
Any idea what I'm doing wrong?
It took me a while to figure this out...the problem was the UNIX time I gave was something of the year 1970 -_- so of course, since the JWT token expired I was not able to retrieve an access token from Salesforce Einstein.
I suggest using the following resource to get the correct expiration time in UNIX seconds : https://www.epochconverter.com/.
Here's my final code for generating a JWT Assertion String :
require('dotenv').config()
const fs = require('fs);
const jwt = require('jsonwebtoken');
let privateKey = fs.readFileSync(process.env.PRIVATE_KEY);
const header = {
algorithm: "RS256"
}
const payload = {
"sub": "<EINSTEIN_PLATFORM_SERVICES_USERNAME>",
"aud": "https://api.einstein.ai/v2/oauth2/token",
"exp": 1907891585 //Epoch timestamp of 6/17/2030
}
let token = jwt.sign(payload, privateKey, header);
With this code, I was able to retrieve an access token!
I am trying to generate a password token through speakeasy.js on a node.js express server, which shall be used as authentication. The password should change every hour. I'm using routers to retrieve the token and verify it.
If have set time to 30 seconds for testing purposes, but the token never changes.
Code:
var secret = speakeasy.generateSecret();
var token = speakeasy.totp({
secret: secret.base32,
encoding: 'base32',
step: : 10
});
router.get('/token/:token', function(req, res) {
console.log(token);
var usertoken = req.params.token;
if(usertoken == token){
res.send("Verified")
} else {
res.send("Not Verified")
}
res.json({ token: token, usertoken: usertoken });
});
Any suggestions?
EDIT
Added step to token.
When i request the end point e.g. http://localhost:8080/api/token/664006 the console shows the toke e.g. 290595. When i refresh the endpoint after a certain amount of time the token should change, but it doesn't. It's still 290595.
I've just checked the documentation and it looks that the parameter you're looking for it's step.
You should keep the time field to the default (Date.now() from the doc) and play with the step field.
Something like this:
var secret = speakEasy.generateSecret();
var token = speakEasy.totp({
secret : secret.base32,
encoding : 'base32',
// leave time field to default
step : 10
});
and for the verification use the method provided, instead of the ==:
router.get('/token/:token', function(req, res) {
console.log(token);
var usertoken = req.params.token;
var verified = speakeasy.totp.verify({
secret: base32secret,
encoding: 'base32',
token: userToken
});
//check if the token has changed
console.log(verified);
});
https://github.com/speakeasyjs/speakeasy
For me, when I added 'step' inside verify code, then everything went working.
var verified = speakeasy.totp.verify({
secret: secret,
encoding: 'base32',
token: token,
step: 10
})
I've hit a bit of a problem getting client-session middleware working in Express. In short the session_state doesn't seem to be accessible when redirecting to new route after being set. For reference I have followed this video tutorial (client-session part starts 36:00 approx.) and double checked my steps but still encountering problems. Middleware is set up as follows:
var sessions = require('client-sessions');
Instantiated with code from the Express website.
app.use(sessions({
cookieName: 'session',
secret: 'iljkhhjfebxjmvjnnshxhgoidhsja',
duration: 24 * 60 * 60 * 1000,
activeDuration: 1000 * 60 * 5
}));
I have the sessions middleware placed between bodyParser and routes if that makes any difference.
Here are the sections my routes/index.js pertaining to the issue. The req.session_state seems to get set ok and the correct user details log to the console.
// POST login form
router.post('/login', function(req, res) {
User.findOne( { email: req.body.email }, function(err,user){
if(!user) {
console.log("User not found...");
res.render('login.jade',
{ message: 'Are you sure that is the correct email?'} );
} else {
if(req.body.password === user.password) {
// User gets saved and object logs correctly in the console
req.session_state = user;
console.log("session user...", req.session_state);
res.redirect('/dashboard');
}
}
//res.render('login.jade', { message: 'Invalid password'} );
});
});
However, something is going wrong when the res.redirect('/dashboard'); is run because the session_state is not accessible when it hits that route. Here is the code for the /dashboard route.
router.get('/dashboard', function(req, res) {
// OUTPUT = 'undefined' ???
console.log("dash...", req.session_state);
// 'if' fails and falls through to /login redirect
if(req.session && req.session_state){
console.log("dash route...", req.session_state);
User.findOne( { email: req.session_state.email }, function
(err, user){
if(!user){
req.session.reset();
res.redirect('/login');
} else {
res.locals.user = user;
res.render('dashboard.jade')
}
});
} else {
res.redirect('/login');
}
//res.render('dashboard', { title: 'Your Dashboard' });
});
Basically, the object stored in session_state is not accessible after the /dashboard redirect. I've been trying to debug it for a day or so without any luck. Any help much appreciated. Sorry if I am missing something obvious. Just getting my feet wet with session middleware so maybe I haven't fully grasped Session or I am overlooking something. Thanks in advance!
I've updated my answer with code that should help you set the cookie and an alternative session manager known as a token. In this example I've provided to parts to a middle ware one part which attaches the cookie (this can be expanded on to determine your use case) and the second part which checks the token for expiration or what ever else might be in there (i.e. audience, issuer, etc.)
app.use('/js/',function(req, res, next) {
//check if the request has a token or if the request has an associated username
if(!req.headers.cookie){
console.log('no cookies were found')
var token = jwt.sign({user_token_name:req.body.user_name},app.get('superSecret'), {
expiresIn: 1 *100 *60 // expires in 1 mintue can be what ever you feel is neccessary
});
//make a token and attach it to the body
// req.body.token = token // this is just placing the token as a payload
res.cookie('austin.nodeschool' , token,{ maxAge: 100000, httpOnly: true }) //this sets the cookie to the string austin.nodeschool
}
if(req.body.user_name){
next()
}else{
res.send('request did not have a username').end() // this is here because my middleware also requires a username to be associated with requests to my API, this could easily be an ID or token.
}
},function(req, res, next) {
// console.log(req.headers) this is here to show you the avilable headers to parse through and to have a visual of whats being passed to this function
if(req.headers.cookie){
console.log(req.headers.cookie) //the cookie has the name of the cookie equal to the cookie.
var equals = '=';
var inboundCookie = req.headers.cookie
var cookieInfo = splitCookie(inboundCookie,equals) //splitCookie is a function that takes the inbound cookie and splits it from the name of the cookie and returns an array as seen below.
console.log(cookieInfo)
var decoded = jwt.verify(cookieInfo[1], app.get('superSecret'));
console.log(decoded)
// You could check to see if there is an access_token in the database if there is one
// see if the decoded content still matches. If anything is missing issue a new token
// set the token in the database for later assuming you want to
// You could simply check if it's expired and if so send them to the login if not allow them to proceed through the route.
}
next()
});