VUEjs & vuex with laravel backend authentication/remember - javascript

I'm working on a test-app with vuejs and vuex. I can signup/register the users and
I also got the user logged in and set the token in localstorage vuex. But where and how do you check if the user is already logged in after a refresh?
I'm currently using VUEX to handle async calls with axios.
the structure within my "store" folder is following
- Index.js
- actions.js
- mutations.js
- getters.js
Here is a part of my actions.js
import config from './../config'
import axios from 'axios'
import Ls from '../mixins/localStorage'
axios.defaults.headers.common = {
'Accept': 'application/json'
};
export default {
login ({commit,dispatch}, user) {
commit('setLoading', {
modalName: 'loginModal',
state: true
});
const endpoint = config.apiUrl + 'clients/web/login';
axios.post(endpoint, user)
.then(response => {
Ls.set('token',response.data.request_key);
dispatch('getUserData');
return true;
})
.catch(e => {
commit('setLoading', {
modalName: 'loginModal',
state: false
});
console.log(e);
return false
});
},
getUserData({commit}){
const endpoint = config.apiUrl + 'user/profile';
if(Ls.get('token')) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + Ls.get('token').replace(/(^\")|(\"$)/g, '');
}
axios.get(endpoint)
.then(response => {
commit('setUser',response.data);
commit('hideModal', 'loginModal');
})
.catch(e => {
console.log(e);
return false
});
}
}
So the question is
is this the right way to log a user in?
How and where do you check if the user is already logged in and if so, what do you do next ?
Thanks in advance!

Related

Accessing id token of firebase 9 in axios interceptor directly

Is there a way to get the id token from firebase 9 directly in the axios interceptor? It was possible with firebase 8.
import axios from "axios";
import config from "../config";
import { getAuth, getIdToken } from "firebase/auth";
const API = axios.create({
responseType: "json",
baseURL: config.ApiUrl
});
API.interceptors.request.use(async (request) => {
const auth = getAuth();
const { currentUser } = auth;
request.headers = {
Authorization: `Bearer ${await currentUser.getIdToken()}`,
};
return request;
});
currentUser is null first because it is loaded async by firebase. How can I access it directly without always having the problem that the first time it crashes because the user is not loaded yet?
Thank your for your help.
You can create a function that waits for onAuthStateChanged() to load auth state and returns a promise containing user's token. Try:
const getUserToken = async () => {
return new Promise((resolve, reject) => {
const unsub = onAuthStateChanged(getAuth(), async (user) => {
if (user) {
const token = await getIdToken(user);
resolve(token)
} else {
console.log("User not logged in")
resolve(null)
}
unsub();
});
})
}
API.interceptors.request.use(async (request) => {
const token = await getUserToken();
if (token) {
request.headers = {
Authorization: `Bearer ${token}`,
};
} else {
// prompt user to login?
}
return request;
});
Make sure you have initialized Firebase SDK before using getAuth(). I recommend creating a different file firebase.js, initialize required services and exporting the instances as explained in this answer.

Token Authorization header with passport in vue.js

Where can i put the Authorization header token in axios after dispatching login action with laravel passport authentication in a seprated vue.js project?I tried with setting it in main.js like this and doesnt work properly. After dispatching, In the QuestionIndex component, the axios call dont have the authorization header automatically. And by refreshing the page, it has the authorization header. I can fix this by putting the token header in QuestionIndex Component. But I dont think this is a proper way to do it. Please help me with this problem.
In main.js
const token = localStorage.getItem('access_token');
if (token) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
}
In login.vue
login(){
this.$store
.dispatch("login", this.form)
.then(() => {
this.$router.push({ name: "QuestionIndex" });
})
.catch(err => {
console.log(err);
});
}
In vuex store
state: {
token: localStorage.getItem('access_token') || null,
user: {},
},
mutations: {
setToken(state, data) {
state.token = data.token;
state.user = data.user;
},
},
actions: {
login({ commit }, credentials) {
return axios.post("http://127.0.0.1:8000/api/login", credentials).then(( res ) => {
localStorage.setItem('access_token', res.data.data.token);
commit("setToken", res.data.data);
});
},
},
getters: {
token: (state) => state.token,
}
You can set the Authorization header after initializing the axios instance like this:
axiosInstance.interceptors.request.use((config) => {
const token = localStorage.getItem('access_token');
config.headers.Authorization = `Bearer ${token}`
return config
})
In your VUEX action, make sure to use the axiosInstance you created in your main.js (or whereever). If you just import axios in your VUEX store like this import axios from 'axios' it will not work, because it's not the axios instance you set the header on.
you can try this
axios.post("http://127.0.0.1:8000/api/login", credentials, { headers: { Authorization: 'Bearer ' + localStorage.getItem('access_token') } })

