Passport.js stateless/sessionless google auth - node.js

I want to write a stateless node api with passport.js for authentication.
I want to create an oauth google api endpoint that returns the api key on success and other details on success.
Google API route
router.get('/',passport.authenticate('google', { scope : ['profile', 'email']}));
router.get('/callback', function(req, res, next) {
passport.authenticate('google', { session: false, failureRedirect: '/#/login'}, function(err, user, info) {
console.log('------------------in google callback-----------------');
if (err) res.status(500).json({status_code: 500, message: "Authentication error", data : err});
if (!user) {
res.status(404).json({status_code: 404, message : "User not found/created"});
}
var token = 'JWT KEY TO USE AS API TOKEN';
res.status(200).json({status_code: 200, message : "Success", data : {token : token, user:user }});
})(req, res, next);
});
When i open my api endpoint in browser on successfull authentication the json response is just printed on the screen and i have no way to capture the same in a variable. Calling the same api endpoint via ajax doesn't work.
This is how i recieve the json response
How do i create a google login api endpoint that works without
sessions and returns a token?
How can i run this via ajax? Is there any way to call this api end point and recieve the response in a success callback?

The Google authentication process needs to happen in the client (so the browser will always open that new page) and then the Google server needs to contact your server directly (at your callback endpoint), otherwise the client could just pretend they were authenticated.
So if you are trying to do this in a single request to your server or without a server, that is not possible.

Related

Login with Facebook Flow in REST (Express.js with TypeScript + Passport.js) - few questions

i have few questions about login with facebook flow in REST application. I use Passport.js, Express.js, Typeorm and TypeScript. I don't implement client site yet.
First i created facebook strategy and i get a profile information in this place in code, but i want to process profile (check, save and generate JWT) in controller by use service layer.
passport.ts
const facebookStrategyCallback = async(accessToken: any, refreshToken: any, profile: any, done: any) => {
// I can get and process profile here, but i want to do it in controller use only
// service layer to check, save and generate JWT token.
done(null, profile);
};
This is my controller with facebook route and callback route:
facebookAuth = (request: Request, response: Response, next: NextFunction) => {
passport.authenticate('facebook')(request, response, next);
};
facebookAuthCallback = (request: Request, response: Response, next: NextFunction) => {
passport.authenticate('facebook', {
session: false,
failureRedirect: '/authenticate/fail'
}, (error, profile) => {
// process profile here using service functions
// But what do next?
})(request, response, next);
};
My flow for now is:
In client someone click to Login with Facebook (redirect to localhost:8080/oauth2/facebook)
User see facebook login form and fill it
User profile with query params CODE back to server site application localhost:8080/oauth2/facebook/callback?Code={somecode} (Is this correct way?)
...
And now what's next? What i should do with CODE get from (/ouath2/facebook/callback?CODE={somecodehere}). I can process profile save it into database, but how to back token to client? With redirect and query params? it's less security i guess.
Maybe i should set facebook callback url to localhost:3000/facebook/callback - but what i should do with this code from query params when i pass it back to server site?
Can someone write me a correct flow in REST application?

Web and mobile, where to store token/cookies

