nuxtjs - global shared editable server variables - vuejs2

I'm using nuxtjs and I use app authentication against a restful API. I want to store in a server side variable my token, wich I use everywhere to request informations to the API, but I cannot store it in process.env variabls because I need to modify it when it expires (after 1 hour). The token is for the app, not for users, so every call to the api have to use the same token. I try to use fs to save my token in a json file and refresh it when it expires, but I cannot use fs in nuxtjs, it tells me that fs doesn't exists, maybe because I try to use it in client side.
Do you know how can I do that?
Thank you

I solved by using express in server side envirenment, I had to put server middleware configuration in nuxt.config.js:
const bodyParser = require('body-parser')
const session = require('express-session')
module.exports = {
...
serverMiddleware: [
bodyParser.json(),
session({
secret: 'my-secret',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 3600000 }
}),
'~/server'
],
...
and on /server/index.js file :
const express = require('express')
const api = require('./api')
// Create express router
const router = express.Router()
// Transform req & res to have the same API as express
// So we can use res.status() & res.json()
var app = express()
router.use((req, res, next) => {
Object.setPrototypeOf(req, app.request)
Object.setPrototypeOf(res, app.response)
req.res = res
res.req = req
next()
})
router.get('/myroute', (req, res) => {
api.get('myroute')
.then((data) => {
res.json({success: true})
})
.catch((e) => {
res.status(500).json({ message: 'An error occurred' })
})
})
module.exports = {
path: '/server',
handler: router
}
and on my /server/api.js file
const parameters = require('./parameters.js')
const router = require('./router.js')
const axios = require('axios')
const auth = {
accessToken: null,
expiresAt: null
}
const getToken = () => {
const expiresAt = auth.expiresAt
const accessToken = auth.accessToken
const expires = expiresAt ? (new Date()).getTime() : null
if (expires && expires - expiresAt > 0) {
return new Promise((resolve, reject) => {
resolve(accessToken)
})
}
return new Promise((resolve, reject) => {
axios.get(parameters.api + router.token, {
params: parameters.auth
})
.then(({data}) => {
auth.accessToken = data.access_token
auth.expiresAt = (new Date()).getTime() + data.expires_in - 60
resolve(data.access_token)
})
.catch((e) => {
reject(e)
})
})
}
const getCompleteRoute = (route) => {
return new Promise((resolve, reject) => {
getToken()
.then((token) => {
resolve(parameters.api + router[route] + '?access_token=' + token)
})
.catch((e) => {
reject(e)
})
})
}
const get = (route, params) => {
return new Promise((resolve, reject) => {
getCompleteRoute(route)
.then((completeRoute) => {
axios.get(completeRoute, {params: params})
.then(({data}) => {
resolve(data)
})
.catch((e) => {
reject(e)
})
})
.catch((e) => {
reject(e)
})
})
}
const post = (route, params) => {
return new Promise((resolve, reject) => {
getCompleteRoute(route)
.then((completeRoute) => {
axios.post(completeRoute, params)
.then(({data}) => {
resolve(data)
})
.catch((e) => {
reject(e)
})
})
.catch((e) => {
reject(e)
})
})
}
module.exports = {
get: get,
post: post
}

Related

Sending a PUT request with Spotify's WebAPI returns a 401 error