Having problem with Authorization in vuejs vuex stores

I am writing code to call api using axios. So, for this code I have to send an otp to the api along with an authorization token. I am using vuex store.
I am getting an error of 406(not applicable). This is the code I have written.
import { isAuthenticated } from './auth'
import axios from 'axios'
export default ({
state: {
},
mutations: {
},
getters: {
},
actions: {
VERIFY: (payload) => {
const userId = isAuthenticated().user._id
return axios
.post(apilink, payload, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${isAuthenticated().token}`,
Accept: 'application/json'
}
}).then(response => {
console.log(response)
return response.data
})
.catch(error => {
if (error) {
console.log(error)
}
})
}
},
modules: {
}
})
<template>
<mdb-btn color="info" #click="verify()">Verify</mdb-btn>
</template>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js">
data () {
return {
value: ''
}
},
methods: {
verify () {
this.$store.dispatch('VERIFY', {
otp: this.value
}).then(success => {
console.log(success)
}).catch(error => {
console.log(error)
})
}
}
</script>
I think it's the problem with authorization part. Please help me.
isAuthenticated is funtion used to get data from localStorage
export const isAuthenticated = () => {
if (localStorage.getItem('auth')) {
return JSON.parse(localStorage.getItem('auth'))
}
return false
}
406 error is appearing because of Accept parameter in the header try after removing "Accept: 'application/json'"

NuxtServerInit sets Vuex auth state after reload

I'm setting a basic authentication on a Nuxt project with JWT token and cookies to be parsed by nuxtServerInit function.
On login with email/password, works as intended, setUser mutation is triggered and the appropriate user object is stored in state.auth.user.
On reload, nuxtServerInit will get the jwt token from req.headers.cookies, call the GET method and identify user.Works like a charm.
Problem starts when I hit the /logout endpoint. state.auth.user is set to false and Im effectively logged out... but If I refresh, I'm logged in again with the previous user data. Even if my cookies are properly empty (on below code, both user and cookie are undefined after logout and refresh, as expected)
So I really don't get why is my state.auth.user is back to its initial value...
store/index.js
import Vuex from "vuex";
import auth from "./modules/auth";
import axios from "~/plugins/axios";
const cookieparser = process.server ? require("cookieparser") : undefined;
const END_POINT = "api/users";
const createStore = () => {
return new Vuex.Store({
actions: {
async nuxtServerInit({ commit, dispatch}, { req }) {
let cookie = null;
console.log(req.headers.cookie)
if (req.headers.cookie) {
const parsed = cookieparser.parse(req.headers.cookie);
try {
cookie = JSON.parse(parsed.auth);
console.log("cookie", cookie)
const {accessToken} = cookie
const config = {
headers: {
Authorization: `Bearer ${accessToken}`
}
}
const response = await axios.get(`${END_POINT}/current`, config)
const user = response.data
console.log("user nuxt server init", user)
await commit('setUser', user)
} catch (err) {
// No valid cookie found
console.log(err);
}
}
}
},
modules: {
auth
}
});
};
export default createStore;
modules/auth.js
import axios from "~/plugins/axios";
const Cookie = process.client ? require("js-cookie") : undefined;
const END_POINT = "api/users";
export default {
state: {
user: null,
errors: {}
},
getters: {
isAuth: state => !!state.user
},
actions: {
login({ commit }, payload) {
axios
.post(`${END_POINT}/login`, payload)
.then(({ data }) => {
const { user, accessToken } = data;
const auth = { accessToken };
Cookie.set("auth", auth);
commit("setUser", user);
})
.catch(e => {
const error = e;
console.log(e);
commit("setError", error);
});
},
logout({ commit }) {
axios
.post(`${END_POINT}/logout`)
.then(({ data }) => {
Cookie.remove("auth");
commit("setUser", false);
})
.catch(e => console.log(e));
},
},
mutations: {
setUser(state, user) {
state.user = user;
},
setError(state, errors) {
state.errors = errors;
}
}
};
The way I logout my user is by creating a mutation called clearToken and commit to it in the action :
State :
token: null,
Mutations :
clearToken(state) {
state.token = null
},
Actions :
logout(context) {
context.commit('clearToken')
Cookie.remove('token')
}
This way, you token state revert back to null.

Why are Relay Modern QueryRenderer render props undefined?

This is my first attempt at using Relay Modern.
Fetching for a specific User from a PostgraphQL GraphQL Server.
It is fetching the data successfully but not passing to render function:
import {createFragmentContainer, QueryRenderer, graphql} from 'react-relay'
import environment from 'environment'
#CSSModules(styles) export default class Profile extends Component {
render() {
var {props: {children}} = this
return (
<QueryRenderer
environment={environment}
query={graphql`
query ProfileQuery {
userById(id: "f0301eaf-55ad-46db-ac90-b52d6138489e") {
firstName
userName
}
}
`}
render={({error, relayProps}) => {
if (error) {
return <div>{error.message}</div>
} else if (relayProps) {
...
}
return <div>Loading...</div>
}}
/>
)
}
}
Only "Loading..." is rendered.
I am guessing because it successfully fetches data that the graphql server and environment are ok.
I am not using React 16 and the project also uses Redux.
Any suggestions please as to why relayProps wouldn't have a value (e.g. relayProps.user)?
One further thing that may help, the environment (file) is in the main application and the QueryRenderer and components are in an imported npm package (to be shared across a number of applications). As mentioned, the query seems to work fine so I did not think this was a problem. I also run the relay compiler on the package but not the main application since there are no relay components there.
Just in case it's needed the environment is setup using:
const {
Environment,
Network,
RecordSource,
Store,
} = require('relay-runtime')
// Instantiate Store for Cached Data
const store = new Store(new RecordSource())
// Create Network for GraphQL Server
const network = Network.create((operation, variables) => {
// GraphQL Endpoint
return fetch(config.gqlapiProtocol + "://" + config.gqlapiHost + config.gqlapiUri + "/a3/graphql" , {
method: 'POST',
headers: {
'Content-Type': "application/json",
'Accept': 'application/json',
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => {
return response.json()
})
})
// Instantiate Environment
const environment = new Environment({
network,
store,
})
// Export environment
export default environment
props are not relayprops
render={({ error, props }) => {
if (error) {
return <div>{error.message}</div>;
} else if (props) {
...
}
return <div>Loading...</div>;
}}
and
fetch(GRAPHQL_URL, {
method: 'POST',
get headers() {
return {
'Content-Type': 'application/json',
'Accept': 'application/json',
};
},
body: JSON.stringify({
query: operation.text, // GraphQL text from input
variables
})
})
.then(response => response.json())
.then((json) => {
// https://github.com/facebook/relay/issues/1816
if (operation.query.operation === 'mutation' && json.errors) {
return Promise.reject(json);
}
return Promise.resolve(json);
})
);

Categories

Resources