I work on app with an authentication using Node JS, JWT and Sequelize for the API and I'm using React JS / redux for the front part. I'm successfully implemented the login/logout/register parts for the application, but now I need to access to the current_user logged in.
I put a JWT in the localStorage, but I want to have access to the user ID, user email, user name and more informations about my user currently logged in.
Should I use Cookies ? LocalStorage ? Or should I create a currentUser method in my API ?
I'm a bit lost with this, if someone could help me find some usefull resources or advices !
Thank !
If you put that information in the payload of the JWT, then you can get it without decoding on the server or needing the secret, and can therefore put the token in LocalStorage for use whenever. By the spec, a JWT is <headerINfo>.<payloadInfo>.<signature>. So on the client, you can just do:
// given a payload object of { username: 'bob', userid: 1, email: 'bob#example.com' }
const tokenParts = token.split('.');
const encodedPayload = tokenParts[1];
const rawPayload = atob(encodedPayload);
const user = JSON.parse(rawPayload);
console.log(user.username); // outputs 'bob'
Obviously, this info is available to any client that has access to the Token, so you only want to put stuff in the payload that that's OK for.
Storing the token in LocalStorage is fine. If you need to fetch the user details, create an endpoint in your API such as getUser. You can then use jwt.decode(accessToken, JWT SECRET HERE) and return the decoded value (which will be your user) assuming the accessToken is valid.
You can make a middleware if you haven't already that will ensure that user info is always available to those routes that require it:
const auth = jwt({
secret: JWT_SECRET,
userProperty: 'payload',
algorithms: ['HS256']
});
module.exports = auth;
Then you should have req.payload with user details. Alternatively you can check the Authorization property in your headers depending on how you set up your app.
When logging in, server should send token and user data, you can store that data in Redux store. Then simply request data from there. When user reloads page, send API request with JWT token and server should return user data, that you will again put in Redux store.
Related
I'm looking for a way to send user's email and password from the client to my Firebase Backend Functions and make the login from the backend, I find out info about Id tokens and stuff like that, but I need just simple function that receives email and password and make the request to Firebase Auth.
On firebase late versions you might have something like "signInWithEmailAndPassword(email, password)", So I'm looking the exact operation just for the SDK for node.js, and I dont seems to find one.
Thank you.
Firebase Auth only allows you to use signInWithEmailAndPassword on client side.
You should not authenticate users on backend (although it's possible), because it might have unintended consequences, but you can authenticate user with signInWithEmailAndPassword on the browser and then verify "ID Token" to your backend.
Frontend (using firebase):
const payload = {
uid: user.id,
idToken: await user.getIdToken()
}
//send payload to server
Backend (using firebase-admin):
const decodedToken = await getAuth(app).verifyIdToken(body.idToken)
//check decodedToken.uid equals body.uid
You can read more into "ID token verification" here:
https://firebase.google.com/docs/auth/admin/verify-id-tokens#web
I have a custom function that validates the Shopify session token and returns the decoded JWT
{
iss: The shop's admin domain.
dest: The shop's domain.
aud: The API key of the receiving app.
sub: The user that the session token is intended for.
exp: When the session token expires.
nbf: When the session token activates.
iat: When the session token was issued.
jti: A secure random UUID.
sid: A unique session ID per user and app.
}
Then, I initialize the context with Shopify.Context.initialize({...})
How can I get the access token using:
const session = await Shopify.Utils.loadCurrentSession(req, res)
Right now, I'm saving the access token in a database during the initial install since I don't know how to use the function above with AWS API Gateway.
What should be req and res knowing that a Lambda handler has event and context as parameters?
I feel req = event. But I have no idea what res should be in this case.
I'm using JWT passaport to login module:
async validateUser(userEmail: string, userPassword: string) {
const user = await this.userService.findByEmail(userEmail);
if (user && user.password === userPassword) {
const { id, name, email } = user;
return { id: id, name, email };
}else {
throw new UnauthorizedException({
error: 'Incorrect username or password'
});
}
}
async login(user: any) {
const payload = { email: user.email, sub: user.id };
return {
access_token: this.jwtService.sign(payload),
};
}
This part is running.
My question is: how do the logout? I read about creating a blacklist and adding the token to it, but how do I get the user's access token?
Something you should know about token-based authentication is that it is stateless. This means that even the server does not keep track of which users are authenticated, like with session-based authentication. As such, you do not need to do anything on the server side to "log out" a user. You simply need to delete the t\JWT token on the client. If you make a request to the server app, without a valid JWT token, it will be treated as the user is not logged in.
Generally when a logout request would be sent the Authorization header should be present, so you can grab the token from there. Then you can save the token to the database's restrict list table.
When user click to "Log out" btn, you should sent a request which is attached Authorization header with bearer token. In the backend side, you need to extract header and push the token to the blacklist token (as your solution). Basically, you only need remove token in client side, it's so easy to do but in the worst case when the token was stolen by hacker, your token still valid. Using blacklist token is more secure but it can be lead to performance issue and scalable. What is the best solution? it's depend on you.
Read the Nestjs Execution context get the token from the request header and verify this token from JWT.
everything defines in the NESTJS link
//here we check the token from the header is valid or not expired
const tokenVarify = await this.jwtService.verify(token);
my idea is make whitelist every generate new token and remove it when user logout. so u need to check on guard also every user with token access its exist on whitelist or note
You must be refresh expire token to 1ms with:
https://webera.blog/how-to-implement-refresh-tokens-jwt-in-nestjs-b8093c5642a9
Actually there is a workaround for this, but not so straightforward!
The idea is to keep track of the tokens for logged out users (use some sort of black-list) and query provided token against that black-list.
To sum it up, you can follow these 4 steps:
Set a reasonable expiration time on tokens
Delete the stored token from client side upon log out
Have DB of no longer active tokens that still have some time to live
Query provided token against The Blacklist on every authorized request
For detailed explanations, you can check this post: medium
A guide in how to do the implementation is in this youtube video
Code with Vlad
, and there's as well the github source nestjs-jwts. I followed this video and implemented myself as well..
I am new to JWT, not new to react, but am very confused on how to decode a JWT from the front end. I initially thought that I can store the JWT Secret in the .env file but many sources say that it is a very bad idea to do so. I have the backend setup to send me a JWT when you login. But without storing the secret key in the front end as well, how would I decode the information?
Backend:
if(bcrypt.compareSync(ctx.params.password, hashed_db_password)) {
ctx.status = 200;
const payload = { data: tuples[0] };
const options = { expiresIn: '1h', issuer: 'testIssuer'};
const secret = process.env.JWT_SECRET;
const token = jwt.sign(payload, secret, options);
ctx.body = token;
return resolve();
}
How I thought front end should have been:
let data = JWT.verify(result.data, process.env.REACT_APP_JWT_SECRET, options);
I have also read alot that the backend should do validation but then wouldnt that just be a huge security risk to validate, then send back unsecure raw user information? Any information would be greatly appreciated.
BTW, I am using Reactjs, Node.js, Express, and MySql
You should not store JWT secret in client side.
To decode token, you don't need the JWT secret.
You can decode the token using jwt-decode package.
Or if you want to decode without using a package, you can look at here.
You can store it in your main components state, Redux store, React Context, localstorage and so on..
You should get the JWT only when your authentication is successful and you should send it with each request to the server, you don't need to decode it on the front-end you just pass the encoded value to the server and decode it somewhere on the backend (some kind of middle-ware)
I have built my first Node.js app that is supposed to be installed on a Shopify store. If you want to see what my actual code looks like (app.js) you can view it here. It's really basic so reading through won't be hard.
I know how to authenticate the installation of the app (following the Shopify instructions) but I don't how to authenticate all subsequent requests using the permanent access token that a successful installation provides me with.
By subsequent requests I'm referring to requests to either render the app or requests to install the app, even though the app is already installed.
Right now, I'm storing the shop's name (which is unique) along with the permanent token that Shopify sends me in my database. But I don't know if that's necessary. If I'm not mistaken, simply using the browser's session will do ? But how do I do that ? And how do I use this token every time a request comes through to check if it is a valid one?
Thank you for any help/suggestions!
The code below is sort of a representation of what my actual code looks like in order to give you an idea of what my issues are :
db.once('open', function(callback)
{
app.get('/', function (req, res)
{
var name = getNameFrom(req);
if (existsInDB(name) && tokenExistsInDBfor(name))
{
res.redirect('/render');
/*
Is checking that the shop (along with a permanent token)
exists in my DB enough ?
Shouldn't I check whether the current request comes with
a token that is equal to the one in my DB ?
What if the token received with this request is different
from the one stored in my DB ?
*/
}
else res.redirect('/auth');
});
app.get('/auth', function (req, res)
{
if (authenticated(req))
{
var token = getPermanentToken();
storeItInDB(nameFrom(req), token);
res.redirect('/render');
/*
aren't I supposed to do anything more
with the token I've received ? send it
back/store it in the browser session as well maybe?
is storing it in the db necessary ?
*/
}
});
app.get('/render', function (req, res)
{
/*
How do I check that this request is coming
from an authorised shop that has the necessary token ?
Simply checking my DB will not do
because there might be some inconsistency correct ?
*/
res.sendFile(*file that will build app on the client*);
});
});
Getting access token from Shopify is once time process.
Save access token and shop's name in your DB, and also generate and save 'auth token' based on some algorithm. Return generated auth token to Client. Make sure client sends this auth token in every request.
Now when client hit your server verify auth token; once verified make call to Shopify API using appropriate 'access token' and shop name.
Authentication flow could be as follows:
Get Access token from Shopify
Generate token(i am refering this as auth token) for the Shopify Shop, refer this
Now save shopify's access token, shopify store name and your generated token into DB
Now send your generated token to client(save it in cookie or local storage)
Validation flow:
Clients hits your server to get data with your auth token
Verify this auth token in your DB, and get access token and shop name for that auth token
Now make calls to Shopify API using this access token and shop name
Hope this method helps