I am new to vue and stuck on this problem for quite some time. I have a login method that retrieves an API token and stores it in localStorage. The login API call is the only call that does not send Auth headers. After the Login every call should add the API token to the header.
When I login the interceptor does not set the new header. It needs a page refresh in the browser to work. Why is that, what am I doing wrong?
In my Login component I have this method:
methods: {
login() {
api.post('auth/login', {
email: this.email,
password: this.password
})
.then(response => {
store.commit('LOGIN');
localStorage.setItem('api_token', response.data.api_token);
});
this.$router.push('reservations')
}
}
Additionally I have this axios base instance and an interceptor:
export const api = axios.create({
baseURL: 'http://backend.local/api/',
// headers: {
// 'Authorization': 'Bearer ' + localStorage.getItem('api_token')
// },
validateStatus: function (status) {
if (status == 401) {
router.push('/login');
} else {
return status;
}
}
});
api.interceptors.request.use((config) => {
config.headers.Authorization = 'Bearer ' + localStorage.getItem('api_token');
return config;
}, (error) => {
return Promise.reject(error);
});
Related
I have created admin dashboard for one client. Project is created using Vue.js with Nuxt.js. Backend is Directus and it was created by my colleague.
Problem is that auth middleware is not working as I need.
When I log in, I save AUTH_TOKEN and REFRESH_TOKEN in cookies. Then, I am firing up one API call, if response.message is: 'Token expired', I send new API call with REFRESH_TOKEN to refresh. Then, from response I save new REFRESH_TOKEN and new AUTH_TOKEN to cookies again and if response is not 200, I redirect user to /login.
Here is my code (/middleware/authenticated.js):
import authService from '../services/authService';
export default function ({ $cookies, redirect, store, $toast, $router }) {
const access_token = $cookies.get('access_token');
const refresh_token = $cookies.get('refresh_token');
if (!access_token) {
$cookies.remove('access_token');
$cookies.remove('refresh_token');
store.commit('RESET_USER');
return redirect('/login');
}
if(access_token){
store.commit('SET_USER');
setInterval(function(){
try{
authService.retrieveCurrentUser({headers: {
"Content-type": "application/json",
"Authorization": `Bearer ${access_token}`,
}})
.then(() => {
console.log('ok');
})
.catch ((error) => {
console.log('prvy catch error', error);
if(error.response.data.errors[0].message == 'Token expired.'){
const config = {
"refresh_token": refresh_token
}
authService.refreshToken(config)
.then((response) => {
$cookies.set('access_token', response.data.data.access_token);
$cookies.set('refresh_token', response.data.data.refresh_token);
store.commit('SET_USER');
return redirect();
})
.catch((err) => {
console.log('druhy catch error', err);
$cookies.remove('access_token');
$cookies.remove('refresh_token');
store.commit('RESET_USER');
$toast.error('Platnosť vášho prihlásenia vypršala, prihláste sa prosím znova.', { timeout: 5000 });
clearInterval(this);
return redirect('/login');
})
}
})
}
catch (err){
console.log('treti catch error', err);
$cookies.remove('access_token');
$cookies.remove('refresh_token');
store.commit('RESET_USER');
$toast.error('Platnosť vášho prihlásenia vypršala, prihláste sa prosím znova.', { timeout: 5000 });
clearInterval(this);
return redirect('/login');
}
}, 300000)
}
};
Here is authService:
import api from '#/services/api';
export default {
login (credentials){
return api().post('/auth/login', credentials);
},
refreshToken(config) {
return api().post('/auth/refresh', config);
},
logout (refresh_token){
return api().post('/auth/logout', refresh_token);
},
retrieveCurrentUser(refresh_token){
return api().get('/users/me', refresh_token);
}
};
And this is how I call middleware inside page:
middleware: 'authenticated',
Also I need that setInterval because I want to check if token is still valid every 5 minutes.
When I use this code, I am receiving automatic log outs, or spamming of that toast notification.
i'm trying to send a request to the backend which uses headers, please how can i add the headers
this is my script tag
<script>
import axios from "axios";
export default {
data: () => ({
fullName: "",
streetAddress1: ""
}),
created() {
//user is not authorized
if (localStorage.getItem("token") === null) {
this.$router.push("/login");
}
},
methods: {
async onAddAddress() {
const token = localStorage.getItem("token");
headers: {
"Content-Type": "application/json",
Authorization: "Bearer" + token,
"x-access-token": token
}
try {
let data = {
fullName: this.fullName,
streetAddress: this.streetAddress1
};
const response = axios
.post("http://localhost:5000/api/addresses", data)
.then(res => {
console.log(res);
});
console.log(response);
} catch (error) {
console.error("error >>", error);
}
}
}
}
this code gives me an error, please how can i go about this
There are a few problems with your code. For instance you do not define headers as a variable and you do not add it to your axios request as a third argument. I think you need something like this:
async onAddAddress() {
const token = localStorage.getItem("token");
/// define headers variable
const headers = {
"Content-Type": "application/json",
Authorization: "Bearer" + token,
"x-access-token": token
};
let data = {
fullName: this.fullName,
streetAddress: this.streetAddress1
};
try {
/// config as the third argument.
conts result = await axios.post("http://localhost:5000/api/addresses", data, { headers });
console.log(result);
}
catch (error) {
console.error("error >>", error)
}
}
For async/await to work, you need to add await in front of the axios call.
Hope this helps.
Hi everyone!
I have my own custom strategy to get token, and all is good, but when a refresh page I lose user data and fetchUser does not works. It doesn´t send the params to API to get again the user data.
the workflow is next:
1- send params to token api and get token
2- send params to login API to get the user
//nuxt.config.js
customStrategy: {
_scheme: '~/schemes/customScheme',
endpoints: {
login: {
url: '/api/v1/token',
method: 'post',
propertyName: 'token',
headers: {'x-channel-id': 1}
},
user: {
url: '/api/v1/login',
method: 'post',
propertyName: false,
headers: {'x-channel-id': 1}
},
logout: null
}
}
customScheme.js
import LocalScheme from '#nuxtjs/auth/lib/schemes/local'
export default class CustomScheme extends LocalScheme {
_setToken (token) {
if (this.options.globalToken) {
// Set Authorization token for all axios requests
this.$auth.ctx.app.$axios.setHeader(this.options.tokenName, token)
}
}
_clearToken () {
if (this.options.globalToken) {
// Clear Authorization token for all axios requests
this.$auth.ctx.app.$axios.setHeader(this.options.tokenName, false)
}
}
mounted () {
if (this.options.tokenRequired) {
const token = this.$auth.syncToken(this.name)
this._setToken(token)
}
return this.$auth.fetchUserOnce()
}
async login (endpoint) {
if (!this.options.endpoints.login) {
return
}
// Get token
const result = await this.$auth.request({
...endpoint
},
this.options.endpoints.login
)
// Set token
if (this.options.tokenRequired) {
const token = this.options.tokenType
? this.options.tokenType + ' ' + result
: result
this.$auth.setToken(this.name, token)
this._setToken(token)
}
// If result I get and set user
if (result) {
const user = await this.$auth.request({
...endpoint
},
this.options.endpoints.user
)
this.$auth.setUser(user);
}
}
async fetchUser (endpoint) {
// User endpoint is disabled.
if (!this.options.endpoints.user) {
this.$auth.setUser({})
return
}
// Token is required but not available
if (this.options.tokenRequired && !this.$auth.getToken(this.name)) {
return
}
// Try to fetch user and then set
try{
const user = await this.$auth.requestWith(
this.name,
endpoint,
this.options.endpoints.login
)
this.$auth.setUser(user)
} catch (error){
console.log(error)
}
}
}
When I set this.$auth.setUser(user) in login() method all is fine and app redirect me to /dashboard page and the user information (like role and email) is displayed on navBar but when I refresh page I lose user data. The app try to fetchUser but it give me a 400 error because user and password not sent.
Another thing I don´t understand is Why endpoint parameter is undefined in async fetchUser (endpoint) ??? . I think there is an issue in this part.
I hope u can help me
Regards
I just remove all this library and did my own custom Nuxt authentication
https://nemanjadragun92.medium.com/nuxt-js-custom-authentication-245d2816c2f3
Problem:
In my react native app in order to remove repeated calls I have developed a general POST GET methods in httpClient file. It code is look likes this.
import axios from 'axios';
import AsyncStorage from '#react-native-community/async-storage';
axios.defaults.headers.post['Content-Type'] = 'application/json';
var instance = null;
const setAuthorisationHeder = async () => {
const token = JSON.parse(await AsyncStorage.getItem('auth_data'));
if (token) {
console.log('>>>>>> instance', instance);
Object.assign(instance.headers, {
Authorization: 'Bearer' + token.accessToken,
});
} else {
console.log('>>>>>> instance', instance);
Object.assign(instance.headers, {
Authorization: '',
});
}
};
export const setHeader = () => {
console.log('>>>>>>>> HIIII');
instance = axios.create({
baseURL: '',
timeout: 150000,
headers: {
'Content-Type': 'application/json',
},
});
instance.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
if (error.response.status) {
if (error.response.status === 401) {
AsyncStorage.removeItem('auth_data');
} else {
throw error;
}
} else {
console.log(error);
}
},
);
};
export const Get = (route, data) => {
function getData() {
return instance.get(
route,
data == null ? {data: {}} : {data: JSON.stringify(data)},
);
}
if (instance) {
console.log('>>>>>> HIIIIii');
// setAuthorisationHeder();
return getData();
}
return setHeader().then(getData);
};
export const Post = (route, data) => {
console.log('>>>>>> route', route);
function postData() {
return instance.post(route, JSON.stringify(data));
}
if (instance) {
console.log('>>>>>> HIIIIii');
// setAuthorisationHeder();
// setAuthorisationHeder();
return postData();
}
return setHeader().then(postData);
};
Can some tell me a way to add an authorization header to this instance? My token is storing the Asyncstorage in the middle of some actions so at the beginning called I don't have the token. As my code setHeader is running only one time so I created a method call setAuthorisationHeder() function. But it is giving me can not find property .then error when I am putting a request. Can someone help me to solve this issue? Thank you?
you can define global headers once and use it in every network call.
https://github.com/axios/axios#global-axios-defaults
Create a global auth variable where you'll store the auth data from storage. Before making a request get the auth data and use interceptor to set the bearer token.
let authToken = '';
const getAuthToken = async () => {
// asumming auth token was saved as string
authToken = await AsyncStorage.getItem('auth_data');
};
Interceptor
// request interceptor
axiosInstance.interceptors.request.use(
function (config) {
// Do something before request is sent
config.headers.Authorization = `Bearer ${authToken}`;
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error);
}
);
complete code
import axios from 'axios';
import AsyncStorage from '#react-native-community/async-storage';
let authToken = '';
const axiosInstance = axios.create({
baseURL: '',
timeout: 150000,
headers: {
'Content-Type': 'application/json',
},
});
// request interceptor
axiosInstance.interceptors.request.use(
function (config) {
// Do something before request is sent
config.headers.Authorization = `Bearer ${authToken}`;
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error);
}
);
const getAuthToken = async () => {
// asumming auth token was saved as string
authToken = await AsyncStorage.getItem('auth_data');
};
export const Get = async (route, data = {}) => {
// get and set auth token
await getAuthToken();
// route = /user?id=787878 or /user/787878
return await axiosInstance.get(route);
};
export const Post = async (route, data = {}) => {
await getAuthToken();
return await axiosInstance.post(route, data);
};
For my react-native app I need to make sure that before every fetch request to server the use-case below should be executed
-> check the expire date of token that is saved to redux.
--> If token is not expired, app keeps going on with requested fetch to server
--> If token expired, app immediately makes new request to refresh token without making user knows it. After successfully refreshing token, app keeps going on with requested fetch to server
I tried to implement middleware with redux-thunk, but I do not know whether it's good design or not. I just need someone experienced with redux and react to give me feedback over my middleware code.
This is how I make requests to server oveer my app's component through dispatching the checkTokenAndFetch - action creater.
url = "https://———————";
requestOptions = {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + this.props.token
}
};
dispatch(authActions.checkTokenAndFetch(url, requestOptions))
.then((data) => {
})
here is action creator - checkTokenAndFetch located in authActions.js
file where my actions located
function checkTokenAndFetch(url, requestOptions){
return dispatch => {
if(authServices.isTokenExpired()){
console.log("TOKEN EXPIRED");
authServices.refreshToken()
.then(
refreshToken => {
var arr = refreshToken.split('.');
decodedToken = base64.decode(arr[1]);
newTokenExpDate = JSON.parse(decodedToken).exp;
dispatch(writeTokenToRedux(refreshToken,newTokenExpDate));
},
error => {
Alert.alert("TOKEN refresh failed","Login Again");
Actions.login();
}
);
}
else{
console.log("TOKEN IS FRESH");
}
return authServices.fetchForUFS(url, requestOptions)
.then(
response => {
return response;
},
error => {
}
)
;
}
}
Here is isTokenExpired and refreshToken functions that I call for case of token expire, located in another file named authServices.js.
function isTokenExpired(){
var newState = store.getState();
var milliseconds = (new Date).getTime();
var exDate = newState.tokenExpDate;
return milliseconds>exDate*1000
}
function refreshToken(){
var refreshToken = store.getState();
return fetch('https://—————————', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer ' + refreshToken.token
}
})
.then((response) => {
return response._bodyText;
})
.catch((error) => {
return error;
})
}
and my fetchForUFS function in authServices.js to make a call to server after completeing token-check(refresh) stuff.
function fetchForUFS(url,requestOptions){
return fetch(url, requestOptions)
.then((response) => {
return response.json();
})
.then((responseData) =>{
return responseData;
})
.catch((error) => {
})
}
I've read tons of redux-thunk, redux-promise and middleware documentation and I'm yet not sure whether I am implementing middleware logic truly?