As user is passed as a prop its properties are not reactive, so Vue won't update the UI if you try to change them..
Similar to what you do to qr and qr_code you should copy that value to a data property on creating and updating that:
<template>
<div class="text-center">
<div class="checkbox">
<label>
<!-- CHANGED HERE -->
<input type="checkbox" v-model="toggle" :disabled="google2fa_secret"> {{ toggletext }}
</label>
</div>
<hr>
<div v-if="toggle">
<!-- CHANGED HERE -->
<div v-if="google2fa_secret">
<!-- CHANGED HERE -->
<p v-if="google2fa_secret">Your 2FA Secret Key</p>
<!-- CHANGED HERE -->
<h3>{{ google2fa_secret }}</h3>
<button class="md-button md-raised md-accent" @click="disable">{{ disabletext }}</button>
<p>Instructions for first time setup:</p>
<p>Please install the <a :href="google_link">Google Authenticator</a> first.</p>
<p>
You can install it from the
<a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en">Google
Play</a> or
<a href="https://apps.apple.com/us/app/google-authenticator/id388497605">Apple Store</a>.
</p>
<p>Scan The QR code:</p>
<img :src="qr_code" alt="qr_code"/>
<br>
<form action="/google2fa/authenticate" method="POST">
<input type="hidden" v-model="csrf" name="_token">
<input name="one_time_password" type="text">
<button type="submit">Authenticate</button>
</form>
</div>
<div v-else>
<button class="md-button md-raised md-accent" @click="generate">{{ generatetext }}</button>
</div>
</div>
<div v-else>
<p>You don't have the 2FA enabled.</p>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: "TwoFactorAuth",
props: {
qr: {
type: String,
required: false,
default: '',
},
user: {
type: Object,
required: true,
},
toggletext: {
type: String,
required: true,
},
generatetext: {
type: String,
required: true,
},
disabletext: {
type: String,
required: true,
},
},
data() {
return {
toggle: !!this.user.google2fa_secret,
google_link: 'https://www.google.com/landing/2step/',
qr_code: this.qr,
google2fa_secret: this.user.google2fa_secret, // ADDED HERE
csrf: ''
}
},
methods: {
generate() {
axios.post(`/api/user/${this.user.eid}/2fa`)
.then(res => {
this.google2fa_secret = res.data.secret; // CHANGED HERE
this.qr_code = res.data.qr;
})
.catch(this.handleError);
},
disable() {
axios.post(`/api/user/${this.user.eid}/2fa`, {disable: true})
.then(res => {
this.google2fa_secret = res.data.secret; // CHANGED HERE
this.qr_code = '';
this.toggle = false;
})
.catch(this.handleError);
}
},
mounted() {
this.csrf = document.head.querySelector('meta[name="csrf-token"]').content;
}
}
</script>
<style scoped>
</style>