Axios not receive response and error of the server Node - javascript

i'm trying do a request POST using axios.js but the axios not is working, it not give the response or error, the console.log stay empty when i do the request, i dont know why. someone know?
My request axios.js:
handleLogin = () => {
this.setState({
loading: true
})
axios.post("/login", {
body: JSON.stringify({
...this.state
})
})
.then(response =>
localStorage.setItem('user-token', response.token),
this.setState({
loading: false
})
)
.catch(error =>
console.log(error),
this.setState({
loading: false
})
)
};
My middleware(isManager):
const {
findByMail
} = require('../data/acl/acl.model');
module.exports =
async function isAuthenticated(req, res, next) {
const acl = await findByMail(req.body.username);
if (acl && acl.role === "MANAGER") {
next()
} else {
return res.status(401).send({
message: "ERROR: YOU DONT HAVE ACCESS"
})
}
}
My route that axios use:
const isbmer = passport.authenticate('ldapauth', {
session: false
});
router.post('/', [isManager, isbmer], (req, res) => {
let id = req.user.ibmSerialNumber;
const email = req.user.preferredIdentity;
const name = req.user.cn;
const json = {
id,
email,
name
};
const expiresIn = process.env.NODE_ENV === 'local' ? '365d' : '10h';
const token = jwt.sign(json, process.env.JWT_SECRET, {
expiresIn
});
res.status(200).send({
auth: true,
token
});
});
Someone help me?When i do the request, nothing work..

Related

JWT Authentication error on Updating an item in MERN stack

