refactoring to use jwt with cookies
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"proxy": "http://localhost:8080",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|||||||
@@ -1,10 +1,27 @@
|
|||||||
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||||
|
import API from './util/API';
|
||||||
import Home from './pages/Home';
|
import Home from './pages/Home';
|
||||||
import SingleItem from './pages/protected/SingleItem';
|
import SingleItem from './pages/protected/SingleItem';
|
||||||
import Items from './pages/protected/Items';
|
import Items from './pages/protected/Items';
|
||||||
import './App.css'
|
import './App.css'
|
||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import useAuthContext from './context/useAuthContext';
|
||||||
|
import jwtDecode from 'jwt-decode';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
const { setUser, token, setToken } = useAuthContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (document.cookie) {
|
||||||
|
console.log(document.cookie);
|
||||||
|
|
||||||
|
setToken(document.cookie.split("=")[1]);
|
||||||
|
setUser(jwtDecode(document.cookie.split("=")[1]).user);
|
||||||
|
|
||||||
|
console.log(token);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<div className="App">
|
<div className="App">
|
||||||
|
|||||||
4
client/src/context/AuthContext.jsx
Normal file
4
client/src/context/AuthContext.jsx
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { createContext } from "react";
|
||||||
|
|
||||||
|
const AuthContext = createContext();
|
||||||
|
export default AuthContext;
|
||||||
17
client/src/context/AuthProvider.jsx
Normal file
17
client/src/context/AuthProvider.jsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import AuthContext from "./authContext";
|
||||||
|
|
||||||
|
const AuthProvider = ({ children }) => {
|
||||||
|
const [user, setUser] = useState();
|
||||||
|
const [token, setToken] = useState();
|
||||||
|
|
||||||
|
const value = { user, setUser, token, setToken }
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AuthContext.Provider value={ value }>
|
||||||
|
{ children }
|
||||||
|
</AuthContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AuthProvider;
|
||||||
14
client/src/context/useAuthContext.jsx
Normal file
14
client/src/context/useAuthContext.jsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { useContext, useEffect } from "react"
|
||||||
|
import AuthContext from "./authContext"
|
||||||
|
|
||||||
|
const useAuthContext = () => {
|
||||||
|
const value = useContext(AuthContext);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(value);
|
||||||
|
}, [value])
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useAuthContext
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import AuthProvider from './context/AuthProvider'
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client'
|
||||||
import App from './App'
|
import App from './App'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||||
<React.StrictMode>
|
<AuthProvider>
|
||||||
<App />
|
<React.StrictMode>
|
||||||
</React.StrictMode>,
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
</AuthProvider>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,10 +1,23 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { LoginForm, RegisterForm } from "../components/Form";
|
import { LoginForm, RegisterForm } from "../components/Form";
|
||||||
|
import useAuthContext from "../context/useAuthContext";
|
||||||
|
import API from "../util/API";
|
||||||
|
|
||||||
function Auth({ handleLogin, handleRegister }) {
|
function Auth({ handleLogin, handleRegister }) {
|
||||||
const [info, setInfo] = useState({ email: "", password: "" });
|
const [info, setInfo] = useState({ email: "", password: "" });
|
||||||
const [register, setRegister] = useState({ username: "", email: "", password: "" })
|
const [register, setRegister] = useState({ username: "", email: "", password: "" })
|
||||||
|
|
||||||
|
const { setUser, setToken } = useAuthContext();
|
||||||
|
|
||||||
|
async function handleLogin() {
|
||||||
|
if (!info.email || !info.password) return;
|
||||||
|
|
||||||
|
const response = await API.login(info);
|
||||||
|
|
||||||
|
setUser(response.user);
|
||||||
|
setToken(response.token);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<LoginForm info={info} setInfo={setInfo} />
|
<LoginForm info={info} setInfo={setInfo} />
|
||||||
|
|||||||
@@ -1,26 +1,24 @@
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import jwt_decode from "jwt-decode";
|
import useAuthContext from "../context/useAuthContext"
|
||||||
import API from "../util/API";
|
import API from "../util/API";
|
||||||
import Auth from "./Auth";
|
import Auth from "./Auth";
|
||||||
import Welcome from "./protected/Welcome";
|
import Welcome from "./protected/Welcome";
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
const [contents, setContents] = useState(<></>);
|
const [contents, setContents] = useState(<></>);
|
||||||
const [update, setUpdate] = useState(false);
|
const [update, setUpdate] = useState(false);
|
||||||
|
const { user, setUser, token, setToken } = useAuthContext();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
async function handleLogin(info) {
|
async function handleLogin(info) {
|
||||||
if (!info.email || !info.password) return;
|
if (!info.email || !info.password) return;
|
||||||
|
|
||||||
const response = await API.login(info);
|
const response = await API.login(info);
|
||||||
const user = jwt_decode(response.token);
|
|
||||||
|
|
||||||
console.log(user);
|
|
||||||
localStorage.setItem('user', JSON.stringify(user));
|
|
||||||
localStorage.setItem('token', response.token);
|
|
||||||
|
|
||||||
|
setUser(response.user);
|
||||||
|
setToken(response.token);
|
||||||
|
|
||||||
setUpdate(!update);
|
setUpdate(!update);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,16 +44,8 @@ function Home() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let item = localStorage.getItem('user');
|
setContents(user ? <Welcome handleLogout={handleLogout} /> : <Auth handleLogin={handleLogin} handleRegister={handleRegister} />)
|
||||||
if (item) {
|
}, [token])
|
||||||
item = JSON.parse(item);
|
|
||||||
setUser(item.user);
|
|
||||||
}
|
|
||||||
}, [update])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setContents(user ? <Welcome user={user} handleLogout={handleLogout} /> : <Auth handleLogin={handleLogin} handleRegister={handleRegister} />)
|
|
||||||
}, [user, update])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import API from "../../util/API";
|
import API from "../../util/API";
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
|
import useAuthContext from "../../context/useAuthContext";
|
||||||
|
|
||||||
function Items() {
|
function Items() {
|
||||||
const [items, setItems] = useState(<p>Loading...</p>);
|
const [items, setItems] = useState(<p>Loading...</p>);
|
||||||
|
const { token, setToken } = useAuthContext();
|
||||||
const [content, setContent] = useState();
|
const [content, setContent] = useState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async() => {
|
console.log(token);
|
||||||
|
|
||||||
|
token && (async() => {
|
||||||
try {
|
try {
|
||||||
const data = await API.getItems();
|
const data = await API.getItems(token);
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
setItems(data.map(item => (
|
setItems(data.map(item => (
|
||||||
<div className="item" key={v4()}>
|
<div className="item" key={v4()}>
|
||||||
<a href={`/item/${item.id}`}>{item.name}</a>
|
<a href={`/item/${item.id}`}>{item.name}</a>
|
||||||
@@ -25,7 +31,7 @@ function Items() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}, [])
|
}, [token, setToken])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useParams } from "react-router-dom"
|
import { useParams } from "react-router-dom"
|
||||||
|
import useAuthContext from "../../context/useAuthContext";
|
||||||
import API from "../../util/API";
|
import API from "../../util/API";
|
||||||
|
|
||||||
function SingleItem() {
|
function SingleItem() {
|
||||||
const [content, setContent] = useState(<p>Loading...</p>);
|
const [content, setContent] = useState(<p>Loading...</p>);
|
||||||
|
const { token, setToken } = useAuthContext();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async() => {
|
(async() => {
|
||||||
try {
|
try {
|
||||||
const data = await API.getOneItem(id);
|
const data = await API.getOneItem(id, token);
|
||||||
console.log(data);
|
console.log(data);
|
||||||
setContent(
|
setContent(
|
||||||
<>
|
<>
|
||||||
@@ -26,7 +28,7 @@ function SingleItem() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}, []);
|
}, [token, setToken]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
import { useNavigate } from "react-router-dom"
|
import { useNavigate } from "react-router-dom"
|
||||||
|
import API from "../../util/API";
|
||||||
|
import useAuthContext from "../../context/useAuthContext";
|
||||||
|
|
||||||
function Welcome({ user, handleLogout }) {
|
function Welcome() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { user, setUser, setToken } = useAuthContext();
|
||||||
|
|
||||||
|
async function handleLogout() {
|
||||||
|
await API.logout();
|
||||||
|
setUser(null);
|
||||||
|
setToken(null);
|
||||||
|
navigate('/');
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<h2>Welcome, {user.username}!</h2>
|
<h2>Welcome, {user?.username}!</h2>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<h3>Check out some cool protected actions:</h3>
|
<h3>Check out some cool protected actions:</h3>
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import { default as _api } from './axiosInstance';
|
import { default as _api } from './axiosInstance';
|
||||||
|
|
||||||
export default class API {
|
export default class API {
|
||||||
static async validate() {
|
static async validate(token) {
|
||||||
try {
|
try {
|
||||||
const response = await _api.get('/');
|
const response = await _api.get('/', {
|
||||||
const data = Promise.resolve(response.data);
|
headers: {
|
||||||
console.log(data);
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": ("Bearer " + token)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = Promise.resolve(response);
|
||||||
return data;
|
return data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@@ -15,7 +19,8 @@ export default class API {
|
|||||||
static async login(data) {
|
static async login(data) {
|
||||||
try {
|
try {
|
||||||
const response = await _api.post('/auth/login', data);
|
const response = await _api.post('/auth/login', data);
|
||||||
return Promise.resolve(response.data);
|
console.log(response);
|
||||||
|
return Promise.resolve(response);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
@@ -25,7 +30,10 @@ export default class API {
|
|||||||
try {
|
try {
|
||||||
const response = await _api.delete('/auth/logout');
|
const response = await _api.delete('/auth/logout');
|
||||||
console.log(response);
|
console.log(response);
|
||||||
return Promise.resolve(response.data);
|
|
||||||
|
document.cookie = `token=;expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
||||||
|
console.log(document.cookie);
|
||||||
|
return null;
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
@@ -40,21 +48,18 @@ export default class API {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getItems() {
|
static async getItems(token) {
|
||||||
const token = localStorage.getItem("token");
|
|
||||||
|
|
||||||
const response = await _api.get('/app/item', {
|
const response = await _api.get('/app/item', {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Authorization": ("Bearer " + token)
|
"Authorization": `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.resolve(response.data);
|
return Promise.resolve(response.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getOneItem(id) {
|
static async getOneItem(id, token) {
|
||||||
const token = localStorage.getItem("token");
|
|
||||||
|
|
||||||
const response = await _api.get(`/app/item/${id}`, {
|
const response = await _api.get(`/app/item/${id}`, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
|||||||
@@ -1,7 +1,28 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import jwt_decode from 'jwt-decode'
|
||||||
|
|
||||||
const apiUrl = import.meta.env.VITE_APIURL;
|
const apiUrl = import.meta.env.VITE_APIURL;
|
||||||
|
|
||||||
export default axios.create({
|
const instance = axios.create({
|
||||||
baseURL: "http://localhost:8080"
|
baseURL: apiUrl
|
||||||
})
|
});
|
||||||
|
|
||||||
|
instance.interceptors.response.use((res) => {
|
||||||
|
if (res?.data.token) {
|
||||||
|
document.cookie = `token=${res.data.token}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
token: res.data.token,
|
||||||
|
user: jwt_decode(res.data.token).user,
|
||||||
|
data: res.data.data || null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
data: res?.data || null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, (err) => {
|
||||||
|
return Promise.reject(err);
|
||||||
|
})
|
||||||
|
|
||||||
|
export default instance;
|
||||||
@@ -30,6 +30,8 @@ async function authRoute(app, passport) {
|
|||||||
response = response.data;
|
response = response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(response);
|
||||||
|
|
||||||
req.user = response;
|
req.user = response;
|
||||||
req.session.user = response;
|
req.session.user = response;
|
||||||
|
|
||||||
@@ -43,12 +45,14 @@ async function authRoute(app, passport) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const token = jwt.sign({ user: safeUserData }, secret);
|
const token = jwt.sign({ user: safeUserData }, secret);
|
||||||
req.session.token = token;
|
|
||||||
|
|
||||||
req.session.save((err) => {
|
req.session.save((err) => {
|
||||||
return next(err);
|
return next(err);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log(req.session);
|
||||||
|
|
||||||
|
res.cookie('token', token, { httpOnly: true });
|
||||||
res.json({ token });
|
res.json({ token });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -60,7 +64,8 @@ async function authRoute(app, passport) {
|
|||||||
try {
|
try {
|
||||||
req.session = null;
|
req.session = null;
|
||||||
req.user = null;
|
req.user = null;
|
||||||
res.status(200).clearCookie('connect.sid');
|
res.clearCookie('connect.sid').clearCookie('token');
|
||||||
|
res.status(204).send("logout successful");
|
||||||
res.end();
|
res.end();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|||||||
25
server/routes/base.js
Normal file
25
server/routes/base.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
const router = require('express').Router();
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
const secret = process.env.SECRET;
|
||||||
|
|
||||||
|
async function baseRoute(app, passport) {
|
||||||
|
router.get('/', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
console.log(req.session);
|
||||||
|
const user = undefined;
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
res.status(403).send("Not authorized");
|
||||||
|
} else {
|
||||||
|
res.status(200).send({ token: req.token, user: req.user });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = baseRoute;
|
||||||
@@ -1,22 +1,32 @@
|
|||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const authRoute = require("./auth");
|
const authRoute = require("./auth");
|
||||||
const itemRoute = require("./item");
|
const itemRoute = require("./item");
|
||||||
|
const jwtRoute = require('./jwt');
|
||||||
|
const baseRoute = require('./base');
|
||||||
|
|
||||||
async function routesLoader(app, passport) {
|
async function routesLoader(app, passport) {
|
||||||
app.use('/app', (req, res, next) => {
|
app.use('/app', (req, res, next) => {
|
||||||
const token = req.headers['authorization'].split(" ")[1];
|
const token = req.headers['authorization']?.split(" ")[1];
|
||||||
jwt.verify(token, process.env.SECRET, (err, data) => {
|
|
||||||
if (err) {
|
if (!token) {
|
||||||
res.status(403).send(err);
|
res.status(403).send("Unauthorized");
|
||||||
} else {
|
} else {
|
||||||
req.user = data;
|
jwt.verify(token, process.env.SECRET, (err, data) => {
|
||||||
next();
|
if (err) {
|
||||||
}
|
res.status(403).send(err);
|
||||||
})
|
} else {
|
||||||
|
req.user = data;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.use('/', await baseRoute(app, passport));
|
||||||
|
|
||||||
app.use('/auth', await authRoute(app, passport));
|
app.use('/auth', await authRoute(app, passport));
|
||||||
app.use('/app', await itemRoute(app, passport));
|
app.use('/app', await itemRoute(app, passport));
|
||||||
|
app.use('/jwt', await jwtRoute(app, passport));
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = routesLoader;
|
module.exports = routesLoader;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
// const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
const ItemController = require('../controllers/ItemController');
|
const ItemController = require('../controllers/ItemController');
|
||||||
|
|
||||||
async function itemRoute(app, passport) {
|
async function itemRoute(app, passport) {
|
||||||
/* router.use('/', (req, res, next) => {
|
router.use('/', (req, res, next) => {
|
||||||
const token = req.headers['authorization'].split(" ")[1];
|
const token = req.headers['authorization'].split(" ")[1];
|
||||||
jwt.verify(token, process.env.SECRET, (err, data) => {
|
jwt.verify(token, process.env.SECRET, (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -14,7 +14,7 @@ async function itemRoute(app, passport) {
|
|||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}) */
|
})
|
||||||
|
|
||||||
router.get('/item', async (req, res) => {
|
router.get('/item', async (req, res) => {
|
||||||
const response = await ItemController.getAll();
|
const response = await ItemController.getAll();
|
||||||
|
|||||||
22
server/routes/jwt.js
Normal file
22
server/routes/jwt.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
const router = require('express').Router();
|
||||||
|
const jwt = require('jsonwebtoken');
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
const secret = process.env.SECRET;
|
||||||
|
|
||||||
|
async function jwtRoute(app, passport) {
|
||||||
|
router.get('/', (req, res) => {
|
||||||
|
const user = req.user;
|
||||||
|
if (!user) {
|
||||||
|
res.status(403).send("Unauthorized");
|
||||||
|
} else {
|
||||||
|
const token = jwt.sign({ user: req.user }, secret);
|
||||||
|
res.cookie('token', token, { httpOnly: true });
|
||||||
|
res.json({ token });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = jwtRoute;
|
||||||
Reference in New Issue
Block a user