I'm struggling getting this axios call to work. It's in a password reset feature, and it calls an axios request that sends through to the back end, but it's just coming up with an error instead of executing the code in the router route.
I call the request in this block here.
front end side:
async componentDidMount() {
const {
match: {
params: { token },
},
} = this.props;
try {
const response = await axios.get('http://localhost:5000/api/users/reset', {
params: {
resetPasswordToken: token,
},
});
console.log(response)
if (response.data.message === 'password reset link a-ok') {
this.setState({
username: response.data.username,
updated: false,
isLoading: false,
error: false,
});
}
} catch (error) {
console.log(error.response.data);
this.setState({
updated: false,
isLoading: false,
error: true,
});
}
}
It's getting the proper token and everything, but the http://localhost:5000/api/users/reset should be pointing to the /reset route in the code below, and it's never reached.
const express = require("express");
const router = express.Router();
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const keys = require("../../config/keys");
const validateRegisterInput = require("../../validation/register");
const validateLoginInput = require("../../validation/login");
const nodemailer = require('nodemailer');
const crypto = require('crypto');
require('dotenv').config();
const User = require("../../models/User");
router.route('/reset').get((req, res, next) => {
User.find({
where: {resetPasswordToken: req.query.resetPasswordToken,
resetPasswordExpires: {
$gt: Date.now(),
},
},
}).then(user => {
if(user == null) {
console.log('password reset link is invalid or has expired');
res.json('password reset link is invalid or has expired');
}else{
res.status(200).send({
username: user.username,
message: 'password reset link a-ok',
});
}
});
});
module.exports = router;
Actually #TamasSzoke you led me to answer my own question so I thank you! I had another route that was just /:id and that's what it was trying to validate there.
Just have to change that one up and it'll be all good.
thank you!!!
Related
Looking for a backend dev that can simply help me implement MONGODB with nextJS and the current model I have now. I have bought https://www.devias.io admin dashboard, and just want to implement auth and database reading with it.
Just want the basic auth setup. It's already setup in the FILES just wanting to know how to configure it properly based on the devias guides
Has anyone done this before I can't find any documentation on it
It's setup with mock data at the moment
SRC/API/AUTH/index.js
import { createResourceId } from '../../utils/create-resource-id';
import { decode, JWT_EXPIRES_IN, JWT_SECRET, sign } from '../../utils/jwt';
import { wait } from '../../utils/wait';
import { users } from './data';
class AuthApi {
async signIn(request) {
const { email, password } = request;
await wait(500);
return new Promise((resolve, reject) => {
try {
// Find the user
const user = users.find((user) => user.email === email);
if (!user || (user.password !== password)) {
reject(new Error('Please check your email and password'));
return;
}
// Create the access token
const accessToken = sign({ userId: user.id }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
resolve({ accessToken });
} catch (err) {
console.error('[Auth Api]: ', err);
reject(new Error('Internal server error'));
}
});
}
async signUp(request) {
const { email, name, password } = request;
await wait(1000);
return new Promise((resolve, reject) => {
try {
// Check if a user already exists
let user = users.find((user) => user.email === email);
if (user) {
reject(new Error('User already exists'));
return;
}
user = {
id: createResourceId(),
avatar: undefined,
email,
name,
password,
plan: 'Standard'
};
users.push(user);
const accessToken = sign({ userId: user.id }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
resolve({ accessToken });
} catch (err) {
console.error('[Auth Api]: ', err);
reject(new Error('Internal server error'));
}
});
}
me(request) {
const { accessToken } = request;
return new Promise((resolve, reject) => {
try {
// Decode access token
const { userId } = decode(accessToken);
// Find the user
const user = users.find((user) => user.id === userId);
if (!user) {
reject(new Error('Invalid authorization token'));
return;
}
resolve({
id: user.id,
avatar: user.avatar,
email: user.email,
name: user.name,
plan: user.plan
});
} catch (err) {
console.error('[Auth Api]: ', err);
reject(new Error('Internal server error'));
}
});
}
}
export const authApi = new AuthApi();
then /SRC/API/AUTH/data.js
export const users = [
{
id: '5e86809283e28b96d2d38537',
avatar: '/assets/avatars/avatar-anika-visser.png',
email: 'demo#devias.io',
name: 'Anika Visser',
password: 'Password123!',
plan: 'Premium'
}
];
This is the documentation on it
JSON Web Token (JWT)
Most auth providers use this strategy under the hood to provide access tokens. Currently, the app doesn't cover the backend service, and this service is mocked (faked) using http client interceptors. The implementation is basic, but enough to give you a starting point.
How it was implemented
Since tokens are meant to be created on the backend server, they are built with encrypt, encode and decode utility methods because they are not meant to be used on the client. These utilities can be found in src/utils/jwt. These are for development purposes only, and you must remove (or avoid using) them.
How to use JWT Provider
The app is delivered with JWT Provider as default auth strategy. If you changed or removed it, and you want it back, simply follow these steps:
Step 1: Import the provider
Open src/pages/_app.js file, import the provider and wrap the App component with it.
// src/pages/_app.js
import { AuthConsumer, AuthProvider } from '../contexts/auth/jwt-context';
const App = (props) => {
const { Component, pageProps } = props;
return (
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
);
};
Step 2: Set the hook context
Open src/hooks/use-auth.js file and replace the current context the following line:
import { AuthContext } from '../contexts/auth/jwt-context';
How to use auth
Retrieve user profile
In the example below, you can find how it can be used in any component not just the App. Should you want to use it in any other component, you'll have to import the useAuth hook and use it as needed.
// src/pages/index.js
import { useAuth } from '../hooks/use-auth';
const Page = () => {
const { user } = useAuth();
return (
<div>
Email: {user.email}
</div>
);
};
Auth methods / actions
For simplicity and space limitations, the code below is used only to exemplify, actual code can be found in the components.
// src/pages/index.js
import { useAuth } from '../hooks/use-auth';
const Page = () => {
const { login } = useAuth();
const handleLogin = () => {
// Email/username and password
login('demo#devias.io', 'Password123!');
};
s
return (
<div>
<button onClick={handleLogin}>
Login
</button>
</div>
);
};
Implemented flows
Currently, the app only covers the main flows:
Register
Login
Logout
const mongoose = require('mongoose');
const jwt = require("jsonwebtoken");
// Connect to MongoDB
mongoose.connect('mongodb://localhost/yourdbname', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const userSchema = new mongoose.Schema({
id: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true
},
name: {
type: String,
required: true
},
password: {
type: String,
required: true
},
plan: {
type: String,
default:
'Standard'
},
avatar: {
type: String,
default:
null
},
});
const User = mongoose.model('User', userSchema);
const JWT_SECRET = process.env.JWT_SECRET;
const JWT_EXPIRES_IN = '7d';
class AuthApi {
async signIn(request) {
const {
email,
password
} = request;
const user = await User.findOne({
email
});
if (!user || (user.password !== password)) {
throw new Error('Please check your email and password');
}
const accessToken = jwt.sign({
userId: user.id
}, JWT_SECRET, {
expiresIn: JWT_EXPIRES_IN
});
return {
accessToken
};
}
async signUp(request) {
const {
email,
name,
password
} = request;
const existingUser = await User.findOne({
email
});
if (existingUser) {
throw new Error('User already exists');
}
const newUser = new User({
id: mongoose.Types.ObjectId(),
email,
name,
password,
plan: 'Standard',
avatar: null,
});
await newUser.save();
const accessToken = jwt.sign({
userId: newUser.id
}, JWT_SECRET, {
expiresIn: JWT_EXPIRES_IN
});
return {
accessToken
};
}
async me(request) {
const {
accessToken
} = request;
const decoded = jwt.verify(accessToken, JWT_SECRET);
const {
userId
} = decoded;
const user = await User.findById(userId);
if (!user) {
throw new Error('Invalid authorization token');
}
return {
id: user.id,
avatar: user.avatar,
email: user.email,
name: user.name,
plan: user.plan
};
}
}
export const authApi = new AuthApi();
i am getting set-cookie in response header but my browser does not use it.
also, the cookie is not sent to the server there every time a new session is made on server side due to this.
I have checked my routes on postman everything working as expected i.e : cookies are receive and sent by postman but the browser completely ignores cookies.
zip file of project
index.js
const express = require('express');
const session = require('express-session')
const cookieParser = require('cookie-parser');
const mongoDBStore = require('connect-mongodb-session')(session)
const routes = require('./routes/routes')
require('./model/model');
require('./db/mongoose')
const app = express();
const store = new mongoDBStore({
uri: 'mongodb+srv://mny:QTCdKtdkjfdjfouJJWbUYN#cluster0.zxfwd.mongodb.net/MernDocker?retryWrites=true&w=majority',
collection: "mySessions"
})
// app.use(cookieParser())
app.use(express.json());
// app.use(express.urlencoded({ extended: false }));
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Credentials", 'true')//true as string
// res.header('Access-Control-Expose-Headers',
// 'Date, Etag, Access-Control-Allow-Origin, Set-Cookie, Access-Control-Allow-Credentials')
if (req.method === "OPTIONS") {
res.header("Access-Control-Allow-Methods", "GET,PATCH,POST,DELETE");
return res.status(200).send()
}
next();
});
app.use(session({
secret: "mny",
saveUninitialized: true,
cookie: {
path: "/",//if / the cookies will be sent for all paths
httpOnly: false,// if true, the cookie cannot be accessed from within the client-side javascript code.
secure: true,// true->cookie has to be sent over HTTPS
maxAge: 2*24 * 60 * 60 * 1000,
sameSite: 'none',//- `none` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
},
store: store,
resave: false,
}))
app.use(routes);
const port = process.env.PORT || 3001;
app.listen((port), (error) => {
console.log(`lisning on port ${port}`)
})
const express = require('express');
const User = require('../model/model');
const routes = express.Router();
/*
routes.get('/', async (req, res, next) => {
console.log('req.headers.cookie get')
console.log(req.headers.cookie)
// console.log(req.headers.cookie.split(';')[1].split('=')[1])
res.send({
"post": req.session.postClick,
"patch": req.session.patchClick
})
})*/
routes.post('/', async (req, res) => {
console.log("req.headers.cookie post method")
console.log(req.headers)
// console.log(req.headers.cookie.split(';')[1])
const user = new User(req.body)
try {
await user.save()
if (!req.session.postClick) {
req.session.postClick = 0
console.log(req.session);
}
req.session.postClick++
res.send({ "user": user, "postClick": req.session.postClick });
} catch (e) {
res.send(e)
}
})
module.exports = routes;
app.js frontend
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';
const url = 'http://localhost:3001'
console.log(document.cookie)
function App() {
const [inputValue, setInputValue] = useState({
name: '',
})
const handleChange = (e) => {
const { name, value } = e.target;
setInputValue({
...inputValue,
[name]: value
})
}
const handleOnAdd = (e) => {
e.preventDefault()
console.log(document.cookie)
const addData = async () => {
try {
const res = await fetch(`${url}`, {
method: 'POST',
headers: {
"mode": 'cors',
"Credentials": 'include',
'Content-Type': 'application/json',
'Accept': 'application/json',
'WithCredentials': true,
},
body: JSON.stringify(inputValue)
})
if (res.ok) {
let d = await res.json()
console.log(d)
} else {
alert('fetch add failed')
}
} catch (e) {
console.log(e)
}
}
addData()
// setInputValue({})
}
return (
<div>
<h1>session with mongodb</h1>
<form className='form' >
<label>name</label>
<input
name='name'
onChange={(e) => handleChange(e)}
value={inputValue.name}
/>
<button onClick={handleOnAdd}>Add</button>
</form>
</div>
)
}
export default App;
I am following a tutorial from Coding Garden. There he writes to a database and sends it then back to the client.
When I try to do it, I do not get a respond from the server. I guess there has been a mix up in my code.
When I go to localhost/5000/posts there is no database. Why do I not get an errormessage, or a database?
Best regards
Expected Result:
https://youtu.be/JnEH9tYLxLk?t=3060
client code
const form = document.querySelector('form');
const loadingElement = document.querySelector(".loading");
const API_URL = "http://localhost:5000/posts";
loadingElement.style.display = "none";
form.addEventListener('submit', (event) => {
event.preventDefault();
const formData = new FormData(form);
const name = formData.get('name');
const content = formData.get('content');
const post = {
name,
content
};
form.style.display = "none";
loadingElement.style.display= "";
fetch(API_URL, {
method: "POST",
body: JSON.stringify(post),
headers: {
"content-type": "application/json"
}
}).then(response => response.json())
.then(createdPost => {
console.log(createdPost);
});
});
server code
const express = require("express");
const cors = require('cors');
const monk = require("monk");
const app = express();
const db = monk("localhost/posts");
const posts = db.get("posts");
app.use(cors());
app.use(express.json());
app.get("/", (req, res) => {
res.json({
message: "Post"
});
});
function isValidPost(post){
return post.name && post.name.toString().trim() !== "" &&
post.content && post.content.toString().trim() !=="";
}
app.post("/posts", (req, res) => {
if (isValidPost(req.body)){
const post = {
name: req.body.name.toString(),
content: req.body.content.toString(),
created: new Date()
};
//console.log(post);
posts
.insert(post)
.then(createdPost => {
res.json(createdPost);
});
}else {
res.status(422);
res.json({
message: "Hey, Titel und Inhalt werden benötigt!"
});
}
});
app.listen(5000, () => {
console.log('Listening on http://localhost:5000');
});
You forgot to handle the case when post.insert(...) fails and rejects. In this case no response is sent from your server and the request will hang. Add the following:
posts
.insert(post)
.then(createdPost => {
res.json(createdPost);
})
.catch(err => {
console.log(err);
res.status(500).json({errorMessage: err.message});
});
handle the fetch method with catch. It probably goes to catch.
fetch().then().catch(err => ...)
I am implementing a login authentication program in MERN stack.
When I enter correct user name and password, login function works fine.
There are some components which can be displayed only if the client is logged in. Therefore, to validate the client I have implemented authenticator function in the server which should return success message along with the session object.
Once I try to authenticate, req.session.user gives the output as 'undefined'. I referred several similar questions but couldn't solve my issue.How can I solve this issue?
Login function,
router.post('/login', (req, res) => {
const email = req.body.email;
const password = req.body.password;
if (!email || !password) {
return res.status(400).json({ msg: "Please enter all fields" });
}
//Find user
User.findOne({ email : email })
.then(user => {
if(!user){
console.log('Not a user')
}
//Password matching
bcrypt.compare(password, user.password, (err, isMatch) => {
if(err) throw err;
if(isMatch){
console.log('Logged in')
const userSession = {
id: user.id,
name : user.name,
email : user.email
};
req.session.user = userSession;
res.json({ msg: "Logged in successfully", userSession});
} else {
console.log('Incorrect username or password')
}
});
})
.catch(err => console.log(err));
});
server.js,
const express = require('express');
const expressLayouts = require('express-ejs-layouts');
const mongoose = require('mongoose');
const passport = require('passport');
const flash = require('connect-flash');
const session = require('express-session');
const cors = require('cors');
const MongoDBStore = require('connect-mongodb-session')(session);
const app = express();
const router = express.Router();
const {IS_PROD} = require('./config/config');
const MAX_AGE = 1000 * 60 * 2;
mongoose.connect("mongodb+srv://root:admin#cluster0-ynman.gcp.mongodb.net/test?retryWrites=true&w=majority", {useNewUrlParser:true, useCreateIndex:true, useUnifiedTopology:true})
.then(() => console.log('Mongo DB Connected'))
.catch(err => console.log(err));
//setting up connect-mongodb-session store
const mongoDBStore = new MongoDBStore({
uri: "mongodb+srv://root:admin#cluster0-ynman.gcp.mongodb.net/test?retryWrites=true&w=majority",
collection : "mySession"
})
//Bodyparser
app.use(express.urlencoded({extended:false}));
app.use(cors());
app.use(express.json());
//Express Session
app.use(session({
name: 'session',
secret: 'secret',
resave: true,
saveUninitialized: false,
store : mongoDBStore,
cookie :{
path : '/',
httpOnly: false,
maxAge : MAX_AGE,
sameSite: false,
secure : IS_PROD
}
}));
//Routes
app.use('/', require('./routes/index'));
app.use('/users', require('./routes/users'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log(`Server starts on port ${PORT}`));
Authenticate funtion,
router.get("/authenticator", (req, res) => {
const userSession = req.session.user;
console.log(userSession);
if(userSession){
return res.json({msg : "Authenticated successfully", userSession});
} else {
return res.status(401).json({msg : "Unauthorized"});
}
});
I'm have an express server with MongoDB and Mongoose, and using passport to authenticate with JWT, but getting an error as in the title.
I'm following the passport-jwt documentation, but am still getting the error. What am I doing wrong?
Here is the error message when doing GET call on localhost3090 with a valid JWT:
::1 - - [16/Mar/2018:05:35:47 +0000] "GET / HTTP/1.1" 500 1677 "-" "PostmanRuntime/7.1.1"
Error: passport.initialize() middleware not in use
at IncomingMessage.req.login.req.logIn (/Users/okadachikara/react-courses/projects/server/node_modules/passport/lib/http/request.js:46:34)
at JwtStrategy.strategy.success (/Users/okadachikara/react-courses/projects/server/node_modules/passport/lib/middleware/authenticate.js:248:13)
at verified (/Users/okadachikara/react-courses/projects/server/node_modules/passport-jwt/lib/strategy.js:115:41)
at /Users/okadachikara/react-courses/projects/server/services/passport.js:34:7
at /Users/okadachikara/react-courses/projects/server/node_modules/mongoose/lib/model.js:3930:16
at _init (/Users/okadachikara/react-courses/projects/server/node_modules/mongoose/lib/query.js:2007:5)
at model.Document.init (/Users/okadachikara/react-courses/projects/server/node_modules/mongoose/lib/document.js:393:5)
at completeOne (/Users/okadachikara/react-courses/projects/server/node_modules/mongoose/lib/query.js:1993:12)
at Immediate.<anonymous> (/Users/okadachikara/react-courses/projects/server/node_modules/mongoose/lib/query.js:1520:11)
at Immediate._onImmediate (/Users/okadachikara/react-courses/projects/server/node_modules/mquery/lib/utils.js:119:16)
at runCallback (timers.js:773:18)
at tryOnImmediate (timers.js:734:5)
at processImmediate [as _immediateCallback] (timers.js:711:5)
My server/controllers/authentication.js:
const User = require('../models/user');
const jwt = require('jwt-simple');
const config = require('../config');
function tokenForUser(user) {
const timestamp = new Date().getTime();
return jwt.encode({ sub: user.id, iat: timestamp }, config.secret);
}
exports.signup = function (req, res, next) {
const email = req.body.email;
const password = req.body.password;
if (!email || !password) {
return res.status(422).send({ error: 'You must provide an email and
password' });
}
// see if user with the given email exists
User.findOne({ email: email }, function (err, existingUser) {
if (err) { return next(err); }
if (existingUser) {
return res.status(422).send({ error: 'A user with that email
already exists' });
}
const user = new User({
email: email,
password: password
});
user.save(function (err) {
if (err) { return next(err); }
res.json({ token: tokenForUser(user), iat: jwt.iat });
});
});
};
My server/services/passport.js
const passport = require('passport');
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const User = require('../models/user');
const config = require('../config');
const jwtOptions = {
jwtFromRequest: ExtractJwt.fromHeader('authorization'),
secretOrKey: config.secret
};
const jwtLogin = new JwtStrategy(jwtOptions, function (payload, done) {
User.findById(payload.sub, function (err, user) {
if (err) { return done(err, false); }
if (user) {
done(null, user);
} else {
done(null, false);
}
});
});
passport.use(jwtLogin);
My server/router.js
const passport = require('passport');
const Authentication = require('./controllers/authentication');
const passportService = require('./services/passport');
const requireAuth = passport.authenticate('jwt', { sesssion: false });
module.exports = function (app) {
app.get('/', requireAuth, function (req, res) {
res.send({ hi: 'there' });
});
app.post('/signup', Authentication.signup);
};
You need to initialize the passport module before using it:
let app = express();
app.use(passport.initialize());