Search code examples
javascriptphpajaxcodeigniter

Ajax error 403 Forbidden CodeIgniter


I have two links on my html page :

<a id="1" onclick="like(this.id)">first</a>
<a id="2" onclick="like(this.id)">Second</a>

My JS is the following :

function like (id) {
    $.ajax({
        type:'POST',
        data: {
            func:
                'getNewLocations',
            '<?php echo $this->security->get_csrf_token_name(); ?>':
                '<?php echo $this->security->get_csrf_hash(); ?>',
            message:id
        },
        url:'<?php echo base_url();?>index.php/Category/like',
        success: function(result, statut) {
            if (result == 'add') {
                //do something
            }
            else if (result == 'remove') {
                //do something
            }
        }
    });
}

And the php method is the following (just for the example):

public function like() {
    echo 'add';
}

When I click at first on the link 1, the ajax request works fine, the server answers 'add'. But when I click on the link 2, I have a 403 error. Even more surprising, when I click at fisrt on the link 2, it works but then the link 1 doesn't. I work with codeIgniter.

Any idea of why and how solve it ? Thanks


Solution

  • Since it seems you are using a CSRF token to validate requests any request that sends an invalid token is going to get denied.

    When you click either anchor for the first time you use up that token. So in order to make an additional request you need to get a new token back in the response and use it instead of the old one.

    You just send back your data value, "add" in this case, with your csrf values: get_csrf_token_name() and get_csrf_hash()

    Instead of sending back just plain text you could send back JSON value that contains the values, for example

    php script

    function like(){
       $output = new stdClass;
       $output->csrfName = $this->security->get_csrf_token_name();
       $output->csrfHash = $this->security->get_csrf_hash();
       $output->data = "add";
       echo json_encode($output);
    }
    

    In javascript

    //Initial csrf values
    var csrfName = '<?php echo $this->security->get_csrf_token_name();?>';
    var csrfHash = '<?php echo $this->security->get_csrf_hash();?>';
    function like (id) {
        //create data object here so we can dynamically set new csrfName/Hash
        var data = {
           func:'getNewLocations',
           message:id
        };
        data[csrfName] = csrfHash;
    
        $.ajax({
            type:'POST',
            data: data, 
            //dataType tells jQuery to expect JSON response
            dataType:"json",
            url:'<?php echo base_url();?>index.php/Category/like',
            success: function(result, statut) {
                if(result.csrfName){
                   //assign the new csrfName/Hash
                   csrfName = result.csrfName;
                   csrfHash = result.csrfHash;
                }
                if (result.data == 'add') {
                    //do something
                }
                else if (result.data == 'remove') {
                    //do something
                }
            }
        });
    }
    

    Note if you are supporting ECMAScript 2015 capable browsers you could use computed keys to set your csrf values within the data object initializer

        $.ajax({
            type:'POST',
            data: {
                [csrfName]:csrfHash,
                func:'getNewLocations',
                message:id
            },