I'm developing a program which consists of a back-end server, a mobile application, and a web application. I have added JWT token to my mobile application and I'm storing in async storage. However, I cannot find an appropriate way to do in web server.
I have created a middleware file for creating and checking token's validity. In my API route's I'm doing the following
router.post('/:url', middleware.checkToken, (req, res, next)=>
{
...
}
So, every time I call this API, middleware file checks for the token. In my mobile application, I'm storing the token in the async storage and pass it to the web server.
However, in the browser side, I want to store the token inside a cookie rather than storing in local storage. How can I do this without changing my code?
This is mobile login API.
router.post('/login', (req,res,next) => {
let username = req.body.username;
let password = req.body.password;
User.findOne({'username' : username})
.exec()
.then(doc =>{
if(doc.validPassword(password))
{
let token = jwt.sign({
id: doc.id,
email: doc.email,
},
config.secret,
{ expiresIn: '24h' // expires in 24 hours
}
);
res.status(200).json({
success: true,
message: 'Authentication successful!',
token: token
});
}
else{
// invalid credentials
res.send(403).json({
success: false,
message: 'Incorrect username or password'
});
}
})
})
I don't want a separate file for web login. I just want to use the same code, without copying to another file.
Should I write another different code for both mobile and web but one send a cookie, other sends plain token? Is there any way to achieve this with simple solution?
In short:
Mobile users send credentials to the mobile login page and they receive token.
Web users send credentials to the web page and they receive a cookie (a token resides inside the cookie). I don't want to have separate code for login.
You can easily add a new cookie in the front-end with document.cookie = ... (MDN document cookie)
In your middleware, you just have to parse for cookie instead of some Bearer token or whatever.

How to protect routes on a client server with JWT generated from my RESTful backend API?

I was attempting to build a signup/signin application using Nodejs. By looking at the articles, I came to know that it's a good structure to design your app so that your backend is actually a RESTful API and your client accesses that API. (Both client & server running on different servers, whereas the client is just a plain old static file server).
Now things went smooth until I had to sign users in. When the API endpoint (/signin) with the specific data is accessed, the data is validated against the database and if Okay, I am signing a JSON Web Token and passing it along to the client.
But the problem is that with this, I can only secure routes on my API i.e. I can only enforce that a user must be signed in to access a specific backend API endpoint.
But what can I do to enforce the same thing on my client with this JWT? For example, if in my client I have dashboard.html and I want it only accessible to signed in users, a user can go ahead and get a JWT generated. But how does this JWT come into play about restricting client routes?
My Signin Route:
app.post('/signin', (req, res) => {
var data = req.body;
if (!exists(data.username) || !exists(data.password))
return res.status(422).json({
message: 'All fields are required'
});
const users = db.get('users');
users
.findOne({
username: data.username,
password: shajs('sha256').update(data.password).digest('hex')
})
.then((user) => {
if (user) {
jwt.sign({
_id: user._id,
username: user.username
}, 'keyboard_cat', {
expiresIn: '1h'
}, (err, tok) => {
return res.status(200).json({
message: 'OK',
token: tok
});
});
return;
}
return res.status(200).json({
message: 'Invalid Username or Password.'
})
});
});
You can use conditional render on the front-end side. You can fire an api with the api token (generated from '/signin' api) which will tell you wether the api token is valid or not whenever you enter the route.
On the basis of the response from the server about the token you can decide which page to render (normal one or the unauthorised page).
There is also a better approach, send the api token in every route in the header, and if the token is malformed or invalid return 401 error from backend. Catch this error globally(or you can use response interceptor which is provided by axios) and then do conditional rendering.

JWT node protected data

I'm currently working on a MEAN full stack web project for a little marketplace app. This project's build in 3 parts :
- server -> node.js express mongoose
- front web -> angular 4
- front mobile -> ionic
I've to build this simple API REST, with a classic CRUD, but I have to use JWT to secure my adverts (for the market place).
An user will be able to delete or modify only the advertisements which he himself create, using JWT verification.
Currently, I have a token verification's middle-ware, but it does not prevent a user from deleting an ad created by another user.
I'm calling my middle-ware as I understood on tutorials, it can be change.
And after a lot of research, i only found information about authentication with JWT, then if someone can help my, thanks.
//my token verification's middle-ware
function verifyToken(req, res, next) {
var token = req.headers['x-access-token'];
if (!token)
return res.status(403).send({ auth: false, message: 'No token provided.' });
jwt.verify(token, config.secret, function(err, decoded) {
if (err)
return res.status(500).send({ auth: false, message: 'Failed to authenticate token.' });
// if everything good, save to request for use in other routes
req.userId = decoded.id;
next();
});
}
//an example of middle-ware call
router.delete('/:id',VerifyToken, (req, res) => {
advertModel.findById(req.params.id, (err, advert) => {
if(!advert){
res.json({message:"No advert corresponding"})
}
advert.remove((err) => {
if(err){
console.log(err);
}
res.json({message: 'Successfully deleted'});
});
});
});
This application is still under construction, then if you have any comments that would allow me to improve the few pieces of code that you see, go.
jwt token when comes with a request, if that token is valid it just pass the request to next with that user credential, but if the token is not valid, it stops the request lifecycle. But it does not have anything to do with the things you are trying to do.
You can write a simple conditional in your controller code like this
if(req.user.id !== youradd.user_id){
return ('with valid message and http code')
#shahinmahmud is right. Basically there are two parts to what you are doing. Authentication and Authorization. Authentication is done by JWT token validation. Authorisation is to restrict access based on the user. In your case, if it's just access to one resource, a simple if-else will do. Otherwise you need to look into some user management libraries.
This definition should probably help

express passport-linkedin, making api requests

I'm using express and passport-linkedin. The authentication flow works fine, I can get the user's basic profile, and now I want to make an API request. /v1/people/~/connections, for example.
I've done some reading and trial and error, but all I get is Wrong Authentication Scheme or Internal Server Error.
I have the token and tokenSecret given to the verify callback of the LinkedInStrategy instance. How do I go from those to an authorized API request?
I use a 'isLegit' function running as middleware.
Example :
app.get('/api/mysecuredpage',isLegit,function(req,res){
res.render('mysecurepage');
});
function isLegit(req, res, next) {
// if user is authenticated in the session, next
if (req.isAuthenticated())
return next();
// if they aren't send an error
res.json({error:'You must be logged in to view information'});
}
EDIT :
To make a request to the linkedIn api, just set up your request with the following options :
var options = {
url: 'https://api.linkedin.com/v1/people/~/connections',
headers: { 'x-li-format': 'json' },
qs: { oauth2_access_token: user.access_token }
};
request(options,function(err,res,body){
console.log(body);
});
access_token is the name of the variable in your passport strategy, it could be different depending how you've set it up. basically, it's one of the fields of your authenticated user ;-)

Resources