I’m fairly new to Vue and it’s my first time using Pinia. I’m following this guide to set up Firebase, Pinia and Axios. The app I’m building uses FirebaseUI to sign a user in, via an email link – this all happens in the LoginPage component below:
(Please ignore all incorrectly types variables/functions – I’m just trying to get this working in the first place)
<script setup lang="ts">
import { onMounted } from "vue";
import { EmailAuthProvider } from "firebase/auth";
import { auth } from "firebaseui";
import { auth as firebaseAuth } from "../firebase/config";
import { useUserStore } from "../stores/user"
onMounted(async () => {
const uiConfig: auth.Config = {
signInSuccessUrl: "/",
signInOptions: [
{
provider: EmailAuthProvider.PROVIDER_ID,
signInMethod: EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD,
forceSameDevice: true,
},
],
callbacks: {
signInSuccessWithAuthResult: function (authResult) {
const store = useUserStore();
store.user = authResult;
return true;
},
},
};
const ui = new auth.AuthUI(firebaseAuth);
ui.start("#firebaseui-auth-container", uiConfig);
});
</script>
<template>
<div id="firebaseui-auth-container"></div>
</template>
When the user successfully signs in, the app updates the Pinia store user object, with the AuthResult return object from the signInSuccessWithAuthResult
function. When debugger, I can see that the object being stored looks like the following:
{
additionalUserInfo: {...}
operationType: "signIn"
user: {
accessToken: "eyJhbGciOiJSUzI1N..."
auth: {...}
displayName: null
...
}
}
I.e. the accessToken
is being stored. The user store is below:
import { defineStore } from 'pinia'
export const useUserStore = defineStore("userStore", {
state: () => ({
user: null as any
}),
getters: {
getUser(state) {
return state.user
}
}
})
In the app I have set up an axios interceptor, that appends the accessToken
to any Axios request made by the app:
axiosInstance.interceptors.request.use((config) => {
const userStore = useUserStore();
if (userStore) {
debugger;
// accessToken is undefined
config.headers.Authorization = 'Bearer ' + userStore.user.user.accessToken;
}
return config;
});
When attempting the retrieve the accessToken
from the user store at this point, it’s gone. Most (if not all) of the other properties from the user object still exist, but not the access token, therefore I’m pretty sure I’m using the store correctly:
{
additionalUserInfo: {...}
credential: null
operationType: "signIn"
user: {
// accessToken is gone
apiKey: "..."
appName: "[DEFAULT]"
email: "..."
emailVerified: true
....
}
}
Can anybody explain where I’m going wrong with this, and why the accessToken
is being removed from the store? It looks to me as though I’m using the Pinia store correctly, and I’m pretty sure that the interceptor is also correct. However it’s likely that I’m going about storing the access token in the wrong way. I’d appreciate any help/advice about how to setup Firebase authentication correctly with Vue.
Edited to include value of the user store when debugging inside the interceptor.
2
Answers
It looks like accessToken might be in userStore.user.user.accessToken?
Im just finishing the same battle that you are in… IMO there are many ways that this setup can be configured… This is similar to why you might use callbacks in one place, and async await in another it depends on your project structure.
Heres a simple example that might help you clarify it.
first
create a firebase file to hold the config put this where ever your organization habits tells you to put it. Just remember so we can use it later.
Second – userStore
The user store does the legwork. We will use the actions when we want to interact with userauth from our ui.
*** step3 setup the login / reg components in vue. ***
register is going to be simailar
now whenever you want to access the user it is in userStore.userData
if you dont have the userStore up yet just use the useUserStore() method and access it the same way you do from the setup in login / register view