What I want to do
I want to change the playlist image using Spotify's API.
API reference:https://developer.spotify.com/documentation/web-api/reference/#/operations/upload-custom-playlist-cover
Problem
API request returns 401 error.
Access token is fine.
Other requests using the same axios instance (spotify_api) are fine.
Even if the access token is invalid, the process of reissuing and repeating the previous request runs.
My Code
home.vue
import spotify_api from "../../util/spotify_api";
import fivetune_api from "../../util/fivetune_api";
let fi_user_id = "";
let sp_user_id = "";
let access_token = "";
export default {
data() {
return {
playlists: [],
tracks: [],
track: {
no: 1,
artist: "",
artist_url: "",
album_url: "",
track_name: "",
track_image_url: "",
track_url: "",
},
};
},
name: "Home-1",
props: {
msg: String,
},
async created() {
fi_user_id = this.$cookies.get("fi_user_id");
access_token = this.$cookies.get("access_token");
await fivetune_api.get("/api/user/" + fi_user_id).then((res) => {
sp_user_id = res.data.sp_user_id;
});
fivetune_api.get("/api/playlist/home").then(async (res) => {
this.playlists = res.data;
for (let i = 0; i < this.playlists.length; i++) {
this.tracks = [];
await Promise.all([
spotify_api.get("/users/" + this.playlists[i].sp_creator_user_id),
fivetune_api.get("/api/download/" + this.playlists[i].fi_playlist_id),
])
.then((res2) => {
this.playlists[i].creator_name = res2[0].data.display_name;
this.playlists[i].download_count = res2[1].data[0].download_count;
})
.catch((err) => {
console.log(err);
console.log(access_token);
// access_token = refreshToken(err);
});
for (let j = 0; j < this.playlists[i].track_ids.length; j++) {
await spotify_api
.get("/tracks/" + this.playlists[i].track_ids[j].sp_track_id)
.then((res_track) => {
this.track = {
no: j + 1,
track_id: res_track.data.id,
artist: res_track.data.artists[0].name,
artist_url: res_track.data.artists[0].external_urls.spotify,
album_url: res_track.data.album.external_urls.spotify,
track_name: res_track.data.name,
track_image_url: res_track.data.album.images[0].url,
track_url: res_track.data.external_urls.spotify,
};
this.tracks.push(this.track);
})
.catch((err) => {
console.log(err);
// access_token = refreshToken(err);
});
}
this.playlists[i].tracks = this.tracks;
this.playlists[i].playlist_image =
process.env.VUE_APP_HOST +
"/images/playlist/" +
this.playlists[i].fi_playlist_id +
".jpeg";
}
});
},
methods: {
download: async function (index) {
const track_1 = document.getElementById(
`playlist-${index}-track-0-id`
).value;
const track_2 = document.getElementById(
`playlist-${index}-track-1-id`
).value;
const track_3 = document.getElementById(
`playlist-${index}-track-2-id`
).value;
const track_4 = document.getElementById(
`playlist-${index}-track-3-id`
).value;
const track_5 = document.getElementById(
`playlist-${index}-track-4-id`
).value;
const fi_playlist_id = document.getElementById(
`playlist-${index}-id`
).value;
const playlist_name = document.getElementById(
`playlist-${index}-playlist-name`
).innerHTML;
///////////////////////////////////////////////////////////////////////////////////////////////////
////// this //////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
spotify_api
.post("/users/" + sp_user_id + "/playlists", {
name: playlist_name,
description: "",
public: false,
})
.then(async (res) => {
const created_playlist_id = res.data.id;
spotify_api
.put("/playlists/" + created_playlist_id + "/images", {
data: this.playlists[index].img_base64
})
.then(() => {})
.catch((err) => {
console.log(err);
});
///////////////////////////////////////////////////////////////////////////////////////////////////
////// end //////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
await Promise.all([
spotify_api.post("/playlists/" + created_playlist_id + "/tracks", {
uris: [
"spotify:track:" + track_1,
"spotify:track:" + track_2,
"spotify:track:" + track_3,
"spotify:track:" + track_4,
"spotify:track:" + track_5,
],
}),
])
.then(() => {
fivetune_api
.post("/api/download", {
fi_user_id: fi_user_id,
fi_playlist_id: fi_playlist_id,
})
.then(() => {
this.playlists[index].download_count += 1;
this.$swal.fire({
title: "ダウンロード完了",
html: "Spotifyのプレイリストに追加されました。",
confirmButtonColor: "#8db30f",
});
})
.catch((err) => {
console.log(err);
});
})
.catch((err) => {
console.log(err);
this.$swal.fire({
title: "ダウンロード失敗",
confirmButtonColor: "#8db30f",
});
});
});
},
},
};
spotify_api.js(
An instance of axios is created)
import axios from 'axios';
const spotify_api = axios.create({
baseURL: 'https://api.spotify.com/v1',
withCredentials: false,
})
let refresh_token_promise;
const getRefreshToken = () => {
return new Promise((resolve) => {
console.log(300)
axios.get('/api/refresh').then((res) => {
const access_token = res.data
return resolve(access_token)
}).catch((err) => {
console.log('err 2')
console.log(err)
})
})
}
spotify_api.interceptors.request.use(req => {
req.headers = {
authorization: `Bearer ${localStorage.getItem('access_token')}`,
"Content-Type": "application/json",
}
return req
})
spotify_api.interceptors.response.use((res) => {
return res
}, (err) => {
if (err.config && err.response && err.response.status === 401 && !err.config._retry) {
console.log(100)
if (!refresh_token_promise) {
err.config._retry = true;
refresh_token_promise = getRefreshToken().then((token) => {
refresh_token_promise = null;
console.log(token)
localStorage.setItem('access_token', token)
return token
}).catch((err) => {
console.log('err')
console.log(err)
})
}
console.log(200)
return refresh_token_promise.then((access_token) => {
const config = err.config;
config.headers = {
authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
}
return axios.request(config)
}).catch((err) => {
console.log(err)
})
}
return Promise.reject(err)
})
export default spotify_api
What I tried
I tried various names of the body requesting the image
( data、image、postData )
I tried setting Content-Type to image/jpeg
I wrote it directly without using axios instant.
await axios
.put(
"https://api.spotify.com/v1/playlists/" +
created_playlist_id +
"/images",
{
data: this.playlists[index].img_base64,
headers: {
authorization: `Bearer ${localStorage.getItem(
"access_token"
)}`,
"Content-Type": "application/json",
},
}
)
.then((res_image) => {
console.log("res_image");
console.log(res_image);
})
.catch((err) => {
console.log("err");
console.log(err);
});
Environment
FrontEnd
Vue.js3
BackEnd
Node.js

