How to serialize axios functions ?
-
Hello, I’m still learning Vue.js and Quasar and I have a problem with my server store.
I use JWT and have 2 functions using axios : refreshToken() and updateProfile().
When updating my profile, I want first to refresh my token to ensure my user is still valid.
My problem is that the updateProfile() is called before the end of the refreshToken() with this code :this.$store.dispatch('server/refreshToken'); // SHOULD WAIT refreshToken() END before continue... const pwd_data = new URLSearchParams(); pwd_data.append("user_id", this.Name); pwd_data.append("password", this.new_password1); this.$store.dispatch('server/changePassword', { data: pwd_data })
my store :
refreshToken ({ commit }) { const authorization = { headers: { 'Authorization': 'Bearer ' + state.token } } this.$axios .patch(constantes.SERVER_URL + "/api/auth/refresh-token", authorization) .then(response => { // status 200 -> "Refreshed" = OK console.log("refreshToken - Response OK : ", response); }) .catch(error => { // Request Failed! ....
My updateProfile() has the same structure.
I tried to use await in the refreshToken() axios call, but it doesn’t wait 'til the result !
I read many things about promises, but they are always relating to display problems.
As I just want to serialize my two function calls in my server dialog, how would you do that ?
Thanks for your help. -
@Incremental Try to first return a promise from the refreshToken action, like this:
refreshToken ({ commit }) { const authorization = { headers: { 'Authorization': 'Bearer ' + state.token } } return this.$axios .patch(constantes.SERVER_URL + "/api/auth/refresh-token", authorization) // ...
Notice the returning of the axios call, that will return a promise. Then, like this:
this.$store.dispatch('server/refreshToken') .then(() => { // SHOULD WAIT refreshToken() END before continue... const pwd_data = new URLSearchParams(); pwd_data.append("user_id", this.Name); pwd_data.append("password", this.new_password1); this.$store.dispatch('server/changePassword', { data: pwd_data }) }).catch(error => { // Request failed })
-
Wow ! Thanks beets for your help, it works.
Just a complement : how could I retreive error codes for refreshToken() and changePassword() ?
For some reasons, I get a CORS error in my refreshToken() and a HTTP 500 in changePassword() but nothing is displayed with the following code :this.$store.dispatch('server/refreshToken') .then(() => { // SHOULD WAIT refreshToken() END before continue... const pwd_data = new URLSearchParams(); pwd_data.append("user_id", this.Name); pwd_data.append("password", this.new_password1); this.$store.dispatch('server/changePassword', { data: pwd_data }) }).catch(error => { // Request failed console.log('error.config', error.config); console.log("error response : ", error.response); console.log('error.message', error.message); console.log("error.request : ", error.request); })
-
@Incremental Try something like this:
refreshToken ({ commit }) { const authorization = { headers: { 'Authorization': 'Bearer ' + state.token } } return this.$axios .patch(constantes.SERVER_URL + "/api/auth/refresh-token", authorization) .then(response => { // status 200 -> "Refreshed" = OK console.log("refreshToken - Response OK : ", response); }) .catch(error => { // Request Failed! // do whatever here, but re-throw console.log('Refresh error code: ', error.response.status) throw error }) }
And
this.$store.dispatch('server/refreshToken') .then(() => { // SHOULD WAIT refreshToken() END before continue... const pwd_data = new URLSearchParams(); pwd_data.append("user_id", this.Name); pwd_data.append("password", this.new_password1); this.$store.dispatch('server/changePassword', { data: pwd_data }).catch(error => { console.log('Change password error code: ', error.response.status) }) }).catch(error => { // Request failed, but we already caught the error console.log(error) })
You probably have to change your changePassword action to return the axios promise call like we did with the refresh token one. There’s many ways to skin this cat once you realize how promises / async / errors all work together. You could also just not put a catch block in your actions (make sure you’re returning the axios call still), and do this:
async someFn() { try { await this.$store.dispatch('server/refreshToken') const pwd_data = new URLSearchParams(); pwd_data.append("user_id", this.Name); pwd_data.append("password", this.new_password1); await this.$store.dispatch('server/changePassword', { data: pwd_data }) } catch(error) { // One of the two requests failed console.log('error.config', error.config); console.log("error response : ", error.response); console.log('error.message', error.message); console.log("error.request : ", error.request); } }
Edit, and if you want to know which of the two actions failed:
async someFn() { try { await this.$store.dispatch('server/refreshToken') } catch(error) { // Refresh requests failed console.log('error.config', error.config); console.log("error response : ", error.response); console.log('error.message', error.message); console.log("error.request : ", error.request); } try { const pwd_data = new URLSearchParams(); pwd_data.append("user_id", this.Name); pwd_data.append("password", this.new_password1); await this.$store.dispatch('server/changePassword', { data: pwd_data }) } catch(error) { // Change requests failed console.log('error.config', error.config); console.log("error response : ", error.response); console.log('error.message', error.message); console.log("error.request : ", error.request); } }
-
Thanks a lot beets, you really helped me !
-
I’m just getting into the world of jwt tokens myself, and my understanding of the token flow is, your system should be working between a refresh and an access token (which seems to be missing here) and this “workflow” should be seamless for the app developer. By seamless I mean, either the current user is “logged in” or she isn’t. Every call to the server should have a (short-lived) access token in the request header (ala
Authorization Bearer <token>
). If the access token is no longer valid (because of ttl) the system should automatically call the refresh endpoint, also sending the refresh token. If it is still valid, then a new access token is given and the app can continue working. If the refresh token is no longer valid, the request for refresh gets an an error in return and the user is logged out. There shouldn’t need to be a checking of the refresh token “manually” in the code ever. There should be a set state for the user. LoggedIn (true or false), which is set at login and only revoked, when the refresh token is stale i.e. with that error from the refresh endpoint.Please correct me if I’m wrong.
Scott
-
You’re right, I just found this clear article simpler than the official doc : https://hasura.io/blog/best-practices-of-using-jwt-with-graphql
But at the moment, I can’t really test, because there are some bugs with RLuders JWT plugin and CORS…