I am trying to retrieve my jwt token after login within my Profile component and store the token as within localstorage. I know that localstorage isnt the best option but this will be a native mobile app so localstorage from what I know is my best option. However when I sign in , I receive a token , here is an token that Ive received recently
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaGVjayI6dHJ1ZSwiaWF0IjoxNTYzMDUzMzk4LCJleHAiOjE1NjMwNTQ4Mzh9.tw8ks-jFZID5rmwhoNTkWV8598niE3zMFIDk4Gz-sVg
when my Profile component trys to retrieve /current it use jwt malformed
Server.js
var express = require('express');
var cors = require('cors');
var bodyParser = require('body-parser');
var app = express();
var port = process.env.PORT || 5000;
var morgan = require('morgan');
const auth = require('./middleware/auth');
const User = require('./models/User');
app.use(cors());
app.use(
bodyParser.urlencoded({
extended: false
})
);
app.use(bodyParser.json());
/*========= Here we want to let the server know that we should expect and allow a header with the content-type of 'Authorization' ============*/
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Headers', 'Content-type,Authorization');
next();
});
// use morgan to log requests to the console
app.use(morgan('dev'));
var Users = require('./routes/Users');
app.use('/users', Users);
// Create a Server
const PORT = process.env.PORT || 5000; // Environment variable or port 5000
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
module.exports = app;
User.js
const express = require('express');
const users = express.Router();
const cors = require('cors');
const jwt = require('jsonwebtoken');
var exjwt = require('express-jwt');
var jwtauth = require('../middleware/authjwt.js');
const bcrypt = require('bcrypt');
const bodyParser = require('body-parser');
const User = require('../models/User');
const config = require('config');
const auth = require('../middleware/auth');
const secret = 'dasdsad';
users.use(
bodyParser.urlencoded({
extended: true
})
);
users.use(bodyParser.json());
users.use(cors());
users.post('/register', (req, res) => {
const today = new Date();
const userData = {
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: req.body.password,
created: today
};
User.findOne({
where: {
email: req.body.email
}
})
//TODO bcrypt
//Need validation to appear on console and in view
.then(user => {
if (!user) {
bcrypt.hash(req.body.password, 10, (err, hash) => {
userData.password = hash;
User.create(userData)
.then(user => {
res.json({ status: user.email + 'Registered!' });
})
.catch(err => {
res.send('error: ' + err);
});
});
} else {
res.json({ error: 'User already exists' });
}
})
.catch(err => {
res.send('error: ' + err);
});
});
users.post('/authenticate', (req, res) => {
User.findOne({
where: {
email: req.body.email
}
}).then(user => {
if (user) {
if (bcrypt.compareSync(req.body.password, user.password)) {
const payload = {
check: true
};
const token = jwt.sign(payload, config.get('myprivatekey'), {
expiresIn: 1440 // expires in 24 hours
});
res.json({
message: 'authentication done ',
token: token
});
console.log('Successful Login');
console.log(user.first_name);
} else {
res.json({ message: 'please check your password !' });
console.log('incorrect password');
}
} else {
res.json({ message: 'user not found !' });
console.log('user cannot be found');
}
});
});
//users.get('/something', [express.bodyParser(), jwtauth], function(req, res) {
// do something
//});
// app.all('/api/*', [express.bodyParser(), jwtauth]);
users.get(
'/current',
exjwt({ secret: config.get('myprivatekey') }),
async (req, res) => {
const user = await User.findById(req.user._id).select('-password');
console.log(user);
res.send(user);
}
);
Login
import React, { Component } from 'react';
class Login extends Component {
constructor() {
super();
this.state = {
email: '',
password: '',
errors: {}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
onSubmit(e) {
e.preventDefault();
const user = {
email: this.state.email,
password: this.state.password
};
var token = window.localStorage.getItem('token');
fetch('http://localhost:5000/users/authenticate', {
method: 'POST', // or 'PUT'
body: JSON.stringify(user), // data can be `string` or {object}!
headers: {
'Content-Type': 'application/json'
}
});
}
render() {
return (
<div className='container'>
<div className='row'>
<div className='col-md-6 mt-5 mx-auto'>
<form noValidate onSubmit={this.onSubmit}>
<h1 className='h3 mb-3 font-weight-normal'>Please sign in</h1>
<div className='form-group'>
<label htmlFor='email'>Email address</label>
<input
type='email'
className='form-control'
name='email'
placeholder='Enter email'
value={this.state.email}
onChange={this.onChange}
/>
</div>
<div className='form-group'>
<label htmlFor='password'>Password</label>
<input
type='password'
className='form-control'
name='password'
placeholder='Password'
value={this.state.password}
onChange={this.onChange}
/>
</div>
<button
type='submit'
className='btn btn-lg btn-primary btn-block'
>
Sign in
</button>
</form>
</div>
</div>
</div>
);
}
}
export default Login;
This is how I am currently fetching the token within My Profile component
componentDidMount() {
var token = localStorage.getItem('token');
fetch('http://localhost:5000/users/current', {
//cahng taht
method: 'GET',
mode: 'cors',
headers: { Authorization: 'Bearer ' + token }
});
}
I guess the problem is on the expiresIn. 'expiresIn' expressed in seconds or a string describing a time span. You set 1440, which means 1440/60 = 24minutes => expires after 24 minutes not after 24 hours... Could you please try to set as below:
const token = jwt.sign(payload, config.get('myprivatekey'), {
expiresIn: '24h' // expires in 24 hours
});
Related
Getting my signup and login form to connect to my local MongoDB is not working. I am using a Passport for authentication. At first, it threw up "no username was given error". I fixed that by defining usernameField. Now, when I fill in details on the frontend form, it is not sending to the MongoDB database on clicking submit. The values are just there.
Here is My Server.js
const express = require("express"),
connect = require("./config/db"),
passport = require("passport"),
bodyParser = require("body-parser"),
User = require("./model/trialModel");
LocalStrategy = require("passport-local").Strategy,
routes = require('./route/userRoute')
const path = require('path')
connect()
const app = express();
app.engine('html', require('ejs').renderFile)
app.set("view engine", "html");
app.set('views', path.join(__dirname, 'views'))
app.use(bodyParser.urlencoded({ extended: true }));
app.use(require("express-session")({
secret: "Rusty is a dog",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
// passport.use(User.createStrategy());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
//=====================
// ROUTES
//=====================
// Showing home page
app.get("/", function (req, res) {
res.render("home");
});
// Showing secret page
app.get("/secrete", isLoggedIn, function (req, res) {
res.render("secrete");
});
// Showing register form
app.get("/register", function (req, res) {
res.render("register");
});
//Showing registration success page
app.get("/success", function (req, res) {
res.render("success");
});
// // Handling user signup
// app.post("/register", function (req, res) {
// var username = req.body.username
// var password = req.body.password
// var fullname = req.body.fullname
// var email = req.body.email
// User.findByUsername(username, function(err, user) {
// if (err) {
// console.log(err)
// } else if (user){
// res.send('username already exist!')
// } else{
// User.register(new User({ username: username, fullname: fullname, email: email}), password,
// function (err, user) {
// if (err) {
// console.log(err);
// return res.render("register");
// } else{
// res.redirect('/success')
// }
// passport.authenticate("local")(
// req, res, function () {
// res.render("secrete");
// });
// });
// }
// })
// });
//Showing login form
app.get("/login", function (req, res) {
res.render("login");
});
// //Handling user login
// app.post("/login", passport.authenticate("local", {
// successRedirect: "/secrete",
// failureRedirect: "/login"
// }), function (req, res) {
// });
// //Handling user logout
// app.get("/logout", function (req, res) {
// req.logout(function(err){
// if (err){
// return next(err)
// }
// res.redirect("/");
// });
// });
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) return next();
res.redirect("/login");
}
app.use('/', routes)
var port = process.env.PORT || 4000;
app.listen(port, function () {
console.log("Server Has Started!");
});
Here is my controller.js
const User = require('../model/trialModel')
passport = require("passport")
//sign up
exports.signUp = (req, res) => {
var username = req.body.username
var password = req.body.password
var fullname = req.body.fullname
var email = req.body.email
User.findByUsername(username, function(err, user) {
if (err) {
console.log(err)
} else if (user){
res.send('username already exist!')
} else{
User.register(new User({ username: username, fullname: fullname, email: email}), password,
function (err, user) {
if (err) {
console.log(err);
return res.render("register");
} else{
passport.authenticate("local")(
req, res, function () {
res.send('User registered successfully')
})}
});
}
})
};
//login
exports.login = passport.authenticate("local", {
successRedirect: "/secrete",
failureRedirect: "/login"
}), function (req, res) {
}
//logout
exports.logout = (req, res) => {
req.logout(function(err){
if (err){
return next(err)
}
res.redirect("/");
});
}
Here is my Schema Model:
const {Schema, model} = require('mongoose')
const passportLocalMongoose = require('passport-local-mongoose');
const newSchema = new Schema({
username: {
type: String,
require : true
},
fullname: {type: String,
require: true
},
email: {
type: String,
require: true
}
},
{timestamps: true})
newSchema.plugin(passportLocalMongoose,{
usernameField: 'fullname'
});
const todoModel = model('trial', newSchema);
module.exports = todoModel
Here is my HTML for Signup:
<h1> Sign up form </h1>
<h1>Auth-wiki</h1>
<h2>Create your free account</h2>
<form action="" id="register">
<div class="input-details">
<label for="">Full name</label> <br />
<input type="text" name="fullname" placeholder="Enter full name" id="" />
<br />
<label for="">Username</label> <br />
<input type="text" name="username" placeholder="Enter username" id="" />
<br />
<label for=""> Email</label> <br />
<input
type="email"
name="email"
placeholder="Enter username or email"
id="email"
/>
<h5 id="email-msg"></h5>
<br />
<label for="">Password</label> <br />
<input
type="password"
name="password"
placeholder="Enter Password"
id="Password"
/>
<h5 id="pass-msg"></h5>
</div>
<div class="check">
<input type="checkbox" id="checkbox" />
<label for="">Remember Password</label>
</div>
<button id="creat-account" type="submit">Create account</button>
</form>
<h1>This is home page</h1>
<li>Sign up!!</li>
<li>Login</li>
<li>Logout</li>
Here is my codes to consume the API from the Frontend:
const registerForm = document.getElementById('register')
function registerUser(event) {
event.preventDefault();
let fullname = event.target.fullname.value
let username = event.target.username.value
let password = event.target.password.value
//validation
if (!username || !password || !fullname) {
alert('All fields must be entered')
return;
}
let userObj = {
fullname,
username,
password
}
console.log(userObj)
fetchAPI(userObj,'register', 'POST').then((data) =>{
if (data) {
alert('user created successfully! Click ok to sign in')
// window.location.href = "../"
}
})
}
const API = 'http://localhost:4000';
async function fetchAPI(data, endpointurl, method) {
try {
//response from form
const response = await fetch(`${API}/${endpointurl}`, {
method: 'POST',
headers: {
"content-type": "application/json"
},
body:JSON.stringify(data) //convert the plain data to json so server is able to read it
})
const result = await response.json()
console.log(result)
} catch (error) {
}
}
registerForm.addEventListener('submit', registerUser)
I have written an API in Nodejs which helps in reset password using Mysql database.It is working fine in Postman.I have called this API in Expo IOS App.But I am getting Network request failed error. Below is the Node js program:
app.js:
var express = require('express');
var path = require('path');
var connection = require('./database.js');
var nodemailer = require('nodemailer');
const bcrypt = require("bcryptjs")
var randtoken = require('rand-token');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var flash = require('express-flash');
var session = require('express-session');
var bodyParser = require('body-parser');
const createError = require('http-errors');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
var connection = require('./database.js');
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: false}))
//send email
function sendEmail(email, token) {
var email = email;
var token = token;
var mail = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'c***********#gmail.com', // Your email id
pass: '**********' // Your password
}
});
var mailOptions = {
from: 'poornima#abccompany.com',
to: email,
subject: 'Reset Password Link - ABCCompany.com',
html: '<p>You requested for reset password, kindly use this link to reset
your password</p>'
};
mail.sendMail(mailOptions, function(error, info) {
if (error) {
console.log(1)
} else {
console.log(0)
}
});
}
app.post('/reset-password-email', function(req, res, next) {
var email = req.body.email;
console.log('email from api '+email);
connection.query('SELECT * FROM JTGDB.UserInfo WHERE email ="' + email + '"',
function(err, result) {
if (err) throw err;
var type = ''
var msg = ''
console.log(result[0]);
if (result[0].Email.length > 0) {
var token = randtoken.generate(20);
var sent = sendEmail(email, token);
if (sent != '0') {
var data = {
token: token
}
connection.query('UPDATE JTGDB.UserInfo SET ? WHERE email ="' + email + '"', data,
function(err, result) {
if(err) throw err
})
type = 'success';
msg = 'The reset password link has been sent to your email address';
} else {
type = 'error';
msg = 'Something goes to wrong. Please try again';
}
} else {
console.log('2');
type = 'error';
msg = 'The Email is not registered with us';
}
res.redirect('/');
});
})
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret: '123458cat',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}))
app.use(flash());
app.use('/', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.listen(4000, function () {
console.log('Node app is running on port 4000');
});
module.exports = app;
Below is the IOS App ForgetPassword Screen page:
ForgetPasswordScreen.js:
import React, { Component, Fragment, useState } from "react";
import { View, Text,SafeAreaView, Image, StyleSheet } from "react-native";
import { Formik } from "formik";
import * as Yup from "yup";
import FormInput from "../../components/UI/FormInput";
import FormButton from "../../components/UI/FormButton";
import ErrorMessage from "../../components/UI/ErrorMessage";
import * as authActions from '../../store/actions/auth';
import {useDispatch} from "react-redux";
import Toast from 'react-native-root-toast';
const validationSchema = Yup.object().shape({
email: Yup.string()
.label("Email")
.email("Enter a valid email")
.required("Please enter a registered email"),
});
const ForgotPasswordScreen = props => {
const [isLoading,setIsLoading] = React.useState(false);
const [error, setError] = React.useState('');
const dispatch = useDispatch();
const handlePasswordReset = async (values, actions) => {
const { email } = values;
console.log('email is '+email);
let action
action = authActions.resetpassword(
email
);
setError(null);
setIsLoading(true);
try{
await dispatch(action);
props.navigation.navigate("Login");
} catch (error) {
actions.setFieldError("general", error.message);
}
};
return (
<SafeAreaView>
<View style={styles.emailiconview}>
<Image source={require('../../assets/reset_email.png')} />
</View>
<View style ={styles.instrview1}>
<Text>
Please enter your registered email address below to
</Text>
</View>
<View style={styles.instrview2}>
<Text>receive password reset instruction</Text>
</View>
<View style={styles.emailinputview}>
<Formik
initialValues={{ email: "" }}
onSubmit={(values, actions) => {
handlePasswordReset(values, actions);
}}
validationSchema={validationSchema}
>
{({
handleChange,
values,
handleSubmit,
errors,
isValid,
touched,
handleBlur,
isSubmitting,
}) => (
<Fragment>
<FormInput
name="email"
value={values.email}
onChangeText={handleChange("email")}
placeholder="Enter email"
autoCapitalize="none"
iconName="ios-mail"
iconColor="blue"
onBlur={handleBlur("email")}
/>
<ErrorMessage errorValue={touched.email && errors.email} />
<View style={styles.buttonContainer}>
<FormButton
buttonType="outline"
onPress={handleSubmit}
title="Send Email"
buttonColor="blue"
disabled={!isValid || isSubmitting}
/>
</View>
<ErrorMessage errorValue={errors.general} />
</Fragment>
)}
</Formik>
</View>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
marginTop: 150,
},
text: {
color: "#333",
fontSize: 24,
marginLeft: 25,
},
buttonContainer: {
margin: 25,
},
emailiconview:{
justifyContent:'center',
alignItems:'center',
top:"30%"
},
instrview1:{
top:'40%',
justifyContent:'center',
alignSelf:'center'
}, instrview2:{
top:'45%',
justifyContent:'center',
alignSelf:'center'
},
emailinputview:{
top:'50%'
}
});
export default ForgotPasswordScreen;
Below is the store auth where I fetch API:
auth.js:
import Device from '../../model/Device';
import AsyncStorage from '#react-native-async-storage/async-storage'
export const FORGOTPASSWORD = 'FORGOTPASSWORD';
export const resetpassword=(email) =>{
console.log(email);
return async dispatch =>{
const response = await fetch(
'http://my_IPV4_Address:4000/reset-password-email',
{
method: 'POST',
header: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email
})
}
);
const resData = await response.text();
console.log(resData);
dispatch({type:FORGOTPASSWORD});
};
}
After running this I am getting the below error in Expo:
Network request failed
It is taking email, but not hitting the api.
email is cpoornima.1987#gmail.com
Email id to API cpoornima.1987#gmail.com
I am getting below error in NodeJs:
email from api undefined
undefined
I have added
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
to the Info.plist. I am just checking in IOS Simulator attached to Expo App. How to get through this?
Below is the auth.js fetch API which is working good.As soon as I press Send Email button, an email is going to provided email id for reset password using real Iphone device.
auth.js:
import Device from '../../model/Device';
import AsyncStorage from '#react-native-async-storage/async-storage'
export const FORGOTPASSWORD = 'FORGOTPASSWORD';
export const resetpassword=(email) =>{
const formData = new FormData();
formData.append('email',email);
console.log('Email id to API '+email);
return async dispatch =>{
fetch('http://My_IPV4_Address:4000/reset-password-email',
{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body:JSON.stringify({
email: email,
}),
})
.then(res => res.text())
.then(
(signupresult) =>{
}).catch(err =>{
console.log(err);
})
dispatch({type:FORGOTPASSWORD});
};
}
So I am using a nodejs server to post contact form information from my react app into nodemailer so that I can send emails to my gmail account (this works fine and the emails come through) My question is I want to get React to respond to the response from the post request. (IE change state and then compile a message depending on that state). However when I send an email the page redirects to show just the plain json message sent from node. How can I stop this from happening? (Beginner here so please go easy!)
FORM FILE:
import React from 'react';`enter code here`
import './form.scss';
import axios from 'axios'
class Form extends React.Component{
constructor(){
super();
this.state= {
email: "",
topic: "",
query: "",
result: ""
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit = (event)=> {
const {email, topic, query, error, success} = this.state;
const data ={
email,
topic,
query
};
event.preventDefault();
axios
.post('http://localhost:5000/', data)
.then((res) => {
this.setState({result: "success"})
})
.catch(err => {
console.error(err)
this.setState({result: "fail"})
})
}
handleChange = (event) => this.setState({
[event.target.name]: event.target.value
});
render(){
const {result, topic, email, query} = this.state;
if(result === "success"){
return(<div>YES</div>);
}
if(result === "fail"){
return(<div>NO</div>);
}
else{
return(
<div>
<form action="/" method="POST" className="contact-form" >
<label className="contact-label">Email
<input type="text" name="email" value={email} onChange={this.handleChange} />
</label>
<label className="contact-label">Topic
<input type="text" name="topic" value={topic} onChange={this.handleChange}/>
</label>
<label className="contact-label">Query
<textarea name="query" value={query} onChange={this.handleChange} id="" cols="30" rows="10"></textarea>
</label>
<button type="submit" className="submit-button" onSubmit={this.handleSubmit}>Send Email</button>
</form>
</div>
)
}
}
}
export default Form;
NODEJS FILE:
const express = require('express')
const path = require('path');
const PORT = process.env.PORT || 5000;
const { body,validationResult } = require('express-validator');
const nodemailer = require("nodemailer");
const bodyParser = require('body-parser');
const app = express();
const cors = require('cors');
const { google } = require("googleapis");
const { reseller } = require('googleapis/build/src/apis/reseller');
const OAuth2 = google.auth.OAuth2;
require('dotenv').config()
app.use(express.static('public'));
app.use(bodyParser.json());
app.use(express.urlencoded({
extended: true
}))
if (process.env.NODE_ENV === 'production'){
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('*', function(req,res){
res.sendFile(path.join(__dirname, 'client/build' , 'index.html'))
})
}
app.use(
cors({
origin: 'http://localhost:3000',
credentials: true,
})
);
app.route('/')
.post([body('email').isEmail()],(req,res) => {
const errors = validationResult(req);
const email = req.body.email
const topic = req.body.topic
const query = req.body.query
const body = `${email} sent a message with the topic: ${topic} and content: ${query} `
const myOAuth2Client = new OAuth2(
process.env.CLIENT_ID,
process.env.CLIENT_SECRET,
"https://developers.google.com/oauthplayground"
)
myOAuth2Client.setCredentials({
refresh_token: process.env.REFRESH_TOKEN
});
const myAccessToken = myOAuth2Client.getAccessToken()
const transport = nodemailer.createTransport({
service: "gmail",
auth: {
type: "OAuth2",
user: process.env.SECRET_EMAIL, //your gmail account you used to set the project up in google cloud console"
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
refreshToken: process.env.REFRESH_TOKEN,
accessToken: myAccessToken //access token variable we defined earlier
}});
const mailOptions = {
from: email,
to: process.env.SECRET_EMAIL,
subject: topic,
text: body
};
if (!errors.isEmpty()) {
console.log(error)
} else {
transport.sendMail(mailOptions, function(error, info){
if(error){
res.status(400).send({message: "failed"})
}else{
res.status(200).send({message: "success"})
};
});
}
});
app.listen(PORT, () => {
console.log(`Listening on port ${PORT}!`)
});
I'm building a 3rd server to authenticate users with company accounts on google action. I use account linking with OAuth, Linking type: Implicit. I used ngrok.io to build.
auth.js:
const jwtHelper = require("../helpers/jwt.helper");
const accessTokenSecret = process.env.ACCESS_TOKEN_SECRET || "xxx";
let auth = async (req, res) => {
try {
const userFakeData = {
email: req.body.email,
};
const accessToken = await jwtHelper.generateToken(userFakeData, accessTokenSecret);
return res.status(200).json({"token_type": "Bearer", accessToke);
} catch (error) {
return res.status(500).json(error);
}
}
login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Login Form Tutorial</title>
</head>
<body>
<div class="login-form">
<h1>Login Form</h1>
<form action="login" method="POST">
<input type="text" name="email" placeholder="email" required>
<input type="submit">
</form>
</div>
</body>
</html>
jwt.helper.js
const jwt = require("jsonwebtoken");
let generateToken = (user, secretSignature, tokenLife) => {
return new Promise((resolve, reject) => {
const userData = {
email: user.email,
}
jwt.sign(
{data: userData},
secretSignature,
{
algorithm: "HS256",
expiresIn: tokenLife,
},
(error, token) => {
if (error) {
return reject(error);
}
resolve(token);
});
});
}
let verifyToken = (token, secretKey) => {
return new Promise((resolve, reject) => {
jwt.verify(token, secretKey, (error, decoded) => {
if (error) {
return reject(error);
}
resolve(decoded);
});
});
}
module.exports = {
generateToken: generateToken,
verifyToken: verifyToken,
};
middelware auth.js:
const jwtHelper = require('../helpers/jwt.helper');
const accessTokenSecret = process.env.ACCESS_TOKEN_SECRET || "xxx";
let isAuth = async(req, res, next) =>{
const tokenFromCLient = req.body.token || req.query.token || req.headers["access-token"];
if ( tokenFromCLient) {
//thuc hien giai ma xem co hop len khong
try{
const decode = await jwtHelper.verifyToken(tokenFromCLient, accessTokenSecret);
req.jwtDecoded = decode;
next();
}
catch (error) {
return res.status(401).json({ message: Unauthorized})
}
}
else {
return res.status(403).send({message: 'No token provided'})
}
}
module.exports = {
isAuth: isAuth
}
router.js
const express = require("express");
const router = express.Router();
const AuthMiddleWare = require("../middleware/auth");
const AuthController = require("../controllers/AuthController");
let initAPIs = (app) => {
router.post("/auth", AuthController.login);
router.use(AuthMiddleWare.isAuth);
return app.use("/", router);
}
module.exports = initAPIs;
server.js
const express = require("express");
const app = express();
const initAPIs = require("./routes/router");
var bodyParser = require('body-parser');
var path = require('path');
app.use(bodyParser.urlencoded({extended : true}));
app.use(bodyParser.json());
app.get('/', function(request, response) {
response.sendFile(path.join(__dirname + '/public/login.html'));
});
initAPIs(app);
app.listen(2310, () => {
console.log("server is working in localhost:2310")
})
My account linking setup
My Credentials Google Cloud :
This is what happened when I "talk to fun app"
After submit form :
Click link :
Click link:
Nothing happened in Google Console
I trying to understand what is the wrong with my credetrials inside my server code, because when I make Login from the client side, the credetrials does not recorgonizes inside the router.get('/auth/login') method, but when I do the same login action by the Postman with POST method and then reload the page with GET method the credetrials recorgonizes normally and I got the message, that I already loggined.
So, I actually want to say, that I do not have any problem with loginnig from the client side by "POST" method for router.post('/auth/login'), as for logs - user info transmits normally and credentials also creates, but on router.get('/auth/login') it does not callbacks in the res.json({session: req.session.userId, session2: req.session, log: 'You already logined!'});, where I gets just empty string...
My server code:
'use strict'
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
const bcrypt = require('bcrypt-nodejs');
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const app = express();
const router = express.Router();
const EmployersSchemaDB = require('./SchemaDB/EmployersSchemaDB');
const User = require('./SchemaDB/ShemaAuthtificaion');
mongoose.connect('mongodb://myDB');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
res.setHeader('Cache-Control', 'no-cache');
next();
});
app.use(session({
secret: 'work hard',
resave: true,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
router.get('/', (req, res) => {
res.json('Hello on Homepage!');
});
router
.get('/auth/login', (req, res) => {
User.find((err, users) => {
if (err) { res.send(err) }
if (req.session.userId !== undefined) { // there is where I always falls...
res.json({session: req.session.userId, session2: req.session, log: 'You already logined!'});
} else {
console.log('User credentials!:', req.session.userId);
res.json({session: req.session.userId, session2: req.session});
console.log('---===--- \n Employers showed!: \n', users + '\n ---===---');
}
});
})
.post('/auth/login', (req, res, next) => {
if (req.body.password !== req.body.passwordConf) {
var err = new Error('Passwords do not match.');
err.status = 400;
res.send("passwords dont match");
return next(err);
}
if (req.body.email &&
req.body.username &&
req.body.password &&
req.body.passwordConf) {
let user = new User();
user.email = req.body.email;
user.username = req.body.username;
user.password = req.body.password;
user.passwordConf = req.body.passwordConf;
user.save((err) => {
if (err) { res.send(err) }
res.json({ message: 'Comment successfully added!', user });
console.log('---===--- \n Employer added: \n', user + '\n ---===---');
});
} else if (req.body.logemail && req.body.logpassword) {
User.authenticate(req.body.logemail, req.body.logpassword, function (error, user) {
if (error || !user) {
var err = new Error('Wrong email or password.');
err.status = 401;
return next(err);
} else { // this is the where credentials are creates. All work good!
req.session.userId = user._id;
console.log('Signed Cookies: ', req.session.userId, req.signedCookies)
console.log('User logined and redirected!');
return res.redirect('/employers');
}
});
} else {
var err = new Error('All fields required.');
err.status = 400;
return next(err);
}
});
app.use('/', router);
const port = process.env.API_PORT || 3016;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
My client code (just for info) : UPDATED FOR KEVIN
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import axios from 'axios';
class LoginPage extends Component {
constructor(props) {
super(props);
this.state = {
navigate: false
}
}
handleSubmit = (e) => {
e.preventDefault();
let userLogin = {
logemail: e.target.email.value,
logpassword: e.target.password.value
}
axios.post('http://localhost:3016/auth/login', userLogin)
.then(function(){
axios.get('http://localhost:3016/auth/login', {withCredentials: true})
.then(res => console.log(res.data))
.catch(err => console.log(err));
this.setState({
navigate: true
})
})
.catch(err => {
console.error(err);
});
};
render() {
// if (this.state.navigate) {
// return <Redirect to="/employers" />
// }
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="exampleInputEmail1">Email address</label>
<input name="email" type="email" className="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email" />
<small id="emailHelp" className="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
<div className="form-group">
<label htmlFor="exampleInputPassword1">Password</label>
<input name="password" type="password" className="form-control" id="exampleInputPassword1" placeholder="Password" />
</div>
<div className="form-check">
<input type="checkbox" className="form-check-input" id="exampleCheck1" />
<label className="form-check-label" htmlFor="exampleCheck1">Check me out</label>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
)
}
}
export default LoginPage;
This may be a cross domain problem as you can login successfully with Postman.
AJAX calls will not send cookies in CORS environment by default. You need to set the withCredentials field of XMLHttpRequest object as true to send cookies even cross domain. Here is the official document.
As you are using axios, hope this setting would be helpful.
axios.defaults.withCredentials = true;
Update:
Please update your client code and make sure GET /auth/login are requested after POST /auth/login are completed, otherwise the Get request might be sent while POST request has not complete authenticate and set session. I recommend you change your code like following (put Get request after POST request are resolved):
axios.post('http://localhost:3016/auth/login', userLogin)
.then(function(){
axios.get('http://localhost:3016/auth/login').then(res => console.log(res.data).catch(e => console.log(e));
this.setState({
navigate: true
})
})
.catch(err => {
console.error(err);
});
```