Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

CamKem's avatar
Level 10

Security issues when exposing CSRF token in the response

Hello, I am trying to do an axios request in my Vue component & I need to have the CSRF token for sanctum authentication of the request. Is there any security risk if I expose the X-CSRF token through HandleInertiaRequests middleware?

I am trying to implement a feature that will let the user know if the username they are typing in is available. Even with the CSRF token exposed, I am still getting a 401 response, so I really am stuck with this. So far this is the code I have. Maybe you can suggest a better way of doing it?

<script setup>
import {Link, router, useForm} from '@inertiajs/vue3';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import AppHead from "@/Layouts/AppHead.vue";
import {reactive, toRefs, watch} from "vue";
import axios from "axios";

const form = useForm({
    email: '',
    username: '',
    password: '',
    password_confirmation: '',
    terms: false,
});

const state = reactive({
    checking: false,
    available: false,
    unavailable: false
});

watch(() => form.username, (value) => {
    checkUsername();
});

const checkUsername = () => {
    state.checking = true;
    axios.get('/users/' + form.username + '/exists', {
        withCredentials: true,
        headers: {
            'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')

        }
    })
        .then(response => {
            state.checking = false;
            state.available = response.data.exists;
            state.unavailable = !response.data.exists;
        })
        .catch(error => {
            console.error(error);
            state.checking = false;
        });
};

const {checking, available, unavailable} = toRefs(state);

const submit = () => {
    form.post(route('login'), {
        onFinish: () => form.reset('password', 'password_confirmation'),
    });
};
</script>

<template>
    <AppHead title="Register">
        <meta content="Register" name="description"/>
        <meta name="csrf-token" :content="$page.props.csrfToken">
    </AppHead>

    <form @submit.prevent="submit">
        <div class="m-2">
            <InputLabel for="username" value="Username"/>
            <div class="flex">
                <TextInput
                    id="username"
                    v-model="form.username"
                    autocomplete="username"
                    autofocus
                    class="mt-1 block"
                    type="text"
                />
                <InputError :message="form.errors.username" class="mt-2"/>
                <span v-show="checking">Checking...</span>
                <span v-show="available">Available!</span>
                <span v-show="unavailable">Unavailable!</span>
            </div>
        </div>

        <div class="mt-4 m-2">
            <InputLabel for="email" value="Email"/>
            <TextInput
                id="email"
                v-model="form.email"
                autocomplete="email"
                class="mt-1 block w-full"
                type="email"
            />
            <InputError :message="form.errors.email" class="mt-2"/>
        </div>

        <div class="mt-4 m-2">
            <InputLabel for="password" value="Password"/>
            <TextInput
                id="password"
                v-model="form.password"
                autocomplete="new-password"
                class="mt-1 block w-full"
                type="password"
            />
            <InputError :message="form.errors.password" class="mt-2"/>
        </div>

        <div class="mt-4 m-2">
            <InputLabel for="password_confirmation" value="Confirm Password"/>
            <TextInput
                id="password_confirmation"
                v-model="form.password_confirmation"
                autocomplete="new-password"
                class="mt-1 block w-full"
                type="password"
            />
            <InputError :message="form.errors.password_confirmation" class="mt-2"/>
        </div>

        <div class="flex items-center justify-end mt-4">
            <Link :href="route('login')" class="underline text-sm text-gray-600 hover:text-gray-900">
                Already registered?
            </Link>

            <PrimaryButton :class="{ 'opacity-25': form.processing }" :disabled="form.processing" class="ml-4">
                Register
            </PrimaryButton>
        </div>
        <div class="m-2 mt-4 pt-4 border-t border-gray-500">
            <p class="text-center text-gray-500 text-xs">
                Social Login Coming Soon here...
            </p>
        </div>
    </form>
</template>
0 likes
1 reply
CamKem's avatar
CamKem
OP
Best Answer
Level 10

I discovered it is not a good idea to expose the CSRF token through HandleInertiaRequests middleware, as it can be used for cross site attacks. All i needed to do was change my route and sanctum handled the rest.

Please or to participate in this conversation.