How to get userId from token? - node.js

I'm coding a simple get endpoint, and I send from front-end header the token information. But in back-end I need to use userId. I think it is available on token, but how can I get userId from token?
// React Front End service
const response = await fetch(
`${process.env.REACT_APP_API_HOST}/export-data/pdf?${urlParams}`,
{
headers: {
...authService.authHeader(),
Authorization: `Bearer ${authService.getToken()}`,
},
}
);
// Nestjs Back End controller
#UseGuards(AuthGuard)
#Permissions('admin')
#Get('/pdf')
async exportDataPdf(#Query() query: GetOrdersFilterDto): Promise<any> {
// I need to use userId from token here.
return await this.exportDataService.exportDataPdf(query);
}

It depends on how you sign this.jwtService.sign() while signIn a user / while generating jwt token.
For example if you use
this.jwtService.sign({ userId: user._id });
Then you can simply do this on your controller
#Get('profile')
getUserId(#Request() req: any) {
return req.user.userId;
}
Note req.user object is used internally by nestjs to store jwt payload data.
In case you want any data you provide on jwt in a nestjs guard. You can also get access it from req object.
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const [req] = context.getArgs();
// console log user ID
console.log(req.user.userId);
// create your conditional logic here before return true
return true;
}

You can make a method called getUserIdFromToken and use it for that. If bcrypt was used to create the token out of the email, you can get the email back from it.
Here is how I did it in node:
Encode the token
const hashData = { email: user.email }
const accessToken = jwt.sign(hashData, process.env.ACCESS_TOKEN_SECRET)
Decode the token
const email = jwtDecode(token).email;
Then, you can retrieve the user with the email.

Related

Get token for firebase admin authentication

this is my function, for firebase function:
export const hello = onRequest({ cors }, async (request, response) => {
const token = request.headers.authorization?.split('Bearer ')[1]
if (token) {
const tokenData = await getAuth().verifyIdToken(token, true)
response.send({
status: 'success',
data: tokenData.email
})
} else {
response.status(401).send('Unauthorized')
}
})
I don't like how I'm getting token here, but that's the only way I found:
request.headers.authorization?.split('Bearer ')[1]
is there any better way? Let's say, maybe admin itself has some built in method?
The verifyIdToken() requires only the JWT token as first parameter. The 'Bearer ' just indicates that the request uses Bearer token system. If you just add the token in your API request you won't have to parse the string to get the token part. The Admin SDK does not have any built-in function for that.
Alternatively, you can use onCall() instead of onRequest() that'll handle the authentication part and you can read user's information from context.auth object.

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.

How to obtain the token from the current user with jwt/express/node

I have a controller that receives an user that is trying to login via form. When all validations are checked, the user will be logged in and a token will be created in the following way:
const token = jwt.sign({userId: user._id}, config.secret ,{expiresIn: '24h'})
res.json({success: true, message: 'Sesión iniciada', token: token, user: {email: user.email}})
However, how do I access this token from another controller? I've seen that a good approach would be to create a middleware that intercepts such token, but I don't really know how to accomplish this.
I'd be happy only knowing how to get the token tho. I'm kinda new and I'm taking very small steps.
You should setup your client requests to send such token as #Vahid said.
Here's an example with axios
const instance = axios.create({
baseURL: 'https://some-domain.com/api',
// From the docs:
// `transformRequest` allows changes to the request data before it is sent to the server
// This is only applicable for request methods 'PUT', 'POST', 'PATCH' and 'DELETE'
// The last function in the array must return a string or an instance of Buffer, ArrayBuffer,
// FormData or Stream
// You may modify the headers object.
transformRequest: [function (data, headers) {
headers['Authorization'] = localStorage.getItem('jwt')
return data;
}],
})
export default instance
In case you also need GET request you can add:
export setAuthToken = (token) => {
instance.defaults.headers.common['Authorization'] = token;
}
Although you'll need to call it every time your JWT is renewed.
After that, you could catch it using the Middlewares to decode the token from the headers
app.use((req, res, next) => {
const authToken = req.headers['Authorization']
if(authToken) {
try {
const decoded = jwt.verify(authToken, config.secret)
req.user = decoded.userId
// Hopefully
// req.user = getUserById(decoded.userId)
next()
} catch(e) {
// Handle Errors or renewals
req.user = null
// You could either next() to continue or use 'res' to respond something
}
} else {
// Throw 403 if should be authorized
res.sendStatus(403)
}
})
This way you should be able to access req.user on any route defined after your middleware.
Eg:
app.post('/me', (req, res) => {
res.send(req.user)
})
Note that this is just one example of a global middleware. In other cases, you should be able to create custom middlewares based on which routes you want to protect or with which amount of permissions.

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.

Apollo Server 2 + Auth0

So I have an app that logs me in via Auth0 and saves a jwt token in a cookie.
I also have an Apollo Server 2 that retrieves the data. How do I secure the Apollo Server and only return data if the user is logged in and verified by the Auth0 server?
The code below comes right from https://www.apollographql.com, but what I don't understand is how to handle getUser(token) below to actually check for a valid JWT in the Authorization header, and if present, the user will be allowed to access protected resources?
// using apollo-server 2.x
const { ApolloServer } = require('apollo-server');
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
// get the user token from the headers
const token = req.headers.authorization || '';
// try to retrieve a user with the token
const user = getUser(token);
// add the user to the context
return { user };
},
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
});
getUser is the method that returns your user with the given token. you might need to write that method yourself or use OAuth's getUser method.
After getting the user object, you're returning it so now you have access to the user object in your resolvers. In your resolver method, the third parameter is your context object. you can access the user object there. If you want to protect that resolver to only be allowed by logged in users you can throw an error if user is null or undefined.
For example:
export const resolvers = {
Query: {
Me: (parent, args, { user }) => {
if (!user) return Error(`Not Logged In!`)
return user
}
}
}

Resources