How to logout authenticate user - node.js

I am logging in user successfully /login and able to show information on my /profile route.
Now, I am trying to /logout the authenticate user, but seems it is not working. When trying passing logout route , nothing is happening. The JWT token is not getting expire so the /profile data is there even after logout click.
//logout testing
router.post('/logout' , checkAuth, (req, res) => {
req.logOut();
res.status(200).send(["logged out"]).redirect('/login');
});
This is my /profile:-
router.get('/profile', checkAuth, (req, res, data) =>{
User.find(req.userData, function(err, users) {
res.send(req.userData);
});
});
I want the logout to be global. The user must get logged out from each device user is logged in

When you use a JWT your server is stateless, you don't have a session in your server. You must delete the stored JWT from the client side or (but I'm not fan of this technique, it's not a good practice) you can store the list of "revoked" JWT, in the server side, when you logout and check if the token send by the client is on this list. You can also store the date of the last logout and check if the date of the JWT is oldest than the logout date, if is oldest the JWT is not valid.

Related

Handling sessioning and middleware in a react SPA?

If I wasn't using react and was using express(nodejs) in the backend, this is what I would do for [an extremely simplified] auth system:
//Auth Middleware
const auth = (req, res, next)=>{
if(req.session.loggin_in===true){ next()}
else{ res.redirect('/login')}
}
//Endpoints
app.get('/', auth, (res, req)=>{ res.render('homepage')})
app.get('/login', (req, res)=>{ res.render('login')})
I know that you can use react routing to redirect the user to different pages, but how can you use middleware and session variables?
Do you have to send an http request for authentication from the client side to see whether the user is logged in? If this was the case, and supposing I wasn't logged in and tried to access the home page, I would first go to the home page before being redirected to the login page.
Thanks.

Handle Google OAuth with JWT (react + nodejs)

