how to do i get user id from JWT token? [duplicate] - node.js

I tried to get user id from a JWT token. I got a JWT token and sucessfully verified it, but it doesn't return an id.
When I decode the JWT:
const decoded = jwt.verify(token, config.get('jwtPrivateKey'));
var userId = decoded.id
console.log(decoded)
I got this output:
{ iat: 1561463667 }
But I excepted this output:
id :"*****************"
How do I get the user id from the token?

When the whole output is { iat: 1561463667 }, it means, that no extra payload/claims were added when the token was signed.
The jsonwebtoken package usually adds iat (issuedAt, the time when the token was issued) as a default claim.
In simple words: you can only decode claims, that were added before.
To add more claims, try this code (when you're in control of the code which issues the token):
let payload = { "id" : "1"};
let token = jwt.sign( payload,'secret', { noTimestamp:true, expiresIn: '1h' });
Here I added an expiry time (exp), and set the option noTimestamp to suppress the automatically added iat claim.
The result looks like this:
{
"id": "1",
"exp": 1561471747
}
and the token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJleHAiOjE1NjE0NzI0MzV9.jmKyITRoxLl0fy0-rrwgPOA_iRgGQu8W4Cc6dPupOMA
Then you can get the id as you have already shown in your question:
const decoded = jwt.verify(token, "your secret or key");
var userId = decoded.id
console.log(userId)
You can also paste the above shown JWT or your token into the https://jwt.io debugger, to inspect the token and see the structure and the actual claim names. Maybe there's no id, but a userId or similar, or a subclaim, which is a registerd claim name to be used to identify the principal:
The "sub" (subject) claim identifies the principal that is the
subject of the JWT.
It might also happen, that the token contains nested objects, e.g.:
{
"user_data":
{
"user_id": "1",
"user_name: "superuser"
},
"exp": 1561471747
}
then you get the user_id this way:
const decoded = jwt.verify(token, "your secret or key");
var userId = decoded.user_data.user_id
console.log(userId)

Related

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.

DocuSign Get JWT Token MEAN Stack

Building a basic application where users can find Service Providers using MEAN Stack, and after negotiations are over, agreements are auto generated and have to be signed by both parties.
Got Stuck on generation of JWT Token for authentication.
Steps I followed are:
Generate a url for obtaining consent from user and pass it to frontend. Users will be redirected and permissions can be granted from there.
var url = "https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature&client_id=42017946-xxxx-xxxx-xxxx-81b0ca97dc9a&redirect_uri=http://localhost:4200/authorization_code/callback";
res.status(200).json({
status: 1,
message: 'Fetched',
value: url
});
After successful redirection with code in URL, API call is made to backend for the generation of JWT token.
Token is generated as follows:
var jwt = require('jsonwebtoken');
var privateKey = fs.readFileSync(require('path').resolve(__dirname, '../../src/environments/docusign'));
const header = {
"alg": "RS256",
"typ": "JWT"
};
const payload = {
iss: '42017946-xxxx-xxxx-a5cd-xxxxxx',
sub: '123456',
iat: Math.floor(+new Date() / 1000),
aud: "account-d.docusign.com",
scope: "signature"
};
var token = jwt.sign(payload, privateKey, { algorithm: 'RS256', header: header });
Private key used above is from docusign admin panel.
iss -> Integration key against my app.
sub -> user id in the drop down of user symbol in admin panel
Obtain the access token
const axios = require('axios');
axios.post('https://account-d.docusign.com/oauth/token',
{
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: token
})
.then(resposne => {
console.log(response);
})
.catch(err => {
if (err.response) {
console.log(err);
} else if (err.request) {}
else {}
})
But I am constantly getting error: { error: 'invalid_grant', error_description: 'no_valid_keys_or_signatures' }
I would suggest using the node.JS SDK or npm package and using the build-it JWT method to authenticate. The code would look like this:
(click here for GitHub example)
DsJwtAuth.prototype.getToken = async function _getToken() {
// Data used
// dsConfig.dsClientId
// dsConfig.impersonatedUserGuid
// dsConfig.privateKey
// dsConfig.dsOauthServer
const jwtLifeSec = 10 * 60, // requested lifetime for the JWT is 10 min
scopes = "signature", // impersonation scope is implied due to use of JWT grant
dsApi = new docusign.ApiClient();
dsApi.setOAuthBasePath(dsConfig.dsOauthServer.replace('https://', '')); // it should be domain only.
const results = await dsApi.requestJWTUserToken(dsConfig.dsClientId,
dsConfig.impersonatedUserGuid, scopes, rsaKey,
jwtLifeSec);
const expiresAt = moment().add(results.body.expires_in, 's').subtract(tokenReplaceMin, 'm');
this.accessToken = results.body.access_token;
this._tokenExpiration = expiresAt;
return {
accessToken: results.body.access_token,
tokenExpirationTimestamp: expiresAt
};

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 get user id using jwt token

I tried to get user id from a JWT token. I got a JWT token and sucessfully verified it, but it doesn't return an id.
When I decode the JWT:
const decoded = jwt.verify(token, config.get('jwtPrivateKey'));
var userId = decoded.id
console.log(decoded)
I got this output:
{ iat: 1561463667 }
But I excepted this output:
id :"*****************"
How do I get the user id from the token?
When the whole output is { iat: 1561463667 }, it means, that no extra payload/claims were added when the token was signed.
The jsonwebtoken package usually adds iat (issuedAt, the time when the token was issued) as a default claim.
In simple words: you can only decode claims, that were added before.
To add more claims, try this code (when you're in control of the code which issues the token):
let payload = { "id" : "1"};
let token = jwt.sign( payload,'secret', { noTimestamp:true, expiresIn: '1h' });
Here I added an expiry time (exp), and set the option noTimestamp to suppress the automatically added iat claim.
The result looks like this:
{
"id": "1",
"exp": 1561471747
}
and the token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJleHAiOjE1NjE0NzI0MzV9.jmKyITRoxLl0fy0-rrwgPOA_iRgGQu8W4Cc6dPupOMA
Then you can get the id as you have already shown in your question:
const decoded = jwt.verify(token, "your secret or key");
var userId = decoded.id
console.log(userId)
You can also paste the above shown JWT or your token into the https://jwt.io debugger, to inspect the token and see the structure and the actual claim names. Maybe there's no id, but a userId or similar, or a subclaim, which is a registerd claim name to be used to identify the principal:
The "sub" (subject) claim identifies the principal that is the
subject of the JWT.
It might also happen, that the token contains nested objects, e.g.:
{
"user_data":
{
"user_id": "1",
"user_name: "superuser"
},
"exp": 1561471747
}
then you get the user_id this way:
const decoded = jwt.verify(token, "your secret or key");
var userId = decoded.user_data.user_id
console.log(userId)

extract payload of expired jwt token

I am making API Server with Node.js and Express.
Also I used JWT token authentication for auth user.
If token is expired, my scenario is here.
(Backend) Middleware detect expired
(Frontend) Receive token is expired
(Fronend) Refresh token request to backend
(Backend) Verify token is valid and if it expired, sign new token(with old token's payload) and response it to frontend
at number 4, my code is here.
try {
const token = req.headers.authorization.split(' ')[1];
jwt.verify(token, SECRET, (err, decoded) => {
if(err.name === 'TokenExpiredError') {
const payload = jwt.verify(token, SECRET);
const userid = payload.userid;
const is_admin = payload.is_admin;
const refreshToken = jwt.sign({
userid: userid,
is_admin: is_admin
}, SECRET, {
algorithm: 'HS256',
expiresIn: '10m'
})
res.status(200).json({status: true, token: refreshToken});
}
else if(err) {
res.status(401).json({status: false, result: "Invalid token"});
}
})
} catch(e) {
//console.log(e);
res.status(401).json({status: false, result: "Token does not exist"});
}
After run it, throw errors line of const payload = jwt.verify(token, SECRET);.
Because if token is expired, it throws TokenExpiredError error.
I want to decode token and extract payload of expired token.
But in verify(), there is no information about payload.
So I read document, found some interest method decode().
But it mention that do not use decode(), because it doesn't check signature is correct or not.
Is there any solution about extract payload of expired token?
Thanks.
You can set the option ignoreExpiration to true to avoid getting this error for expired tokens (at that point you know it already) and then get the payload:
if(err.name === 'TokenExpiredError') {
const payload = jwt.verify(token, SECRET, {ignoreExpiration: true} );
// your code
}
Now you can be sure the token is valid but just expired.

Resources