No 'Access-Control-Allow-Origin' header is present on the requested resource (MERN)

This error is never ending, I keep getting it and it's been days I've been trying to find a solution for this annoying error.
Here is what happens when I try to log in.
My app works perfectly fine in localhost but there are alot of issue when I uploaded it to heroku and it is really annoying.
Im using
Axios.defaults.withCredentials = true;
code on my every front end.
My backend
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')
var MongoDBStore = require('connect-mongodb-session')(session);
app.use(express.json());
const corsOptions = {
origin: 'https://incomparable-speculoos-abdd5f.netlify.app',
//update: or "origin: true," if you don't wanna add a specific one
credentials: true,
};
app.use(cors(corsOptions));
app.options('*', cors());
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }))
mongoose.connect("hidden",
{
useNewUrlParser: true,
useUnifiedTopology: true
}
)
var store = new MongoDBStore({
uri: 'hidden',
collection: 'sessions'
});
// Catch errors
store.on('error', function(error) {
console.log(error);
});
app.use(session({
secret: "hidden",
resave: false,
store: store,
saveUninitialized: false,
cookie: {
maxAge: 1000 * 60 * 60 * 24
}
}))
app.post('/login', async (req, res) => {
const email = req.body.email;
const password = req.body.password;
voterModel.find({email: email}, {"email":1}, async (err, result) => {
if (err) {
console.log(err)
} else {
if(result.length > 0) {
const user = await voterModel.findOne({email: email})
const pass = await user.comparePassword(password)
if (pass) {
req.session.user = user
} 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('/voted', async (req, res) => {
// FOR UPDATING THE VOTING STATUS
const email = req.body.email
// VARIABLES FOR CHOSEN CANDIDATES OF USER
const president = req.body.president
const vice = req.body.vice
const treasurer = req.body.treasurer
// SETS THE STATUS OF VOTER TO TRUE SO HE/SHE CAN ONLY VOTE ONCE
voterModel.updateOne({email: email}, {$set : {status: true}}, (err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
}
})
// BELOW ARE THE COMMANDS FOR INCREMENTING THE VOTE COUNT OF SELECTED CANDIDATES OF THE VOTER
presidentModel.updateOne({nickname: president}, {$inc : {votes: 1}}, (err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
}
})
viceModel.updateOne({nickname: vice}, {$inc : {votes: 1}}, (err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
}
})
treasurerModel.updateOne({nickname: treasurer}, {$inc : {votes: 1}}, (err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
}
})
})
app.get('/login', (req, res) => {
if (req.session.user) {
res.send({loggedIn: true, user: req.session.user})
} else {
res.send({loggedIn: false})
}
})
app.post('/checkVote', (req, res) => {
const email = req.body.email
const num = true;
voterModel.find({ $and : [{email: email}, {status : num}]},(err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
if (result.length > 0) {
res.send( {voted: true } )
} else {
res.send( {voted: false } )
}
}
})
})
app.get("/logout", (req, res) => {
req.session.destroy(err => {
if (err) return next(err)
res.status(200).send('logged out')
})
res.status(200).send('User has been logged out');
});
const PORT = process.env.PORT || 3001
app.listen(PORT, () => {
console.log('running on port 3001')
})

Vuex store authentication and axios interceptor returns undefinied

Scratching my head on this issue. I do all the authentication logic in my vuex store. When using an axios interceptor to catch the error, it always returns undefined. When I only perform the interceptor on other calls, it works fine. (did this by adding if(token) { api.interceptor...}
My code is as follow
store/index.js
return new Promise((resolve, reject) => {
commit('auth_request')
api({url: '/api/auth/login', data: user, method: 'POST' })
.then((resp) => {
let token = resp.data.token
//let sites = JSON.stringify(resp.data.sites)
let user = JSON.stringify(resp.data.user)
localStorage.setItem('token', token)
api.defaults.headers.common['Authorization'] = 'Bearer ' + token
commit('auth_success', token)
//commit('set_sites', sites)
commit('set_default', resp.data.user.default_site)
commit('set_user', user)
resolve(resp)
})
.catch((err) => {
commit('auth_error', err)
reject(err)
})
})
},
axios.js
import axios from 'axios'
import store from 'src/store'
let token = localStorage.getItem('token')
const api = axios.create({ baseURL: 'http://127.0.0.1:8000/' })
api.interceptors.response.use(response => {
console.log('ok')
return response;
}, error => {
if (error.response.status === 401) {
store.dispatch('log_out')
}
return error
});
Login.vue
this.loading = true
this.$store.dispatch('login', this.user)
.then(() => {
this.loading = false
this.$router.push('/')
})
.catch(error => {
this.loading = false
this.errorMessage = error.response.data.message
})
},```
Dont be hard on me, junior in this ;-)

redirect after authenticate expired using axios in nuxt js

This is my refresh token plugin
refresh_token.js
const axiosOnResponseErrorPlugin = ({ app, $axios, store }) => {
$axios.onResponseError(err => {
const code = parseInt(err.response && err.response.status)
let originalRequest = err.config
if (code === 401) {
originalRequest.__isRetryRequest = true
const refreshToken = store.state.auth.refresh_token ? store.state.auth.refresh_token : null
if (refreshToken) {
return new Promise((resolve, reject) => {
$axios.post('refresh-token/', {
refresh: refreshToken
})
.then((response) => {
if (response.status === 200) {
let auth = response.data
err.response.config.headers['Authorization'] = `${auth.access}`
}
resolve(response)
})
.catch(e => {
// should jump here after facing error from request
reject(e)
})
})
.then((res) => {
return $axios(originalRequest)
})
.catch(e => {
app.router.push('/')
})
}
}
})
}
export default axiosOnResponseErrorPlugin
My problem is, if refresh token is not expired then it's working fine, but if it is expired then it should redirect to a page which is not doing right now. I couldn't find any way to redirect/push to another router after expiration.
Have any suggestion ?
Here is my solution about this situation ..You have to check your original request also. and for that it will create a loop ..if some how refresh token is failed .So check it with your refresh token URL.
$axios.interceptors.response.use(
response => {
return response;
},
function(error) {
const originalRequest = error.config;
if (error.response.status === 401 && originalRequest.url === "accounts/refresh-token/") {
store.dispatch("clearUserData")
return Promise.reject(error)
}
if (error.response.status === 401 && !originalRequest._retry) {
console.log('originalRequest ', originalRequest)
originalRequest._retry = true;
const refreshToken = localStorage.getItem("UserRefreshToken");
return store.dispatch("refreshToken")
.then(res => {
$axios.defaults.headers.common[
"Authorization"
] = localStorage.getItem("UserToken");
return $axios(originalRequest);
})
}
return Promise.reject(error);
}
);
Here is the complete solution of this question
refresh_token.js
const axiosOnResponseErrorPlugin = ({ app, $axios, store }) => {
$axios.onResponseError(err => {
const code = parseInt(err.response && err.response.status)
let originalRequest = err.config
let explode = originalRequest.url.split("/") // i split the original URL to fulfill my condition
if (code === 401 && explode[explode.length - 2] === "refresh-token") {
app.router.push('/')
}
if (code === 401 && !originalRequest._retry) {
originalRequest._retry = true
const refreshToken = store.state.auth.refresh_token ? store.state.auth.refresh_token : null
if (refreshToken) {
return new Promise((resolve, reject) => {
$axios.post('refresh-token/', {
refresh: refreshToken
})
.then((response) => {
if (response.status === 200) {
let auth = response.data
err.response.config.headers['Authorization'] = `${auth.access}`
}
resolve(response)
})
.catch(e => {
// should jump here after facing error from request
reject(e)
})
})
.then((res) => {
return $axios(originalRequest)
})
.catch(e => {
app.router.push('/')
})
}
}
})
}
export default axiosOnResponseErrorPlugin

How to assign value to global variable in fetch method in react native?

I am creating a react native app and I'm getting data from an API. I need to assign specific data into a global variable. That means my API return JSON data like {user_Id:"1' user_name:'abc' user_email:'abc#gmail.con'}. I need to assign user_Id into a global variable to access that in all of my screens.
This is what I tried;
componentDidMount() {
const arrFinal = [];
const {userDel} = this.state;
fetch('my API url')
.then(response => response.json())
.then(responseJson => {
// console.warn(responseJson);
arrFinal.push(responseJson);
arrFinal.map((item, index) => {
global.UserID = item.user_Id
})
.catch(error => {
console.error(error);
});
console.error(global.UserID)
}
But here nothing will print on console. How can I fix this problem?
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
componentDidMount() {
const arrFinal = [];
const {userDel} = this.state;
fetch('my API url')
.then(response => response.json())
.then(responseJson => {
// console.warn(responseJson);
arrFinal.push(responseJson);
arrFinal.map((item, index) => {
global.UserID = item.user_Id
console.error(global.UserID)
})
.catch(error => {
console.error(error);
});
// console.error(global.UserID)
}
or :
async componentDidMount() {
const arrFinal = [];
const { userDel } = this.state;
const response = await fetch('my API url');
const responseJson = await response.json();
// console.warn(responseJson);
arrFinal.push(responseJson);
arrFinal.map((item, index) => {
global.UserID = item.user_Id;
console.error(global.UserID);
});
console.error(global.UserID);
}