I am working on the authentication system of a web app, using Next.js for the client app and Node.js for the API.
I have my Next.js app on port 3000
I externalized the API of my application, on port 5000
That's why I used JWT for the local signin/signup strategies.
(I'm planning to use the same API for the mobile application later)
I am now wondering what is the best approch for a Google Authentication.
I have set it up, but I don't know how to give the token to the client.
Here is the process:
On Signin page (http://localhost:3000/signin), the user clicks on "Google authentication". It redirects to 'http://localhost:5000/auth/google"
Passport handles it, it redirects to Google OAuth page. User authorize the application.
Google redirects to the callback URL (http://localhost:5000/auth/google/redirect)
In the callback route, I can create a JWT. But how can I give it back to the client ?
I have thought of passing it through URL, but I am wondering if it is safe ?
Is there another way to do it / Am I missing the point ?
router.get('/google/redirect', (req, res, next) => {
return passport.authenticate('google', (err, user) => {
if (err) {
return res.redirect('http://localhost:3000/signin')
}
console.log(user)
// Create JWT and redirect to http://localhost:3000/signin/oauth?token=xxx ?
})(req, res, next)
})
I can show more code if needed, but it works (code is not the blocking point).
Thank you in advance !
all you have to do is setting up cookie session. When google sends responds to /google/redirect, passport.authenticate will call req.login() and this will call the serializeUser
passport.serializeUser(
(user, done ) => {
done(null, user.id); // stores the id<4kb
}
);
this function will create, passport:{user:userId}. this is the unique identifying information about the user. This where you need session. Because passport.js will automatically look for req.session and attaches the passport object to the req.session.
Since we are storing only userId, usually cookie-session package. this package will set req.session object, passport.js will attach the passport object and the cookie-session will store this on the client.

Local authentication in NodeJS express passing JWT token back to separate Angular SPA client

I am building an app with a back-end in NodeJS 12 Express 4 and a front-end client SPA in Angular 8. I am building local authentication with the PassportJS local authentication strategy.
Auth workflow:
A GET request is sent to the /login endpoint and the login page is loaded.
Note: The login page is NOT in the SPA, it is a simple pug page with a form that sends a to POST to the /login endpoint.
GET /login
router.get('/', (req, res, next) => {
return res.render('login');
});
The user enters their credentials, submits the form and sends a POST request to /login. The Passport local strategy checks the credentials and then in the callback, creates a JWT to be sent back to the client.
This is where I am getting stuck. If I had the login page in the SPA, I could just send an AJAX request and get the response back to the client as JSON e.g. return res.json(jwtToken) and the SPA could parse the token and store it in session storage directly.
However, since the login page is on the server directly, how can I send the token back to the client?
At the moment, I am trying to place the token in the auth header and 'redirect' to the client URL. This is working (I can see the auth token in the browser console) but how does can the SPA read the token on the Angular side? Angular would need to access the HTTP Headers, get the token and save it in the session storage.
POST /login
router.post('/', (req, res, next) => {
// Passport authentication strategy
passport.authenticate('local', function (err, user, info) {
// Callback after authentication strategy is complete
// Check error
if (err) {
console.error(err);
return res.status(404).json(err);
}
// Check if user was returned
if (user) {
// Generate JWT token
let jwt;
jwtToken = generateJwt();
// Set authorization header
res.set({
'Content-Type': 'application/json',
'Authorization': `Bearer: ${jwtToken}`,
});
// Redirect to the client
return res.redirect('http://localhost:4200/login');
//return res.json(jwtToken);
}
})(req, res);
});
Question:
In the Angular component, is it possible to parse the Authorization header to get the token that was sent by the server? I tried using the activatedRoute module but wasn't able to get access to the header data from the initial page load. I also tried adding the token as a URL parameter in the GET request but that makes the URL extremely long and exposes the token in plain text. Are there any reasonable ways send the token from the server to the client safely?
UPDATE:
I am going to try sending the token in a cookie using express cookieParser similar to this answer in another post. That way the SPA can access the token saved in the cookie, parse it, and then save it in session storage. However, I am hesitant to do this and am not sure if this is going to be the most sustainable technique, since this requires an additional module to parse the cookie in the SPA.
let options = {
maxAge: 1000 * 60 * 15,
httpOnly: false,
signed: true
}
// Set cookie
res.cookie('jwt-token', jwt, options)
// Redirect to the client
return res.redirect(302, 'http://localhost:4200/login');

Respond to User with CSS after failed authentication. (Passport)

I have a site that allows users to login by clicking login which will popup a Bootstrap modal without redirecting the user. I see on many sites that if you fail to login you will remain on that route and all that will change is a message will appear notifying you of the failure to login. I would like to do this with passport local where after a failed authentication I can simply show some CSS while still having the Bootstrap modal up.
However, all that I can seem to do is show a req.flash and it seems that I have to redirect after a failed authentication or be shown an error.
router.post("/login", passport.authenticate("local",
{
successRedirect: "/profile",
failureRedirect: "/",
failureFlash : true
})
);
Currently, this is all I can do. Is it possible to do it the way I've mentioned without redirecting? Passport documentation shows no sight of this.
Of course, you can do whatever you want. From the official docs:
app.post('/login',
passport.authenticate('local'),
function(req, res) {
// If this function gets called, authentication was successful.
// req.user contains the authenticated user.
res.redirect('/users/' + req.user.username);
});
"By default, if authentication fails, Passport will respond with a 401 Unauthorized status, and any additional route handlers will not be invoked. If authentication succeeds, the next handler will be invoked and the req.user property will be set to the authenticated user."
So all you have to do is handle the 401 response in your client-side logic and then based on it show a message/CSS.

How do I make Instagram OAuth (or any OAuth) always force the user to sign in, even if they are signed into the application's website?

I'm building a tool where a user would want to authenticate multiple Instagram accounts into the application. The problem I run into is if the user has already authenticated one and I initiate the OAuth dialogue again, the OAuth assumes that I want the access token of the user already logged in.
I have an iOS app that is similar and the way to avoid this is clear all the cookies of the Safari browser.
I'm using the instagram-node module right now.
app.get('/authenticateInstagram', function(req, res) {
res.redirect(ig.get_authorization_url(redirectURI, {
scope: ['basic', 'public_content', 'likes', 'follower_list', 'relationships'],
state: 'a state'
}));
});
app.get('/handleInstagramAuth', function(req, res) {
ig.authorize_user(req.query.code, redirectURI, function(err, result) {
if (err) {
console.log(err.body);
res.send('Didn\'t work');
} else {
console.log('Yay! Access token is ' + result.access_token);
res.send('You made it!!');
}
});
});
So when I try to add another IG account (now that I've signed into an Instagram account already), I don't get prompted to log in by the OAuth sequence. It assumes I'm the previously signed in user.
I can think of the following approaches
You can make a request to logout end point if Instagram supports it. Once you logout you can login again
I am not sure if instagram supports prompt=login parameter. If so it should take you to login page for each call.
I checked Instagram documentation and I think you can use Client side (Implicit) flow to login every time to get access token.

Resources