Can't update/edit. It's a basic MERN CRUD app with JWT, RTK, and MUI. When I try, I get
PUT http://localhost:3000/api/purchases/[object%20Object] 401 (Unauthorized) xhr.js:210
in Chrome Dev Tools. Also I'm getting 2 error messages saying Not Authorized tableForm.jsx:29 and Not Authorized Table.jsx:17
Those messages are originating from a console.log in my auth middleware, but only happen when updating. Get, Create, and Delete all work fine.
const protect = asyncHandler(async (req, res, next) => {
let token
if(req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
try{
//Get token from header
token = req.headers.authorization.split(' ')[1]
//Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET)
//Get user from the token
req.user = await User.findById(decoded.id).select('-password')
next()
} catch (error) {
console.log(error)
res.status(401)
throw new Error('Not authorizecd')
}
}
if (!token) {
res.status(401)
throw new Error('Not authorized, no token')
}
} )
In Table and tableForm, I also have
useEffect(() => {
if (isError) {
console.log(message)
}
Maybe my Slice or Controller is wrong, but I've checked similar questions and projects on here and GitHub, so idk. Here, they are:
//Update Purchase
export const updatePurchase = createAsyncThunk(
'purchases/update',
async (purchaseData, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token
return await purchaseService.updatePurchase(purchaseData, token)
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message)
}
})
//extra reducers part
.addCase(updatePurchase.pending, (state) => {
state.isLoading = true
})
.addCase(updatePurchase.fulfilled, (state, action) => {
state.isLoading = false
state.isSuccess = true
state.purchases = state.purchases.map((purchase) => purchase._id === action.payload._id ? action.payload : purchase)
})
.addCase(updatePurchase.rejected, (state, action) => {
state.isLoading = false
state.isError = true
state.message = action.payload
})
//"Service" part
const updatePurchase = async (purchaseId, purchaseData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`
}
}
const response = await axios.put(API_URL + purchaseId, purchaseData, config)
return response.data
}
//and the Controller
const updatePurchase = asyncHandler(async (req, res) => {
const purchase = await Purchase.findById(req.params.id)
if (!purchase){
res.status(400)
throw new Error('Purchase not found')
}
//const user = await User.findById(req.user.id)
//Check for user
if(!req.user) {
res.status(401)
throw new Error('User not found')
}
//Make sure the user matches the purchases
if (purchase.user.toString() !==req.user.id) {
res.status(401)
throw new Error('User not authorized')
}
const updatedPurchase = await Purchase.findByIdAndUpdate(req.params.id, req.body, {
new: true,
})
res.status(200).json(updatedPurchase)
})
Any and all help would be appreciated. I've tried everything and have been working on this for days, but I'm kind of new so I'm sure I'm missing something obvious.
Here is the git repo if needed.
https://github.com/LazAustin/final_license_manager.git
Here is the front end where updatePurchase is used. I'm not sure what to pass anymore. The ID and/or the whole Purchase? Either way I've tried everything.
function EditForm({purchase}) {
const [title, setTitle] = useState(purchase.title);
const [producer, setProducer] = useState(purchase.producer);
... //shortened for reading purposes
const [notes, setNotes] = useState(purchase.notes);
const dispatch = useDispatch()
const onSubmit = (e) => {
e.preventDefault()
const purchaseData = {
title,
producer
... //just shortening for reading purposes
notes,
id: purchase._id
}
dispatch(updatePurchase(purchaseData)) // <-tried different combinations of id and purchase on front and back end.
//I think its supposed to be updatePurchase(purchase._id, purchaseData) and same on the slice but that didnt work either
}
Nvm! Figured it out, just in case anyone else rolls on this question. Forgot my id was set to "purchaseId" in the Service. Changed my service back to what I originally had it as (below). Then below that is my new front end with purchaseId: purchase._id
const updatePurchase = async (purchaseData, token) => {
const { purchaseId, ...body } = purchaseData;
const config = {
headers: {
Authorization: `Bearer ${token}`
}
}
const response = await axios.put(API_URL + purchaseId, body, config)
return response.data
}
const onSubmit = (e) => {
e.preventDefault();
const purchaseData = ({
title,
...,
notes,
purchaseId: purchase._id
})
dispatch(updatePurchase(purchaseData))
}

Why am I getting different response from my data when local and when on heroku?

I am working on an Application which i have also deployed in heroku. The issue is that when I login in using heroku, user is nested inside a data object. but when I work locally or use postman, user isnt nested.
Help Please.
I get this response on the deployed version.
data: {
user: {
email: "my_email"
name: "my_name"
role: "user"
_id: "6205807deeadcfa734f954f3".
}
status: "success"
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYyMDU4MDdkZWVhZGNmYTczNGY5NTRmMyIsImlhdCI6MTY0NDg0NTYyMCwiZXhwIjoxNjQ1NDUwNDIwfQ.YeWFNrN8rsLPJvvU8JQDwBVG4aBqqEuo7ssgLrR3O8M"
But when I log in locally, I get the response as
user: {
email: "my_email"
name: "my_name"
role: "user"
_id: "6205807deeadcfa734f954f3".
}
status: "success"
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYyMDU4MDdkZWVhZGNmYTczNGY5NTRmMyIsImlhdCI
For Heroku, the USER is nested inside data but for local host and postman, the user isnt nested.
My codes are:
exports.login = catchAsync(async (req, res, next) => {
const { email, password } = req.body
if (!email || !password) {
return next(new AppError('Please provide email and password!', 400))
}
const user = await User.findOne({ email }).select('+password')
if (!user || !(await user.comparePassword(password, user.password))) {
return next(new AppError('Incorrect email or password', 401))
}
createSendToken(user, 200, req, res)
})
These are my api codes
const createSendToken = (user, statusCode, req, res) => {
const token = signToken(user._id)
res.cookie('jwt', token, {
expires: new Date(
Date.now() + process.env.JWT_COOKIE_EXPIRES_IN * 24 * 60 * 60 * 1000
),
httpOnly: true,
})
user.password = undefined
res.status(statusCode).json({
status: 'success',
token,
user,
})
}
For my react, The function code is:
function request(path, { data = null, token = null, method = 'GET' }) {
return (
fetch(`${process.env.REACT_APP_API}${path}`, {
method,
headers: {
Authorization: token ? `Bearer ${token}` : '',
'Content-Type': 'application/json',
},
body:
method !== 'GET' && method !== 'DELETE' ? JSON.stringify(data) : null,
})
.then((response) => {
// If Successful
if (response.ok) {
if (method === 'DELETE') {
// If delete, nothing returned
return true
}
return response.json()
}
// If errors
return response
.json()
.then((json) => {
// Handle Json Error response from server
if (response.status === 400) {
const errors = Object.keys(json).map(
(k) => `${json[k].join(' ')}`
)
throw new Error(errors.join(' '))
}
throw new Error(JSON.stringify(json))
})
.catch((e) => {
if (e.name === 'SyntaxError') {
throw new Error(response.statusText)
}
throw new Error(e)
})
})
.catch((e) => {
// Handle all errors
toast(e.message, { type: 'error' })
})
)
}
The main sign in function
export function signIn(email, password) {
return request('/api/v1/auth/login', {
data: { email, password },
method: 'POST',
})
}
Then I import this into my auth context and execute it there
import {signIn as signInApi} from '../apis'
const AuthContext = createContext()
export const AuthProvider = ({ children }) => {
const [token, setToken] = useState(localStorage.getItem('token'))
const [user, setUser] = useState(
JSON.parse(localStorage.getItem('user'))
)
const [loading, setLoading] = useState(false)
const signIn = async (email, password, callback) => {
setLoading(true)
const res = await signInApi(email, password)
if (res.token) {
localStorage.setItem('token', res.token)
localStorage.setItem('user', JSON.stringify(res.user)) // This stores the user in localhost but returns undefined for user in the one deployed to heroku. I have to use
localStorage.setItem('user', JSON.stringify(res.data.user)) which now works on the deployed one but not on the local one
setToken(res.token)
setUser(res.user)
callback()
}
setLoading(false)
}
}
it seems the deployed version is using built in implementaion of createSendToken and not the one you provided. need to check your project structure.
in order to validate this change the function name and the call createSendToken to something else and you will find the issue

Request Aborted on axios.get reactJS

I'm trying to make get request via token from local storage but it is giving me Request aborted error.
Here is My nodeJS code :
//Read
app.get('/:username',verify, (req, res) => {
console.log('Welcome to roffys server')
Todo.find({'username' : req.params.username})
.exec((err, todo) => {
if (err) {
console.log('Error retrieving todos')
} else {
res.json(todo)
}
})
})
Here is the Verify function :
const jwt = require('jsonwebtoken')
module.exports = function (req,res,next){
const token = req.header('Authentication')
if(!token) return res.status(401).send('Access Denied')
try {
const verified = jwt.verify(token, 'secretkey')
req.user = verified
}catch (err) {
res.status(400).send(
'Invalid token'
)
next()
}
And here is my FE on ReactJS component:
componentDidMount() {
axios
.get(`http://localhost:8080/${localStorage.getItem('username')}`,{
headers : {
Authentication : localStorage.getItem('token')
}
})
.then((res) => {
this.setState({todos: res.data})
this.setPageCount()
})
.catch((err) => {
console.log("err", err);
});
}
None of yow methods return anything.
componentDidMout () {
return axios.get(url, config)
.then (res=> this.setState(myProp: res.data});
......
Back
var verify = require(“./path/to verify”);
//Read
app.get('/:username',verify, (req, res) => {
return Todo.find({'username' : req.params.username})
.exec()
.then(todo=> res.json(todo))
.catch(console.log);
})

How to store, manage REST API JWT authentication token in vue?

I am a noob, using vue.js and a node auth api, the api works fine and provides the jwt token in the response, my question is how can i use the token in all the requests that follows (using axios), and any best practices for handling the token in the front end is also appreciated.
Thanks
You can use something like that for Your scenario in your vuejs app.
import axios from 'axios'
const API_URL = 'http://localhost:3000'
const securedAxiosInstance = axios.create({
baseURL: API_URL,
withCredentials: true,
headers: {
'Content-Type': 'application/json'
}
})
const plainAxiosInstance = axios.create({
baseURL: API_URL,
withCredentials: true,
headers: {
'Content-Type': 'application/json'
}
})
securedAxiosInstance.interceptors.request.use(config => {
const method = config.method.toUpperCase()
if (method !== 'OPTIONS' && method !== 'GET') {
config.headers = {
...config.headers,
'X-CSRF-TOKEN': localStorage.csrf
}
}
return config
})
securedAxiosInstance.interceptors.response.use(null, error => {
if (
error.response &&
error.response.config &&
error.response.status === 401
) {
return plainAxiosInstance
.post('/refresh', {}, { headers: { 'X-CSRF-TOKEN': localStorage.csrf } })
.then(response => {
localStorage.csrf = response.data.csrf
localStorage.signedIn = true
let retryConfig = error.response.config
retryConfig.headers['X-CSRF-TOKEN'] = localStorage.csrf
return plainAxiosInstance.request(retryConfig)
})
.catch(error => {
delete localStorage.csrf
delete localStorage.signedIn
location.replace('/')
return Promise.reject(error)
})
} else {
return Promise.reject(error)
}
})
export { securedAxiosInstance, plainAxiosInstance }
And in your component you use this to process your request with api
Products.vue
export default {
name: 'products',
data () {
return {
products: [],
newProduct: [],
error: '',
editedProduct: ''
}
},
created () {
if (!localStorage.signedIn) {
this.$router.replace('/')
} else {
this.$http.secured.get('/api/v1/products')
.then(response => { this.products = response.data })
.catch(error => this.setError(error, 'Something went wrong'))
}
},
methods: {
setError (error, text) {
this.error = (error.response && error.response.data && error.response.data.error) || text
},
addProduct () {
const value = this.newProduct
if (!value) {
return
}
this.$http.secured.post('/api/v1/products/', { product: { name: this.newProduct.name } })
.then(response => {
this.products.push(response.data)
this.newProduct = ''
})
.catch(error => this.setError(error, 'Cannot create product'))
},
removeProduct (product) {
this.$http.secured.delete(`/api/v1/products/${product.id}`)
.then(response => {
this.products.splice(this.products.indexOf(product), 1)
})
.catch(error => this.setError(error, 'Cannot delete product'))
},
editProduct (product) {
this.editedproduct = product
},
updateProduct (product) {
this.editedProduct = ''
this.$http.secured.patch(`/api/v1/products/${product.id}`, { product: { title: product.name } })
.catch(error => this.setError(error, 'Cannot update product'))
}
}
}
You can find here a lot of good patterns which I personally use on my projects and how also JWT token handling.
For saving token in a brower, you can use cookie, sessionStorage or localStorate, last one is the most popular now (short explination here).
In a few words, you can create an axion instance and add a token before request sent.
const http = axios.create({
baseURL: process.env.VUE_APP_SERVER_API,
// here you can specify other params
})
http.interceptors.request.use(request => {
// Do something before request is sent
request.headers['Authorization'] = `JWT ${TOKEN_HERE}`
// some logic what to do if toke invalid, etc ...
return request
}, function (error) {
// Do something with request error
return Promise.reject(error)
})

Sequelize, Deleting multiple rows with React

I'm using React with a Postgres DB with Sequelize.
within my project, I have a promise that is "suppose" to delete all songs relating to the album, using the the Album.id in my state.
** Instead of deleting the rows of songs relating to the Album, after the delete request in the database, it removes the value of the AlbumId of the song. **
Is there an update I am missing
When I console.log outside of the service and in the promise this.state.Album.id remains the same.
It hit's the server with the appropriate number.
This is the function within the React Component
DeleteAlbum (e) {
e.preventDefault()
axios.delete(`${domain}/albums/${this.state.Album.id}`)
.then((res) => {
axios.delete(`${domain}/songs/ByAlbumId/${this.state.Album.id}`)
.then((res) => {
window.location.href = '/#/'
})
.catch((error) => {
console.log('axios error', error)
})
})
.catch((error) => {
console.log('axios error', error)
})
}
This is the Database to the Songs Route
const express = require('express')
const router = express.Router()
const bodyParser = require('body-parser')
const db = require('./../models')
const Song = db.Song
router.use(bodyParser.json({ extended: false }))
const exists = (req) => {
if (typeof parseInt(req.params.id) === 'number') {
Album.findOne({
where: {
id: req.params.id
}
})
.then((album) => {
if (album) {
return true
};
return false
})
.catch((err) => {
return false
})
} else {
return false
}
}
router.delete('/ByAlbumId/:id', function (req, res) {
Song.destroy({
where: {
AlbumId: req.params.id
}
})
.then(function (data) {
return res.json(data)
})
.catch(function (err) {
return res.json({ error: err})
})
})
router.delete('/:id', function (req, res) {
if (exists) {
Song.destroy({
where: {
id: req.params.id
}
})
.then(function (data) {
return res.json(data)
})
.catch(function (err) {
return res.json({ error: err})
})
} else {
res.json({success: false})
}
})
This is the Album Route
const express = require('express')
const router = express.Router()
const bodyParser = require('body-parser')
const db = require('./../models')
const Album = db.Album
router.use(bodyParser.json({ extended: false }))
const exists = (req) => {
if (typeof parseInt(req.params.id) === 'number') {
Album.findOne({
where: {
id: req.params.id
}
})
.then((album) => {
if (album) {
return true
};
return false
})
.catch((err) => {
return false
})
} else {
return false
}
}
router.delete('/:id', function (req, res) {
if (exists) {
Album.destroy({
where: {
id: req.params.id
}
})
.then(function (data) {
return res.json(data)
})
.catch(function (err) {
return res.json({ error: err})
})
} else {
res.json({success: false})
}
})
If I place console logs all over the place, the output is what I expect it to be. There's is just something going wrong with Deleting two songs from my app. I can delete multiple songs if I hit the server directly with postman
Any idea?
You are actually destroying the album, before you destroy the songs.
In this case, since they probably have onDelete: 'SET NULL' option added, you will just de-associate the songs with that album.
Your fix will be to just replace the order of your calls :
// First we delete the songs and then the album
axios.delete(`${domain}/songs/ByAlbumId/${this.state.Album.id}`)
.then((res) => {
axios.delete(`${domain}/albums/${this.state.Album.id}`)
.then((res) => {

Categories

Resources