So I have been researching for hours and trying different things and have been researching for hours to no avail. The call is to get a JWT token after providing user and pass.
function listenForLogin() {
console.log('listening')
$('#submit-btn').on('click', e => {
e.preventDefault();
console.log('button-pressed');
const username = $('#user-input').val().trim();
const password = $('#pass-input').val().trim();
var user = {}
user.username = username;
user.password = password
console.log(user);
$('#user-input').val('');
$('#pass-input').val('');
authenticateUser(user);
});
}
//send to autenticate
function authenticateUser(user) {
console.log('trying to authenticate');
const settings = {
url:"/api/auth/login",
data: JSON.stringify(user),
dataType: "json",
method:"POST",
success: (data) => {
console.log('authenticated user');
redirectWithToken(data.authToken, user);
},
error: (err) => console.log(err)
}
$.ajax(settings);
}
When it hits the server morgan sees that there was a request but i get back a status of 400. here is my routes
'use strict';
const express = require('express');
const passport = require('passport');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const {JWT_SECRET, JWT_EXPIRY} = require('dotenv').config();
const router = express.Router();
const createAuthToken = function(user) {
return jwt.sign({user}, 'shade', {
subject: user.username,
expiresIn: '7d',
algorithm: 'HS256'
});
};
const localAuth = passport.authenticate('local', {session: false});
router.use(bodyParser.json());
router.post('/login', localAuth, (req, res) => {
const authToken = createAuthToken(req.user.serialize());
res.json({authToken});
});
const jwtAuth = passport.authenticate('jwt', {session: false});
router.post('/refresh', jwtAuth, (req, res) => {
console.log('refresh targeted');
const authToken = createAuthToken(req.user);
res.json({authToken});
});
router.get('/dashboard/:user', jwtAuth, (req, res) => {
res.redirect(`https:flow-state.herokuapp.com/dashboard/${req.params.user}`);
})
module.exports = router;
and I am having a hard time understanding how passport.authenticate('localAuth') works so here is my strategies file just in case you need that
Update: I am getting some kind of error when checking the requests on fiddler.
RESPONSE BYTES (by Content-Type)
~headers~: 132
~???????~: 11
anybody got any clue what that means?
Did you miss the content-type in the ajax settings?
Add contentType: "application/json" in the ajax settings and try again.
Note :
dataType defines the data type expected of the server response.
contentType defines the data type of the content which will be sent to the server. Default is: "application/x-www-form-urlencoded"
8 hours later and a big headache a solution is here. #vignz.pie you were right but I needed to send the 'Content-Type': 'application/json' in the headers along with strigify the data setting the processData: false did the trick. Thanks for the help!
function listenForLogin() {
console.log('listening')
$('#submit-btn').on('click', e => {
e.preventDefault();
console.log('button-pressed');
const username = $('#user-input').val().trim();
const password = $('#pass-input').val().trim();
$('#user-input').val('');
$('#pass-input').val('');
authenticateUser(username, password);
});
}
//send to autenticate
function authenticateUser(user, pass) {
var info = {
username: user,
password: pass
};
console.log(info)
const settings = {
url:"/api/auth/login",
headers: {
"Content-Type": "application/json"
},
data: JSON.stringify(info),
processData: false,
dataType: "json",
method:"POST",
success: (data) => {
console.log('authenticated user');
redirectWithToken(data.authToken, user);
},
error: (err) => console.log(err)
}
$.ajax(settings);
}
Related
I'm trying to create a platform, once I log in it, creates a token and store it in the cookie. I have successfully been able to create a route that stores the cookie using node js(I could see it saved in postman). But once I try to use the route in my flutter app, it seems the the token doesn't save anywhere.
How do I save the cookie and use it to validate if the user should be logged in or should log in again
Login.dart
Future<void> _signIn(email, password) async {
try {
setState(() {
LoadingWidget.show(context);
bool _absorbme = true;
});
var url = "http://192.168.8.23:3000/route/login"; // iOS
final http.Response response = await http.post(
Uri.parse(url),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'email': email.toLowerCase(),
'password': password,
}),
);
SharedPreferences prefs = await SharedPreferences.getInstance();
var parse = jsonDecode(response.body);
await prefs.setString('msg', parse["msg"]);
await prefs.setString('success', parse["success"]);
String? msg = prefs.getString("msg");
} finally {
setState(() {
LoadingWidget.hide(context);
bool _absorbme = false;
});
}
}
My Route.js file
const express = require('express');
const router = express.Router();
const Users = require('./model/model')
const passport = require('passport')
const bcrypt = require("bcrypt");
const { createTokens, validateToken, authenticateToken } = require("./JWT");
const Server = require('http-proxy');
router.get('/', (req, res)=>{
res.send('Hello world')
})
router.post("/signup", async (req, res) => {
const { username, email, password } = req.body;
let user = await Users.findOne({ email });
if (user){
return res.status(400).json({success: 'false', msg: "Email Already Exist"});
}
bcrypt.hash(password, 10).then((hash) => {
Users.create({
username: username,
password: hash,
email:email,
})
.then(() => {
res.json({success: 'true', msg: 'login Successfully'});
})
.catch((err) => {
if (err) {
res.status(400).json({success: 'false', msg: 'Failed to save'});
}
});
});
});
router.post("/login", async (req, res) => {
const { email, password } = req.body;
let user = await Users.findOne({ email });
if (!user) {
return res.status(400).json({success: 'false', msg: 'Authentication Failed, User not found'});
}
const dbPassword = user.password;
bcrypt.compare(password, dbPassword).then((match) => {
if (!match) {
res
.status(400)
.json({success: 'false', msg: 'Authentication failed, wrong password'});
} else {
const accessToken = createTokens(user);
var token = res.cookie("access-token", accessToken, {
maxAge: 60 * 60 * 24 * 30 * 1000,
httpOnly: true,
});
res
.status(200)
.json({success: 'true', msg: 'Successfully logged In'});
}
});
});
router.get("/profile", validateToken, async (req, res) => {
let user = await Users.findOne({email: req.decoded.email});
return res.json({
email: user.email,
balance: user.balance,
name: user.username
})
router.get("/logout", validateToken, (req, res) => {
return res
.clearCookie("access-token")
.status(200)
.json({success: "true" , msg: "Successfully logged out" });
});
router.get("/authenticate" ,authenticateToken, (req,res)=>{
})
module.exports = router;
enter image description here
Why not use JWT it can help you manage your users for the numbers of hours you specified
Create authorize endpoint on your api to refresh token when expired.
In dart side, create an authenticated client singleton.
class AuthenticatedClient extends http.BaseClient {
factory AuthenticatedClient() => _instance;
AuthenticatedClient._();
static final _instance = AuthenticatedClient._();
int? expiresAt;
String? token;
final _client = http.Client();
void setParams(http.Response res) {
final response = jsonDecode(res.body);
expiresAt = response['expiresAt'];
token = response['token'];
}
Future<void> authorize() async {
// Send a request to refresh token, update token and expiresAt
// accordingly. Note that, you can't use _client to send request, use
// htt.put, http.post.
// Ex:
//
// final response = await http.put(
// Uri.parse('https://myapi.com/authorize'),
// headers: {
// 'Content-Type': 'application/json',
// },
// body: jsonEncode({
// 'email': <email>,
// 'password': <password>,
// }),
// );
//
// setParams(response);
}
#override
Future<http.StreamedResponse> send(http.BaseRequest request) async {
// Ensure you set params for the first time.
assert(expiresAt != null);
if (expiresAt! < DateTime.now().millisecondsSinceEpoch) {
await authorize();
}
request.headers['Authorization'] = 'Bearer $token';
return _client.send(request);
}
}
On your api, generate a token on login or signup request and send token to client. For this example, response format is that:
{
'token': <generated token>,
'expiresAt': <timestamp>,
}
When you got response, call setParams method of AuthenticatedClient and set request params. I didn't add code for error handling to the example, don't forget to add.
Use AuthenticatedClient like this:
AuthenticatedClient().get(Uri.parse('https://myapi/profile'));
I try to post json to Line' messaging api with koa.js and request-promise but got error as attached image :
I'm using heroku with koa.js to connect with Line messaging api.
Here is my code :
const Koa = require('koa');
const Router = require('koa-router');
const logger = require('koa-logger');
const bodyParser = require('koa-bodyparser');
const app = new Koa();
const router = new Router();
const port = process.env.PORT || 4000;
app.use(logger());
app.use(bodyParser());
app.on('error', (err, ctx) => {
console.log('server error', err, ctx)
});
app.use(router.routes());
app.use(router.allowedMethods());
router
.get('/', (ctx, next) => {
console.log(ctx);
ctx.body = ctx;
})
.post('/webhook', async (ctx, next) => {
var reply_Token = ctx.request.body.events[0].replyToken;
console.log('token = ' , ctx.request.body.events[0].replyToken);
var rp_body = JSON.stringify({
replyToken: reply_Token,
messages: [{
type: 'text',
text: 'Hello'
},
{
type: 'text',
text: 'How are you?'
}]
});
var options = {
method: 'POST',
url: 'https://api.line.me/v2/bot/message/reply',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {xxxxxxxx}'
},
json: true,
body: rp_body
};
var rp = require('request-promise');
rp(options)
.then(function (parsedBody){
console.log('rq success');
})
.catch(function (err) {
console.log('server error', err, ctx);
});
});
app.listen(port);
module.exports = { app }
After try to solving with changing variable but seem doesn't work at all. This is what I try to adapt from using Node.Js to Koa.js.
Solving the problems!, thanks to #num8er for pointing to it.
As the body entity has 'json : true' so the body is already stringify by this. There's no need to do stringify before.
So removing it like :
var rp_body = JSON.stringify({
replyToken: reply_Token,
messages: [{
to
var rp_body = ({
replyToken: reply_Token,
messages: [{
However after pull off stringify from body you might encounter 'Invalid Token' if process api.line.me verification.
It's what it should be, because api.line.me will throw zeros as reply token for verification and Koa.js look at it like an error.
So checking for if token is zeros then send status 200 to complete the verification, otherwise do the POST METHOD if token is not zeros.
if(reply_Token === '00000000000000000000000000000000') {
ctx.status = 200;
} else {
//POST METHOD
}
How can I solve this?
i want get token in router and then router send response.but in this middle ware my code get token after routes called.and how can i access middleware token for verify user
var express = require("express");
var request = require("request");
var router = express.Router();
var supertoken;
tokenmiddleware = function(req, res, next) {
console.log("this is auth middleware");
try {
var options = {
method: "POST",
url: "here is my auth server url",
headers: {
json: true,
Authorization: "", //
"Content-Type": "application/x-www-form-urlencoded"
}
},
form: {
grant_type: "password",
username: "usrename",
password: "password"
};
request(options, function(error, response, body1) {
if (error) {
throw new Error(error);
} else {
let info = JSON.parse(body1);
//it parse the body1 into json so we can use property of body1.
supertoken = info.access_token; //it gives the token of the super admin.
// console.log(supertoken)
// console.log(process.env.ACCESS_TOKEN);
//return supertoken
}
});
console.log("superrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr");
console.log(supertoken);
next();
} catch (error) {
return res.status(401).json({ message: "Auth Failed." });
}
}; //this middleware gave me a token.
router.post("/verifyUser", tokenmiddleware, (req, res) => {
//here i want my middleware token (but it calls after the route)
//here i applied logic of verify user but token is not working.(it say's undefined)
});
Your middleware includes request which is an asynchronous operation. And you call next() outside of request callback. After your middleware called you fire next() before request is finished, just move next inside request callback
tokenmiddleware = function (req, res, next) {
console.log('this is auth middleware');
try {
var options = {
method: 'POST',
url: 'here is my auth server url',
headers: {
json: true,
Authorization: '', //
'Content-Type': 'application/x-www-form-urlencoded',
},
form: {
grant_type: 'password',
username: 'usrename',
password: 'password',
},
};
request(options, function(error, response, body1) {
if (error) {
throw new Error(error);
} else {
let info = JSON.parse(body1);
//it parse the body1 into json so we can use property of body1.
supertoken = info.access_token; //it gives the token of the super admin.
// console.log(supertoken)
console.log('superrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr');
console.log(supertoken);
req.userToken = info.access_token;
next();
}
});
} catch (error) {
return res.status(401).json({ message: 'Auth Failed.' });
}
};
router.post("/verifyUser", tokenmiddleware, (req, res) => {
console.log(req.userToken); // should be your token
});
A little background -
I have my NodeJS server running on port 3001 and my React application on port 3000. I've set up a proxy in my React application package.json to proxy all requests to port 3001 -
"proxy": "http://localhost:3001"
Now when I'm using Axios in my React application to make POST request on 'users/authentication' route on my NodeJS server, the request body is being parsed as blank on the Node server
const request = {
method: 'POST',
url: `/users/authenticate`,
headers: {
'Content-Type': 'application/json'
},
body: {
email: email,
password: password
}
};
console.log(request);
axios(request).then((res) => {
//handle success
});
}).catch((err) => //handleError ))
But unfortunately, the NodeJS application crashes because it's parsing req.body as blank. The relevant code on Server side -
//in index.js file
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json())
app.use('/users', users);
//in users.js file
const express = require('express');
const router = express.Router();
const userController = require('../controllers/users');
router.post('/authenticate', userController.authenticate);
module.exports = router;
//in UserController
const userModel = require('../models/user');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
module.exports = {
authenticate: function (req, res, next) {
console.log(req);
userModel.findOne({ email: req.body.email }, function (err, userInfo) {
if (err) {
next(err);
} else {
if (bcrypt.compareSync(req.body.password, userInfo.password)) {
const token = jwt.sign({ id: userInfo._id }, req.app.get('secretKey'), { expiresIn: '1h' });
res.json({ status: "success", message: "user found!!!", data: { user: userInfo, token: token } });
} else {
res.json({ status: "error", message: "Invalid email/password!!!", data: null });
}
}
});
},
}
But when I'm logging the request in the 'authenticate' function, the req.body is being parsed as blank which is making the application crash.
Now when I do this exact thing using 'Request' package on React, it's working completely fine. Below code using 'Request' library -
var options = {
method: 'POST',
url: 'http://localhost:3000/users/authenticate',
headers:
{
'Content-Type': 'application/json'
},
form:
{
email: email,
password: password
}
};
console.log(options);
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
Any idea why it's working fine using Request and not on Axios?
The only problem with 'Request' is that I have to mention the complete URL - 'localhost:3000...' instead of just the route like in Axios.
Any other suggestions on how I could implement this better would be great also.
The property for adding data to the request body in Axios is called data not body.
I am building a web app using Symfony 4 and I am trying to implement the back end as a REST API.
As part of the login process, I have created an endpoint that returns a JWT upon receiving a valid username and password. I then save the JWT to local storage in the browser as so:
$(document).ready(function() {
$('.js-login-form').submit(function (e) {
e.preventDefault();
let username = $('#_username').val();
let password = $('#_password').val();
let data = JSON.stringify({_username: username, _password: password});
$.ajax({
method: 'POST',
url: '/api/tokens',
contentType: "application/json",
dataType: 'json',
data: data,
success: function(data) {
localStorage.setItem('token', data.token);
// Add Header to the request Authorization: "Bearer " . data.token
window.location='/app';
},
error: function(jqXHR) {
var errorData = JSON.parse(jqXHR.responseText);
console.log(errorData);
}
});
});
});
My question is how I can add the JWT to the header so I can redirect the user to the password protected area. My guard authenticator will then validate the token accordingly.
Many thanks
Do you mean add JWT to the header in backend?
If yes, you can create middleware to check user is auth or not.
This is example :
// add jwt module
const jwt = require('jsonwebtoken');
async function isAuthValid(req,res,next) {
try {
// check header
let token = req.headers['authorization'];
if (token.startsWith('Bearer ')) {
// check token type
token = token.slice(7, token.length).trimLeft();
} else {
return res.send('wrong token type');
}
if (token) {
// ? check token
let verifiedUser = await jwt.verify(token, 'somesecret', (err, decoded) => {
if (err) {
return res.send(err.message);
} else {
return decoded
}
});
req.authUser = verifiedUser
next();
}
} catch (err) {
return res.send('no token provided');
}
}
module.exports = isAuthValid
Registering as middleware on your route
const express = require('express');
const isAuthValid = require('./checkAuthUser.js');
const app = express();
app.get('/myRoute', isAuthValid, (req,res) => {
return res.send('protected endpoint')
});