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

rhys's avatar
Level 5

Authenticating Image Uploads API Route Sanctum

Hi

I have a website where you can upload images using vue2-dropzone. I have it working so it posts to an image controller, however now that I'm wanting to deploy the website I want the image controllers post method to be guarded by Auth. At the moment this is not guarded.

I feel like I'm missing the obvious answer as the vue component I'm uploading from is contained within my website. I'm struggling to find a way to authenticate the post axios call with the current user without creating a new sign in route from vue?

Any advice would be appreciated, I'm self taught and probably weakest in js, I've tried looking at the docs but I can't seem to find a full example. I receive a "Unauthenticated" response.

Working unauthed route --

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

Route::post('image', [ImageController::class, 'store']);

authenticated error route

Route::post('image', function () { })->middleware(['auth:sanctum']);
    
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

Vue component called on mount, csrf stuff not needed as I binned trying to use spa authentication

            getToken(){
                axios.get('/sanctum/csrf-cookie').then(response => {
                    this.xsrf = response.config.headers['X-XSRF-TOKEN']
                    axios.post('/tokens/create',{token_name: 'imageToken'}).then(response => {
                        let $token;
                        $token = JSON.parse(response.request.response)
                        var headers = {
                            "Accept": "application/json",
                            "Cache-Control": "no-cache",
                            "Authorization": "Bearer " + $token.token,
                            "X-XSRF-TOKEN": this.xsrf
                        }
                        this.config.headers = headers;
                    });
                });
            }
0 likes
4 replies
Sergiu17's avatar

https://rowanwins.github.io/vue-dropzone/docs/dist/#/installation

this package? all you have to do is to append token to the headers

<vue-dropzone ref="myVueDropzone" id="dropzone" :options="dropzoneOptions"></vue-dropzone>

export default {
  data: function () {
    return {
      dropzoneOptions: {
          headers: { "Authorization": "Bearer " + $token.token, }
      }
    }
  }
}

most simple and insecure way is to store this token in localStorage, after you login, store the token in localStorage, then use it everytime you need it

rhys's avatar
Level 5

@Sergiu17 Hi

I have custom component on top of the one you shared where I set some custom data properties like below

					var headers = {
                        "Accept": "application/json",
                        "Cache-Control": "no-cache",
                        "Authorization": "Bearer " + $token.token,
                        "X-XSRF-TOKEN": this.xsrf
                    }
                    this.config.headers = headers;

I have checked the headers data property on both vue component and it matches the headers above. I have also checked the image post request headers and it includes the bearer token.

Is my api Auth route right? I'm not really sure how to debug this further, at lunch I'll check postman with those headers to reach another secure route? Is there anything I need to do with setting up token abilities or is the default to have all abilities?

I also was unsure of what to put in the /tokens/create data request, its seemed to just want a string so I did this. Which does return a token looking value.

		axios.post('/tokens/create',{token_name: 'imageToken'}).then(response => {})
rhys's avatar
Level 5

Ok,

I think the issue is around what life cycle hook I'm using on vue. My getToken method is not affecting what header is used in the post.

Currently the below works fine as I'm hard coding a working auth token. It seems like config.headers data is set and passed to vue-dropzone before my getToken code is run. I think vue dropzone sets headers on creation because even though the headers data property is updated to the one from the get token call, the one on the post request matches what I initially set the config.

Any ideas?

<template>
        <div id="uploader">
            <vue-dropzone id="upload" :options="config" @vdropzone-complete="afterComplete"></vue-dropzone>
        </div>
</template>

<script>
    import vueDropzone from "vue2-dropzone";
    import axios from "axios";

    export default {
        props: ['message'],
        data: () => ({
            config: {
                url: '/api/image',
                dictDefaultMessage: "",
                timeout: 0,
                maxFilesize: 209715200,
                maxFiles: 10,
                headers: { "Authorization": "Bearer 46|T308wWn44LR6rcCOhs5h1wkNUyyOxMIOixE1bNpm", }
            },
            xsrf:''
        }),
        components: {
            vueDropzone
        },
        methods: {
            afterComplete(file) {
                this.$emit('storeFileName',file.xhr.response)
            },
            getToken(){
                    axios.post('/tokens/create',{token_name: 'imageToken'}).then(response => {
                        let $token;
                        $token = JSON.parse(response.request.response)
                        this.config.headers  = {
                            "Authorization": "Bearer " + $token.token,
                        }
                    });
            }
        },
        beforeMount() {
            this.getToken();
        },
        created(){
             this.config.dictDefaultMessage = this.message;
        }
    };
</script>
rhys's avatar
rhys
OP
Best Answer
Level 5

Ok

I needed to use conditional rendering,

https://v2.vuejs.org/v2/guide/conditional.html?redirect=true https://stackoverflow.com/questions/49839226/vuejs-child-component-method-run-before-parent-query-done-running

I added a v-if to check if the api key is fetched.

<template>
        <div id="uploader">
            <vue-dropzone id="upload" v-if="hasApiKey" :options="config" @vdropzone-complete="afterComplete"></vue-dropzone>
        </div>
</template>

<script>
    import vueDropzone from "vue2-dropzone";
    import axios from "axios";

    export default {
        props: ['message'],
        data: () => ({
            config: {
                url: '/api/image',
                dictDefaultMessage: "",
                timeout: 0,
                maxFilesize: 209715200,
                maxFiles: 10,
                headers: {}

            },
            hasApiKey: false
        }),
        components: {
            vueDropzone
        },
        methods: {
            afterComplete(file) {
                this.$emit('storeFileName',file.xhr.response)
            },
            getToken: function(){
                axios.post('/tokens/create',{token_name: 'imageToken'}).then(response => {
                    let $token;
                    $token = JSON.parse(response.request.response)
                    this.config.headers  = {
                        "Authorization": "Bearer " + $token.token,
                    }
                    this.hasApiKey = true;
                });
            }
        },
        beforeMount() {
            this.getToken();
        },
        created(){
             this.config.dictDefaultMessage = this.message;
        }
    };
</script>

Please or to participate in this conversation.