I'm following a Udemy MERN stack course and I am quite a beginner ,I've got stuck in middle of a problem. There is no point in completing it before solving this problem. The problem is with the concept of authorization and concept of protected roles, so when the user is logged in to the interface we have to check whether is user is authorized or not. I followed the instructer end to end exactly according to the instruction and his code.
Using jsonwebtoken, verifiationn is conducted on the basis of encrypted token. whos key is stored in .env file
The output of the network dev tool in the browser :
enter image description here
I have no idea what causes this.
server.js
const express = require("express");
const app = express();
require("dotenv").config();
const dbConfig = require("./config/dbConfig.js");
app.use(express.json());
const userRoute = require("./routes/userRoute");
app.use("/api/user", userRoute);
const port = process.env.PORT || 5000;
console.log(process.env.MONGO_URL);
app.listen(port, () => console.log(`Node server started at port ${port}`));
.env
MONGO_URL = 'mongodb+srv://users:root#cluster0.vnoq4f8.mongodb.net/ngodatabase';
JWT_SECRET = 'ngo_project';
Home.js
import React, { useEffect } from "react";
import axios from "axios";
function Home() {
const getData = async () => {
try {
const response = await axios.post(
"/api/user/get-user-info-by-id",
{},
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
}, // headers
}
);
console.log(response.data);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getData();
}, []);
return <div>Home</div>;
}
export default Home;
authmiddleware.js
const jwt = require("jsonwebtoken");
module.exports = async (req, res, next) => {
try {
const token = req.headers["authorization"].split(" ")[1];
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err) {
return res.status(401).send({
message: "Auth failed",
success: false,
});
} else {
req.body.userId = decoded.id;
next();
}
});
} catch (error) {
return res.status(401).send({
message: "Auth failed",
success: false,
});
}
};
userRoute.js
const express = require("express");
const router = express.Router();
const User = require("../models/userModel");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const authmiddleware = require("../middlewares/authmiddleware");
router.post("/register", async (req, res) => {
try {
const userExist = await User.findOne({ email: req.body.email });
if (userExist) {
return res
.status(200)
.send({ message: "User already exists", success: false });
}
const password = req.body.password;
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
req.body.password = hashedPassword;
const newuser = new User(req.body);
await newuser.save();
res
.status(200)
.send({ message: "User created successfully", success: true });
} catch (error) {
console.log(error);
res
.status(500)
.send({ message: "Error creating user", success: false, error });
}
});
router.post("/login", async (req, res) => {
try {
const user = await User.findOne({ email: req.body.email });
if (!user) {
return res
.status(200)
.send({ message: "User does not exist", success: false });
}
const isMatch = await bcrypt.compare(req.body.password, user.password);
if (!isMatch) {
return res
.status(200)
.send({ message: "Password is incorrect", success: false });
} else {
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, {
expiresIn: "1d",
});
res
.status(200)
.send({ message: "login successful", success: true, data: token });
}
} catch (error) {
console.log(error);
res
.status(500)
.send({ message: "Error logging in", success: false, error });
}
});
router.post("/get-user-info-by-id", authmiddleware, async (req, res) => {
try {
const user = await User.findOne({ _id: req.body.userId });
if (!user) {
return res
.status(200)
.send({ message: "User does not exist", success: false });
} else {
res.status(200).send({
success: true,
data: {
name: user.name,
email: user.email,
},
});
}
} catch (error) {
res.status(500).send({
message: "Error getting user information",
success: false,
error,
});
}
});
module.exports = router;
package.json
jsonwebtoken in package
Login.js
import { Button, Form, Input } from "antd";
import React from "react";
import toast from "react-hot-toast";
import { Link, useNavigate } from "react-router-dom";
import axios from "axios";
function Login() {
const navigate = useNavigate();
const onFinish = async (values) => {
try {
const response = await axios.post("/api/user/login", values);
if (response.data.success) {
toast.success(response.data.message);
toast("Redirecting to home page");
localStorage.setItem("token", response.data.data);
navigate("/");
} else {
toast.error(response.data.message);
}
} catch (error) {
toast.error("Something went wrong");
}
};
return (
<div className="authentication">
<div className="authentication-form card p-4">
<h1 className="card-title">Welcome Back</h1>
<Form layout="vertical" onFinish={onFinish}>
<Form.Item label="Email" name="email">
<Input placeholder="Email"></Input>
</Form.Item>
<Form.Item label="Password" name="password">
<Input placeholder="Password" type="password"></Input>
</Form.Item>
<Button className="primary-button my-2" htmlType="submit">
LOGIN
</Button>
<Link to="/register" className="anchor mt-2">
CLICK HERE TO REGISTER
</Link>
</Form>
</div>
</div>
);
}
export default Login;
Register.js
import { Button, Form, Input } from "antd";
import React from "react";
import { Link, useNavigate } from "react-router-dom";
import axios from "axios";
import toast from "react-hot-toast";
function Register() {
const navigate = useNavigate();
const onFinish = async (values) => {
try {
const response = await axios.post("/api/user/register", values);
if (response.data.success) {
toast.success(response.data.message);
toast("Redirecting to login page");
navigate("/login");
} else {
toast.error(response.data.message);
}
} catch (error) {
toast.error("Something went wrong");
}
};
return (
<div className="authentication">
<div className="authentication-form card p-4">
<h1 className="card-title">Nice to meet you</h1>
<Form layout="vertical" onFinish={onFinish}>
<Form.Item label="Name" name="name">
<Input type="text" placeholder="Name" name="name"></Input>
</Form.Item>
<Form.Item label="Email" name="email">
<Input type="email" placeholder="Email" name="email"></Input>
</Form.Item>
<Form.Item label="Password" name="password">
<Input
placeholder="Password"
name="password"
type="password"
></Input>
</Form.Item>
<Button
className="primary-button my-2"
htmlType="submit"
name="submit"
>
REGISTER
</Button>
<Link to="/Login" className="anchor mt-2">
CLICK HERE TO LOGIN
</Link>
</Form>
</div>
</div>
);
}
export default Register;
did you check if you already have the token in your storage ?
check using inspectElement, or try to print the token in authmiddleware.js
like:
const jwt = require("jsonwebtoken");
module.exports = async (req, res, next) => {
try {
const token = req.headers["authorization"].split(" ")[1];
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err) {
console.log(token); //this line will print the token that given in your request
return res.status(401).send({
message: "Auth failed",
success: false,
});
} else {
req.body.userId = decoded.id;
next();
}
});
} catch (error) {
return res.status(401).send({
message: "Auth failed",
success: false,
});
}
};
Related
I am trying to connect my vue js application to a msal b2c backend the login is done but now i need to make a button for password reset and sign up i cant find a sign up popup anywhere and i dont know how to set up a password reset popup.
When i click the password reset link in the login popup the popup closes and nothing happens after that
The way i currently have it set up is:
LoginView.vue
<template>
<div class="grid grid-cols-12">
<div class="default-container">
<p>u bent nog niet ingelogd log nu in</p>
<button type="button" #click="login">Login</button>
</div>
</div>
</template>
<script setup>
import useAuthStore from '../stores/AuthStore';
function login() {
useAuthStore().login();
}
</script>
Authstore.js
import { defineStore } from 'pinia';
import AuthService from '../services/AuthService';
const clientId = import.meta.env.VITE_APP_CLIENT_ID;
const authority = import.meta.env.VITE_APP_AUTHORITY;
const scopes = [import.meta.env.VITE_APP_SCOPE_READ];
const authService = new AuthService(clientId, authority, scopes);
const useAuthStore = defineStore('AuthStore', {
state: () => ({
isAuthenticated: !!localStorage.getItem('apiToken'),
apiToken: localStorage.getItem('apiToken'),
user: JSON.parse(localStorage.getItem('userDetails')),
error: null,
}),
getters: {
isLoggedIn: (state) => state.isAuthenticated,
currentApiToken: (state) => state.apiToken,
currentUser: (state) => state.user,
currentError: (state) => state.error,
},
actions: {
async login() {
try {
const token = await authService.login();
this.apiToken = token.apiToken;
localStorage.setItem('apiToken', token.apiToken);
this.isAuthenticated = true;
fetch(`${import.meta.env.VITE_APP_API_URL}/account/current`, {
headers: {
Authorization: `Bearer ${token.apiToken}`,
},
})
.then((response) => response.json())
.then((data) => {
localStorage.setItem('userDetails', JSON.stringify(data));
this.user = data;
});
} catch (error) {
this.error = error;
}
},
async logout() {
try {
await authService.logout();
this.user = null;
this.apiToken = null;
this.isAuthenticated = false;
localStorage.removeItem('apiToken');
localStorage.removeItem('userDetails');
} catch (error) {
this.error = error;
}
},
},
});
export default useAuthStore;
AuthService.js
import * as Msal from 'msal';
export default class AuthService {
constructor(clientId, authority, scopes) {
this.app = new Msal.UserAgentApplication({
auth: {
clientId,
authority,
postLogoutRedirectUri: window.location.origin,
redirectUri: window.location.origin,
validateAuthority: false,
},
cache: {
cacheLocation: 'localStorage',
},
});
this.scopes = scopes;
}
async login() {
const loginRequest = {
scopes: this.scopes,
prompt: 'select_account',
};
const accessTokenRequest = {
scopes: this.scopes,
};
let token = {};
try {
await this.app.loginPopup(loginRequest);
} catch (error) {
return undefined;
}
try {
const acquireTokenSilent = await this.app.acquireTokenSilent(accessTokenRequest);
token = {
apiToken: acquireTokenSilent.accessToken,
expiresOn: acquireTokenSilent.expiresOn,
};
} catch (error) {
try {
const acquireTokenPopup = await this.app.acquireTokenPopup(accessTokenRequest);
token = {
apiToken: acquireTokenPopup.accessToken,
expiresOn: acquireTokenPopup.expiresOn,
};
} catch (errorPopup) {
return undefined;
}
}
return token;
}
logout() {
this.app.logout();
}
}
I'm having a hard time trying to fix my login page
I've provided a very short youtube video on what is the problem that I encountered.
Youtube Link: https://youtu.be/lpyJo6tmiRs
It works properly on localhost but breaks when I deploy to herkou & netlify.
Register function also works properly
I provided everything here and also hidden some important info like mongodb user and passwords.
Website Link
https://incomparable-speculoos-abdd5f.netlify.app/
Login Page
import React, { useState, useEffect } from 'react'
import { useNavigate } from "react-router-dom"
import Axios from 'axios'
import './login.css'
import Register from '../register/register'
const Login = () => {
const navigate = useNavigate();
const [style, setStyle] = useState('hidden')
const [border, setBorder] = useState(false)
const [email, setEmail] = useState('')
const [password, setPass] = useState('')
const [errMsg, setErr] = useState('')
Axios.defaults.withCredentials = true;
const handleEmail = (e) => {
setEmail(e.target.value)
}
const handlePassword = (e) => {
setPass(e.target.value)
}
const show = () => [
setStyle('registerParent')
]
const hide = () => {
setStyle('hidden')
}
const reloadA = () => {
window.location.reload(false);
}
// FUNCTION WHEN LOGIN IS CLICKED
const login = () => {
Axios.post('https://votereact-app.herokuapp.com/login',
{email: email,
password: password,
}).then((response) => {
// CHECKS IF THERE IS A MESSAGE FROM THE BACKEND (MEANS THERE IS A PROBLEM IN THE LOGIN)
if (response.data.message) {
setErr(response.data.message)
setBorder(true)
} else {
// NAVIGATES TO /home ROUTE OF THERE IS NO MESSAGE (/route redirects to privateRoute)
setErr("Logged in")
setBorder(false)
navigate('/home', {replace: true})
}
})
}
return (
<>
<div className="loginParent">
<div className="loginContainer">
<h1 className="vote-login">VoteReact</h1>
<div className="loginBox">
<div className="inputs-parent">
<input type="text" style={{border: border ? '1px solid #e2252b' : '1px solid #1B74E4'}} placeholder="Email" className="email-input" onChange={handleEmail}></input>
<input type="password" style={{border: border ? '1px solid #e2252b' : '1px solid #1B74E4'}}placeholder="Password" className="password-input" onChange={handlePassword}></input>
<p className="errMsg">{errMsg}</p>
</div>
<button className="loginButton" onClick={login}>Log in</button> {/* LOGIN BUTTON */}
<p className="forgot">Forgot Password?</p>
<button className="signup" onClick={show}>Sign up</button>
</div>
</div>
</div>
<Register styleName={style.toString()} close={() => hide()} load={() =>reloadA()}/>
</>
)
}
export default Login
BACK END CODE
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose")
const app = express();
const bcrypt = require("bcryptjs")
const saltRounds = 10;
const bodyParser = require("body-parser")
const cookieParser = require("cookie-parser")
const session = require("express-session")
const voterModel = require('./modules/voters.js')
const presidentModel = require('./modules/president.js')
const viceModel = require('./modules/vice.js')
const treasurerModel = require('./modules/treasurer.js')
app.use(express.json());
require('dotenv').config();
app.use(cors({credentials: true, origin: 'https://incomparable-speculoos-abdd5f.netlify.app'}));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }))
app.use(session({
key: "userId",
secret: "hidden",
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 60000
}
}))
mongoose.connect("hidden",
{
useNewUrlParser: true,
useUnifiedTopology: true
}
)
// GET THE SESSION AND CHECK IF IT DOES EXIST OR NO
//IF YES THEN LOGGEDIN: TRUE ELSE, FALSE
// --- HERE IS WHERE I ENCOUNTER PROBLEM, IT SHOULD RETURN TRUE AFTER I LOG IN BUT STILL RETURNS FALSE ---
app.get('/login', async (req, res) => {
if (req.session.voter) {
res.send({loggedIn: true})
} else {
res.send({loggedIn: false})
}
})
app.post('/login', async (req, res) => {
const email = req.body.email;
const password = req.body.password;
// CHECKS IF USER EMAIL EXISTS
voterModel.find({email: email}, {"email":1}, async (err, result) => {
if (err) {
console.log(err)
} else {
if(result.length > 0) {
// COMPARES PASSWORD IF IT IS CORRECT
const user = await voterModel.findOne({email: email})
const pass = await user.comparePassword(password)
if (pass) {
// SAVE THE SESSION IF PASS IS CORRECT
req.session.voter = result
var oneWeek = 60 * 60 * 24; //1 week
req.session.voter.expires = new Date(Date.now() + oneWeek);
req.session.voter.maxAge = oneWeek;
console.log(req.session.voter)
res.send(result)
} else {
console.log("NOT LOGGED IN")
res.send({ message: 'Invalid email or password!'})
}
} else {
console.log("NOT LOGGED IN")
res.send({ message: 'Invalid email or password!'})
}
}
})
})
app.post('/register', async (req, res) => {
const username = req.body.username;
const email = req.body.email;
const password = req.body.password;
// HASING PASSWORD
bcrypt.hash(password, saltRounds, async (err, hash) => {
if (err) {
console.log(err)
}
// INSERTING VALUES
const voters = await voterModel({email: email, username: username, password: hash, status: false})
// CHECKS IF EMAIL IS IN USE
const isNewEmail = await voterModel.isThisEmailInUse(email)
if (!isNewEmail) return res.send({ message: 'This email is already taken!'})
// SAVES THE INSERT DATA FOR VOTERS
await voters.save()
res.send({success: true})
})
})
app.post('/logout', (req, res) => {
if(req.session.voter) {
req.session.voter = null;
req.session.destroy();
}
})
const PORT = process.env.PORT || 3001
app.listen(PORT, () => {
console.log('Running on port successfuly')
})
Private Route to Home
import React, { useState, useEffect } from 'react'
import { useNavigate } from "react-router-dom"
import Axios from 'axios'
import Home from "./home/home.js"
const PrivateRoute = () => {
Axios.defaults.withCredentials = true;
const navigate = useNavigate();
const [loggedIn, setLoggedIn] = useState(false);
useEffect(()=> {
// GET DATA FROM axios.get(/login) on backend
Axios.get("https://votereact-app.herokuapp.com/login").then((response) => {
if (response.data.loggedIn === true) {
setLoggedIn(true);
console.log(response)
} else {
navigate("/" , {replace: true})
console.log(response)
}
})
},[])
// WHILE CHECKING IF Logged in or not
if (!loggedIn) {
return (
<>
Loading...
</>
)
}
// Redirects to real home page if user is logged in
return (
<>
<Home/>
</>
)
}
export default PrivateRoute
Loginhandler is the function which evokes after clicking log in button. Below are the pieces of two files. LoginScreen is my login.js file where as Action is my action file. I have made reducer file too, but my focus is to get the username and the password from input field, send it to action file using loginhandler function and on success, opens up my Home Screen and on Error, the Alert pops up.
----------------Login Screen------------
useEffect(() => {
if (error) {
Alert.alert("An Error Occurred!", error, [{ text: "Okay" }]);
}
}, [error]);
const loginHandler = async () => {
let action = authActions.login(
formState.inputValues.username,
formState.inputValues.password
);
setError(null);
setIsLoading(true);
try {
await dispatch(action);
props.navigation.navigate("PostAuth");
} catch (err) {
setError(err);
setIsLoading(false);
}
};
-----------------ACTION FILE-------------------
const axios = require("axios");
export const LOGIN = "LOGIN";
export const login = (username, password) => {
const params = new URLSearchParams();
params.append("username", username);
params.append("password", password);
return async (dispatch) => {enter code here
axios
.post("xyz.com/testApp/api/login.php", params)
.then((response) => {
const res = response.data.response;
const resMsg = res.message;
let preDefinedErrMsg;
if (resMsg !== "success") {
preDefinedErrMsg = "Wrong Credentials";
throw new Error(preDefinedErrMsg);
}
dispatch({
type: LOGIN,
token: "resData.idToken",
userId: "resData.id",
errorMessage: "message",
});
console.log(response);
})
.catch((err) => {
//console.log(err);
});
};
};
Yes I got it solved, by handling error in my action file.
const axios = require("axios");
export const LOGIN = "LOGIN";
export const login = (username, password) => {
const params = new URLSearchParams();
params.append("username", username);
params.append("password", password);
return async (dispatch) => {
await axios
.post("xyz.com/api/login.php", params)
.then((response) => {
const res = response.data.response;
const resMsg = res.message;
let preDefinedMsg;
if (resMsg === "Error") {
preDefinedErrMsg = "Wrong Credentials";
throw new Error(preDefinedErrMsg);
} else if (resMsg === "success") {
preDefinedMsg = "success";
dispatch({
type: LOGIN,
token: "resData.idToken",
userId: "resData.id",
errorMessage: "message",
});
}
})
.catch((error) => {
if (error.message === preDefinedErrMsg) {
throw new Error(preDefinedErrMsg);
}
});
};
};
I cannot correctly set my jwt token from my cookie to my Headers for an authenticaed gql request using apollo client.
I believe the problem is on my withApollo.js file, the one that wraps the App component on _app.js. The format of this file is based off of the wes bos advanced react nextjs graphql course. What happens is that nextauth saves the JWT as a cookie, and I can then grab the JWT from that cookie using a custom regex function. Then I try to set this token value to the authorization bearer header. The problem is that on the first load of a page with a gql query needing a jwt token, I get the error "Cannot read property 'cookie' of undefined". But, if I hit browser refresh, then suddenly it works and the token was successfully set to the header.
Some research led me to adding a setcontext link and so that's where I try to perform this operation. I tried to async await setting the token value but that doesn't seem to have helped. It just seems like the headers don't want to get set until on the refresh.
lib/withData.js
import { ApolloClient, ApolloLink, InMemoryCache } from '#apollo/client';
import { onError } from '#apollo/link-error';
import { getDataFromTree } from '#apollo/react-ssr';
import { createUploadLink } from 'apollo-upload-client';
import withApollo from 'next-with-apollo';
import { setContext } from 'apollo-link-context';
import { endpoint, prodEndpoint } from '../config';
import paginationField from './paginationField';
const getCookieValue = (name, cookie) =>
cookie.match(`(^|;)\\s*${name}\\s*=\\s*([^;]+)`)?.pop() || '';
let token;
function createClient(props) {
const { initialState, headers, ctx } = props;
console.log({ headers });
// console.log({ ctx });
return new ApolloClient({
link: ApolloLink.from([
onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
graphQLErrors.forEach(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
)
);
if (networkError)
console.log(
`[Network error]: ${networkError}. Backend is unreachable. Is it running?`
);
}),
setContext(async (request, previousContext) => {
token = await getCookieValue('token', headers.cookie);
return {
headers: {
authorization: token ? `Bearer ${token}` : '',
},
};
}),
createUploadLink({
uri: process.env.NODE_ENV === 'development' ? endpoint : prodEndpoint,
fetchOptions: {
credentials: 'include',
},
headers,
}),
]),
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
// TODO: We will add this together!
// allProducts: paginationField(),
},
},
},
}).restore(initialState || {}),
});
}
export default withApollo(createClient, { getDataFromTree });
page/_app.js
import { ApolloProvider } from '#apollo/client';
import NProgress from 'nprogress';
import Router from 'next/router';
import { Provider, getSession } from 'next-auth/client';
import { CookiesProvider } from 'react-cookie';
import nookies, { parseCookies } from 'nookies';
import Page from '../components/Page';
import '../components/styles/nprogress.css';
import withData from '../lib/withData';
Router.events.on('routeChangeStart', () => NProgress.start());
Router.events.on('routeChangeComplete', () => NProgress.done());
Router.events.on('routeChangeError', () => NProgress.done());
function MyApp({ Component, pageProps, apollo, user }) {
return (
<Provider session={pageProps.session}>
<ApolloProvider client={apollo}>
<Page>
<Component {...pageProps} {...user} />
</Page>
</ApolloProvider>
</Provider>
);
}
MyApp.getInitialProps = async function ({ Component, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
pageProps.query = ctx.query;
const user = {};
const { req } = ctx;
const session = await getSession({ req });
if (session) {
user.email = session.user.email;
user.id = session.user.id;
user.isUser = !!session;
// Set
nookies.set(ctx, 'token', session.accessToken, {
maxAge: 30 * 24 * 60 * 60,
path: '/',
});
}
return {
pageProps,
user: user || null,
};
};
export default withData(MyApp);
api/auth/[...nextAuth.js]
import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';
import axios from 'axios';
const providers = [
Providers.Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
Providers.Credentials({
name: 'Credentials',
credentials: {
username: { label: 'Username', type: 'text', placeholder: 'jsmith' },
password: { label: 'Password', type: 'password' },
},
authorize: async (credentials) => {
const user = await axios
.post('http://localhost:1337/auth/local', {
identifier: credentials.username,
password: credentials.password,
})
.then((res) => {
res.data.user.token = res.data.jwt;
return res.data.user;
}) // define user as res.data.user (will be referenced in callbacks)
.catch((error) => {
console.log('An error occurred:', error);
});
if (user) {
return user;
}
return null;
},
}),
];
const callbacks = {
// Getting the JWT token from API response
async jwt(token, user, account, profile, isNewUser) {
// WRITE TO TOKEN (from above sources)
if (user) {
const provider = account.provider || user.provider || null;
let response;
let data;
switch (provider) {
case 'google':
response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/auth/google/callback?access_token=${account?.accessToken}`
);
data = await response.json();
if (data) {
token.accessToken = data.jwt;
token.id = data.user._id;
} else {
console.log('ERROR No data');
}
break;
case 'local':
response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/auth/local/callback?access_token=${account?.accessToken}`
);
data = await response.json();
token.accessToken = user.token;
token.id = user.id;
break;
default:
console.log(`ERROR: Provider value is ${provider}`);
break;
}
}
return token;
},
async session(session, token) {
// WRITE TO SESSION (from token)
// console.log(token);
session.accessToken = token.accessToken;
session.user.id = token.id;
return session;
},
redirect: async (url, baseUrl) => baseUrl,
};
const sessionPreferences = {
session: {
jwt: true,
},
};
const options = {
providers,
callbacks,
sessionPreferences,
};
export default (req, res) => NextAuth(req, res, options);
When I sign up a user, the header gets set in the /signup route.
Header token set successfully
But when I try to access the header on / route. The authorization fails because in auth.js, getting the header with const token = req.header('curToken') returns undefined. In the network log I can see that the header that has been set (curToken) is empty or non-existent, but is allowed. Can not get Header token
// index.js
const express = require('express')
require('./db/mongoose')
const userRouter = require('./routers/user')
const app = express()
const port = process.env.PORT || 3000
const cors = require('cors')
app.options('*', cors())
app.use(cors())
app.use(express.json())
app.use(userRouter)
app.listen(port, () => {
console.log(`Server is running on port ${port}`)
})
// user.js (express route)
const express = require('express')
const User = require('../models/user')
const auth = require('../middleware/auth')
const router = new express.Router()
// signup
router.post('/signup', async (req, res) => {
const user = new User(req.body)
try {
await user.save()
const token = await user.generateAuthToken()
res.set('curToken', token) // set header
console.log('registered')
res.send({ user, token })
} catch(err) {
res.status(400).send(err)
}
})
// test if token header is accesible
router.get('', auth, async (req, res) => {
try {
// const users = await User.find({})
res.send("logged in.")
} catch(err) {
res.send(err)
}
})
module.exports = router
// auth.js middleware
const jwt = require('jsonwebtoken')
const User = require('../models/user')
const auth = async (req, res, next) => {
res.header('Access-Control-Expose-Headers', 'curToken')
try {
const token = req.header('curToken') // get header
console.log('auth token:', token) // header returns undefined
const decoded = jwt.verify(token, 'thisismysecretcode')
const user = await User.findOne({ _id: decoded._id, 'tokens.token': token })
if (!user) {
throw new Error()
}
req.token = token
req.user = user
next()
} catch(err) {
res.status(401).send({error: 'Please authenticate.'})
}
}
module.exports = auth
// Sign Up
<template>
<div>
SignUp
<form #submit="sendRegData" #submit.prevent>
<input type="text" v-model="firstName" name="firstName" placeholder="First name"><br>
<input type="text" v-model="lastName" name="lastName" placeholder="Last name"><br>
<input type="text" v-model="email" name="email" placeholder="Email"><br>
<input type="text" v-model="password" name="password" placeholder="Password"><br>
<input type="submit" value="Send">
</form>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: "SignUp",
data() {
return {
firstName: null,
lastName: null,
email: null,
password: null
}
},
methods: {
async sendRegData() {
try {
await axios.post('http://localhost:3000/signup', {
firstName: this.firstName,
lastName: this.lastName,
email: this.email,
password: this.password
}).then((res) => {
let token = res.data.token
// console.log('token res received in front:', token)
// localStorage.setItem("currentToken", token)
// console.log('curToken:', localStorage.getItem("currentToken"))
})
} catch(err) {
console.log(err)
}
}
}
};
</script>
// login
<template>
<div class="home">
<!-- <h1>{{ User.firstName }}</h1> -->
</div>
</template>
<script>
import axios from 'axios';
export default {
name: "Page",
data() {
return {
Users: {},
dataFetched: false
}
},
async mounted() {
try {
this.Users = await axios.get('http://localhost:3000/')
console.log(this.Users)
// this.User = this.User.data[0] // transform first object from array
// this.dataFetched = true
} catch(err) {
console.error(err)
}
}
};
</script>