1

I have a codeigniter4 application. When i set public $regenerate = true; in Security.php the view with a form submit to add employee redirects to itself on submit. But when regenerate is false, code submits to the controller and data is processed as required How can i solve the issue with regenerate set to true?.

The controller function handling add_employee is:

public function add_employee()
    {
        $session = session();
        $request = \Config\Services::request();
        $db = \Config\Database::connect();
       
        $usermodel = new \App\Models\UserModel();
        $data['user']=$usermodel->getRow($session->get('email'));
        $data['title'] = 'Add employee';

        $employeemodel = new \App\Models\EmployeeModel();
        $divisionmodel = new \App\Models\DivisionModel();
        $userRoleModel = new \App\Models\UserRoleModel();

        $data['employee'] = $employeemodel->getAll();
        $data['designation'] = $employeemodel->getAllDesignations();
        $data['division'] = $divisionmodel->findAll();
        $data['roles']  = $userRoleModel->findAll();
        
        
         $role_id= $data['user']['role_id'];
        if($role_id==5||$role_id==10){ //Division Admin or Division head

         $builder=$db->table('tbl_division');
         $builder->select('tbl_division.int_divisionID');

             if($role_id==5){         
            
                 $builder->join('tbl_administrator','tbl_administrator.int_divisionID=tbl_division.int_divisionID');
            } else{
                $builder->join('tbl_employee','tbl_employee.int_divisionID=tbl_division.int_divisionID');
            }

         $division=$builder->get()->getRowArray();
         $data['selected_division'] = $division['int_divisionID'];

         $builder=$db->table('tbl_department');
         $builder->select('tbl_department.int_departmentID,tbl_department.vchr_departmentName');
         $builder->where('tbl_department.int_divisionID',$division['int_divisionID']);
         $data['department']= $builder->get()->getResultArray();
        }
         elseif($role_id==11)//Department Head
         {
          $builder=$db->table('tbl_employee');
          $builder->select('int_departmentID');          
          $builder->where('tbl_employee.int_userID',$data['user']['id']);
          $department = $builder->get()->getRowArray();          
          $department_id = $department['int_departmentID'];
          $data['department_id']=$department_id;

          $builder=$db->table('tbl_department');
          $builder->select('tbl_department.int_divisionID');
          $builder->where('tbl_department.int_departmentID',$department_id);
          $division=$builder->get()->getRowArray();
          $data['selected_division'] = $division['int_divisionID'];

          $builder=$db->table('tbl_department');          
          $builder->select('tbl_department.id,tbl_department.int_departmentID,tbl_department.vchr_departmentName');
          $builder->where('tbl_department.int_divisionID',$division['int_divisionID']);
          $data['department']= $builder->get()->getResultArray();
         }

        
        if ($this->request->getMethod() == "post") {

            
             $validation =  \Config\Services::validation();

             $_POST['csrf_test_name']=$_REQUEST['csrf_test_name'];

             $rules = [
           
                    "csrf_test_name" => [
                        "label" => "CSRF Token Name",
                        "rules" => "required|trim|alpha_numeric|max_length[64]"
                    ],
                    "vchr_CDIT_employeeID" => [
                        "label" => "CDIT EmployeeID",
                        "rules" => "required|trim|alpha_numeric|max_length[10]"
                    ],
                    "vchr_employeeName" => [
                        "label" => "Employee Name",
                        "rules" => "required|trim|alpha_space|max_length[100]"
                    ],
                    "vchr_email_id" => [
                        "label" => "Email",
                        "rules" => "required|trim|valid_email|max_length[100]"
                    ],
                    "int_mobileNo" => [
                        "label" => "Mobile No",
                        "rules" => "required|trim|numeric|max_length[10]|min_length[10]"
                    ],
                    "int_empType" => [
                        "label" => "Mobile No",
                        "rules" => "required|trim|numeric|max_length[3]"
                    ]
                    
                ];

                 $int_empType = $request->getPost('int_empType');
      
      
      if(!($int_empType==7 || $int_empType==8)){


        $rules1= [
            "int_designationID" => [
                        "label" => "Designation",
                        "rules" => "required|trim|numeric|max_length[4]"
                    ],
            "int_divisionID" => [
                        "label" => "Division",
                        "rules" => "required|trim|numeric|max_length[4]"
                    ]

        ];

        $rules=array_merge($rules,$rules1);
        
        }

        if(!($int_empType==7 || $int_empType==8 || $int_empType==9 )){

        
        $rules1= [
            "int_departmentID" => [
                        "label" => "Department",
                        "rules" => "required|trim|numeric|max_length[4]"
                    ]

        ];

         $rules=array_merge($rules,$rules1);

        }
       
        if (!($this->validate($rules))) {   

                $session->setFlashdata('employeemessage', '<div class="alert alert-danger" role="alert">
                Validation Errors!</div>');
           
                return redirect()->back()->withInput();
           
            } 
        else{
                
                $email = strip_tags($request->getPost('vchr_email_id'));
                $name = strip_tags($request->getPost('vchr_employeeName'));

         

          $employeeemailexists = $employeemodel->where('vchr_email_id',$email)->first();
          
          if($employeeemailexists){

             $session->setFlashdata('employeemessage', '<div class="alert alert-danger" role="alert">
             employee Creation Failed. employee with this email already exists</div>');
             return redirect()->to('employee');
            
          }

          $userdata  = $usermodel->where('email',$email)->first();
          if($userdata){

            $session->setFlashdata('employeemessage', '<div class="alert alert-danger" role="alert">
             User Creation Failed. User with this email already exists</div>');
             return redirect()->to('employee');
            
          }
          $date_created = date("Y-m-d H:i:s", time());

          $comb = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*_-";
          $shfl = str_shuffle($comb);
          $pwd = substr($shfl,0,12);
          $data = [
              'name' => $name,
              'email' => $email,
              'image' => 'default.jpg',
              'password' => md5($pwd),
              
              'role_id' => 4,
              'is_active' => 1,
              'isFirstLogin' => 1,
              'date_created' => $date_created
          ];

         $token = base64_encode(random_bytes(32));

         
          $emailstatus=sendemail($name,$email,$token,$pwd, 'verify');

          if(!$emailstatus){
               
                $emailmsg='<span class="alert alert-danger" role="alert">Password couldnot be send through email.Check mail configuration</span>';

            }
            else
                $emailmsg='<span class="alert alert-success" role="alert"> Password send to employee email </span>';
           $usermodel->insert($data);
          
           $res=$usermodel->where('email',$email)->first();

            $insert_id=$res['id'];

            $employeemodel->saveToDB($insert_id);

            $session->setFlashdata('employeemessage', '<div class="alert alert-success" role="alert">
                Employee added successfully!.Password is <b>'.$pwd.'</b></div>'.$emailmsg);
                return redirect()->to('employee');
            }
        }
        else{
            echo view('templates/admin_header', $data).
            view('templates/admin_sidebar').
            view('templates/admin_topbar', $data).
            view('employee/add_employee').
            view('templates/admin_footer');
        }

      
    }

My view add_employee

<!-- Begin Page Content -->

<div class="container-fluid">

    <!-- Page Heading -->
    <h1 class="h3 mb-4 text-gray-800">Add Employees </h1>

    <div class="card shadow mb-3">
        <!--<div class="card-header">
            Add Employees
        </div>-->

        <div class="card-body">
        <div style="display: flex; justify-content: flex-end"> <button  onclick="history.back();"><i class="fas fa-arrow-left"></i> Back</button>
            </div>
          <?php
          $attributes = array('id' => 'myform');
          echo form_open('employee/add_employee',$attributes);?>


                <div class="form-group">
                    <label for="vchr_CDIT_employeeID">CDIT Employee ID<font color="red"> *</font></label>
                    <input class="form-control" maxlength="100" 
                    type="text" name="vchr_CDIT_employeeID" placeholder="Enter CDIT Employee ID"
                    value="<?= set_value('vchr_CDIT_employeeID'); ?>">
                    <?= form_error('vchr_CDIT_employeeID', '<small class="text-danger pl-3">', '</small>'); ?>
                </div>
                <div class="error" width="100%"></div>


                <div class="form-group">
                    <label for="vchr_employeeName">Employee Name<font color="red"> *</font></label>
                    <input class="form-control" maxlength="100" 
                    type="text" name="vchr_employeeName" placeholder="Enter Employee Name" value="<?= set_value('vchr_employeeName'); ?>">
                    <?= form_error('vchr_employeeName', '<small class="text-danger pl-3">', '</small>'); ?>
                </div>
                <div class="error" width="100%"></div>


                <div class="form-group">
                    <label for="vchr_email_id">E-Mail ID<font color="red"> *</font></label>
                    <input class="form-control" maxlength="100" 
                    type="email" name="vchr_email_id" placeholder="Enter Email ID" value="<?= set_value('vchr_email_id'); ?>">
                    <?= form_error('vchr_email_id', '<small class="text-danger pl-3">', '</small>'); ?>
                </div>
                <div class="error" width="100%"></div>


                <div class="form-group">
                    <label for="int_mobileNo">Mobile Number<font color="red"> *</font></label>
                    <input class="form-control"
                    type="text" minlength="10" maxlength="10" name="int_mobileNo" placeholder="Enter Mobile Number" value="<?= set_value('int_mobileNo'); ?>">
                    <?= form_error('int_mobileNo', '<small class="text-danger pl-3">', '</small>'); ?>
                </div>
                <div class="error" width="100%"></div>
                
                <div class="form-group">
                    <label for="int_empType">Enter Employee Type <font color="red"> *</font></label>
                    <select name="int_empType" id="int_empType" class="form-control">
                      <option value="">---Select Role---</option>
                      <?php foreach ($roles as $r) : ?>
                      <?php 
                     
                     if(!in_array($r['id'],[1,3,5]))
                      {
                      
                      ?><option value="<?= $r['id']; ?>"><?= $r['role']; ?></option>
                    <?php } endforeach; ?>
                      </select>
                      <?= form_error('int_empType', '<small class="text-danger pl-3">', '</small>'); ?>
                </div>
                <div class="error" width="100%"></div>

                <div class="form-group" id="divisionDiv">
                    <label for="int_divisionID">Enter Division <font color="red"> *</font></label>
                    <select name="int_divisionID" id="int_divisionID" class="form-control"
                    
                    >
                    
                     <?php if(isset($selected_division)) { 
                     foreach ($division as $d) :
                     if($d['int_divisionID']==$selected_division){
                     ?>
                    >
                     <option value="<?= $d['int_divisionID']; ?>" selected > <?= $d['vchr_divisionName']; ?></option>
                    <?php
                    } endforeach;
                    } else {
                    ?>
                    
                    
                        <option value="">---Select Division---</option>
                        <?php foreach ($division as $d) : ?>
                        <option value="<?= $d['int_divisionID']; ?>"                     
                        >
                        <?= $d['vchr_divisionName']; ?></option>
                        <?php endforeach; }?>
                    </select>
                    <?= form_error('int_divisionID', '<small class="text-danger pl-3">', '</small>'); ?>
                </div>
                <div class="error" width="100%"></div>

                <div class="form-group" id="deptdiv">
                    <label for="int_departmentID">Enter Department <font color="red"> *</font></label>
                    <select name="int_departmentID" id="int_departmentID" class="form-control">
                    <?php if(isset($department_id)) { 
                     foreach ($department as $d) :
                     if($d['int_departmentID']==$department_id){
                     ?>
                   
                     <option value="<?= $d['int_departmentID']; ?>" selected > <?= $d['vchr_departmentName']; ?></option>
                    <?php
                    } endforeach;
                    } else {
                    ?>
                        <option value="" selected>---Select Department---</option>
                        <?php if(isset($department)){
                         foreach ($department as $d) : ?>
                        <option value="<?= $d['int_departmentID']; ?>">
                        <?= $d['vchr_departmentName']; ?></option>
                        <?php endforeach; }
                        
                        }?>

                    </select>
                    <?= form_error('int_departmentID', '<small class="text-danger pl-3">', '</small>'); ?>
                </div>
                <div class="error" width="100%"></div>


                <div class="form-group" id="desigDiv">
                    <label for="int_designationID">Enter Designation <font color="red"> *</font></label>
                    <select name="int_designationID" id="int_designationID" class="form-control">
                        <option value="">---Select Designation---</option>

                    </select>
                    <?= form_error('int_designationID', '<small class="text-danger pl-3">', '</small>'); ?>

                </div>
                <div class="error" width="100%"></div>


                <!-- button save -->
                  <div class="form-group">
                        <button type="submit" class="btn btn-success" >Add Employee!</button>
                    </div>
            </form>
        </div>

        <div class="card-footer small text-muted">
        <font color="red"> *</font> must be filled
        </div>
    </div>

</div>
<!-- /.container-fluid -->

</div>
<!-- End of Main Content -->

</div>
<!-- /.container-fluid -->

</div>
<!-- End of Main Content -->

<script type="text/javascript">


$('#int_divisionID').on('change', function(){
    var int_divisionID = $('#int_divisionID').val();
   
     var csrfName = "csrf_test_name";
    var csrfHash = $('[name="csrf_test_name"]').val();

    $.ajax({
        type:"POST",
        url: "<?php echo site_url('Department/getDepartments')?>",
        data: {[csrfName]: csrfHash, int_divisionID: int_divisionID},
        success:function(response){

            $('#int_departmentID').html('<option value=""> ---Select Department--- </option>');
            $.each(JSON.parse(response), function(key,val) {
                $('#int_departmentID').append('<option value="' + val.id + '">'+ val.vchr_departmentName +'</option>');
            });
        }
    });


});

$('#int_departmentID').on('change', function(){
    var int_divisionID = $('#int_divisionID').val();
   
     var csrfName = "csrf_test_name";
    var csrfHash = $('[name="csrf_test_name"]').val();
$.ajax({
        type:"POST",
        url: "<?php echo site_url('Department/getDesignations')?>",
        data: {[csrfName]: csrfHash, int_divisionID: int_divisionID},
        success:function(response){

            $('#int_designationID').html('<option value=""> --Select Designation-- </option>');
            $.each(JSON.parse(response), function(key,val) {
                $('#int_designationID').append('<option value="' + val.id + '">'+ val.vchr_designation +'</option>');
            });
        }
    });
});
</script>

<script type="text/javascript">

$(document).ready(function() {

$('#int_empType').on('change', function(){
 var int_empType = $('#int_empType').val();
 if(int_empType==7 || int_empType==8 || int_empType==9 ){
 $('#deptdiv').hide();
 $('#int_departmentID').val(0);
 }
 else{
 $('#deptdiv').show();
 $('#divisionDiv').show();
  $('#desigDiv').show();
 }
 if(int_empType==7 || int_empType==8){
 
  $('#divisionDiv').hide();
  $('#desigDiv').hide();
  $('#int_divisionID').val(0);
  }
  else{
  $('#divisionDiv').show();
  }
 
});

 var int_divisionID = $('#int_divisionID').val();
    
    var csrfName = "csrf_test_name";
    var csrfHash = $('[name="csrf_test_name"]').val();
$.ajax({
        type:"POST",
        url: "<?php echo site_url('Department/getDesignations')?>",
        data: {[csrfName]: csrfHash, int_divisionID: int_divisionID},
        success:function(response){
            $('#int_designationID').html('<option value=""> --Select Designation-- </option>');
            $.each(JSON.parse(response), function(key,val) {
                $('#int_designationID').append('<option value="' + val.id + '">'+ val.vchr_designation +'</option>');
            });
        }
    });

jQuery.validator.addMethod("name_check", function(value, element) {
return this.optional(element) || /^[a-zA-Z\s.\-]+$/.test(value);
});

jQuery.validator.addMethod("CDIT_employeeID", function(value, element) {
return this.optional(element) || /^[a-zA-Z0-9\s.\-]+$/.test(value);
});

jQuery.validator.addMethod("email_check", function(value, element) {
return this.optional(element) || /^[a-zA-Z0-9._-]+@([a-zA-Z0-9-]+\.[a-zA-Z])*[a-zA-Z0-9-]+\.[a-zA-Z]{2,5}$/i.test(value);
});

jQuery.validator.addMethod("phonenumber", function(value, element) {
return this.optional(element) || /^\d{10}$/.test(value);
});


$("#myform").validate({

rules: {

vchr_CDIT_employeeID: {

required: true,
CDIT_employeeID:true,

},

vchr_employeeName: {

required: true,
name_check:true,

},

vchr_email_id: {

required: true,
//email_check:true,

},

int_mobileNo: {
required:true,
minlength:10,
maxlength:10,
phonenumber:true,

},

int_divisionID:{
  required: {
                depends: function(element) {
                    return (!($('#int_empType').val()==7 || $('#int_empType').val()==8))
                }
                }

},

int_departmentID :{
  required: {depends: function(element) {
                    return (!($('#int_empType').val()==7 || $('#int_empType').val()==8 ||  $('#int_empType').val()==9))
                }}

},

int_designationID: {
  required: {depends: function(element) {
                    return (!($('#int_empType').val()==7 || $('#int_empType').val()==8 ||  $('#int_empType').val()==9))
                } }
},



int_empType: {
  required:true,
},


},
messages: {

vchr_employeeName: {
required: "<font color='#FF0000'> Employee Name required !!</font>",
name_check:"<font color='#FF0000' > Invalid Special characters in Employee Name!!</font>"
},

vchr_email_id: {
required: "<font color='#FF0000'> E-mail ID is required !!</font>",
//email_check: "<font color='#FF0000'> Invalid Email Format !!</font>",
},

int_mobileNo: {
  required: "<font color='#FF0000'> Mobile Number is required !!</font>",
  minlength : "<font color='#FF0000'> Mobile Number should be of 10 characters long !!</font>",
  maxlength : "<font color='#FF0000'> Mobile Number should be of 10 characters long !!</font>",
  phonenumber : "<font color='#FF0000'> Mobile Number is Invalid !!</font>",
},

vchr_CDIT_employeeID :{
  required: "<font color='#FF0000'> CDIT Employee ID required !!</font>",
  CDIT_employeeID : "<font color='#FF0000'> Invalid Employee ID !!</font>",

},

int_divisionID :{
  required: "<font color='#FF0000'> Division required !!</font>",

},

int_departmentID :{
  required: "<font color='#FF0000'> Department required !!</font>",

},

int_designationID :{
  required: "<font color='#FF0000'> Designation required !!</font>",

},

int_empType : {
  required: "<font color='#FF0000'> Employee Type required !!</font>",

},


},
errorElement: "span",
errorPlacement: function(error, element) {
  error.appendTo(element.parent("div").next());
},
submitHandler: function (form) {
            /*var key = "eTicketingCI4CDIT#$abc";
            var form = document.getElementById("myForm");
            var inputs = form.getElementsByTagName("input");

            for (var i = 0; i < inputs.length; i++) {
                var input = inputs[i];
                if (input.type !== "submit" && input.type !== "button") {
                    var encryptedValue = CryptoJS.AES.encrypt(input.value, key).toString();
                    input.value = encryptedValue;
                }
            }*/
              
              form.submit();
          }

});

});


</script>

The CI4 version is 4.2.12. My Security.php file:

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Security extends BaseConfig
{
    /**
     * --------------------------------------------------------------------------
     * CSRF Protection Method
     * --------------------------------------------------------------------------
     *
     * Protection Method for Cross Site Request Forgery protection.
     *
     * @var string 'cookie' or 'session'
     */
    public $csrfProtection = 'cookie';

    /**
     * --------------------------------------------------------------------------
     * CSRF Token Randomization
     * --------------------------------------------------------------------------
     *
     * Randomize the CSRF Token for added security.
     *
     * @var bool
     */
    public $tokenRandomize = true;

    /**
     * --------------------------------------------------------------------------
     * CSRF Token Name
     * --------------------------------------------------------------------------
     *
     * Token name for Cross Site Request Forgery protection.
     *
     * @var string
     */
    public $tokenName = 'csrf_test_name';

    /**
     * --------------------------------------------------------------------------
     * CSRF Header Name
     * --------------------------------------------------------------------------
     *
     * Header name for Cross Site Request Forgery protection.
     *
     * @var string
     */
    public $headerName = 'X-CSRF-TOKEN';

    /**
     * --------------------------------------------------------------------------
     * CSRF Cookie Name
     * --------------------------------------------------------------------------
     *
     * Cookie name for Cross Site Request Forgery protection.
     *
     * @var string
     */
    public $cookieName = 'csrf_cookie_name';

    /**
     * --------------------------------------------------------------------------
     * CSRF Expires
     * --------------------------------------------------------------------------
     *
     * Expiration time for Cross Site Request Forgery protection cookie.
     *
     * Defaults to two hours (in seconds).
     *
     * @var int
     */
    public $expires = 7200;

    /**
     * --------------------------------------------------------------------------
     * CSRF Regenerate
     * --------------------------------------------------------------------------
     *
     * Regenerate CSRF Token on every submission.
     *
     * @var bool
     */
    public $regenerate = true;

    /**
     * --------------------------------------------------------------------------
     * CSRF Redirect
     * --------------------------------------------------------------------------
     *
     * Redirect to previous page with error on failure.
     *
     * @var bool
     */
    public $redirect = true;

    /**
     * --------------------------------------------------------------------------
     * CSRF SameSite
     * --------------------------------------------------------------------------
     *
     * Setting for CSRF SameSite cookie token.
     *
     * Allowed values are: None - Lax - Strict - ''.
     *
     * Defaults to `Lax` as recommended in this link:
     *
     * @see https://portswigger.net/web-security/csrf/samesite-cookies
     *
     * @var string
     *
     * @deprecated `Config\Cookie` $samesite property is used.
     */
    public $samesite = 'Lax';
}
Tanzeem
  • 29
  • 8

2 Answers2

1

OP statement 1

codeigniter4 code to add employee redirects to itself on submit...

Explanation 1

This behavior is expected when you set the $redirect Security property to true.

Redirection on Failure

Since v4.3.0, when a request fails the CSRF validation check, it will throw a SecurityException by default,

If you want to make it redirect to the previous page, change the following config parameter value in app/Config/Security.php:

public bool $redirect = true;

OP statement 2

But when regenerate is false, code submits to the controller and data is processed as required. How can I solve the issue with regenerate set to true?

Explanation 2

It fails because when the $regenerate Security property is set to true, the CSRF Token is regenerated on every POST, PUT, DELETE, and PATCH submission.

Token Regeneration

Tokens may be either regenerated on every submission (default) or kept the same throughout the life of the CSRF cookie. The default regeneration of tokens provides stricter security, but may result in usability concerns as other tokens become invalid (back/forward navigation, multiple tabs/windows, asynchronous actions, etc). You may alter this behavior by editing the following config parameter value in app/Config/Security.php:

public $regenerate = true;

Solution

With that out of the way, this means you will have to update the next submitted CSRF Token on your client (AJAX) on every submission. To manage that, you may send the latest CSRF Token through a Response Header.

  1. STEP 1: Configure your Security settings in your .env file which resides at the root of your project.

    security.csrfProtection = 'session'
    security.tokenRandomize = true
    security.regenerate = true
    security.redirect = true
    
  2. STEP 2: Set an HTML DOM <meta /> element to always hold the latest generated CSRF Token. This may be preferably set in your main HTML template.

<?php echo csrf_meta("csrf-field") ?>
  1. STEP 3: Set up a Filter to manage the need for sending the CSRF Token through a Response Header.

    • app/Config/Filters.php
    <?php
    
    namespace Config;
    
    use CodeIgniter\Filters\CSRF;
    use App\Filters\CsrfToken;
    
    // ...
    
    class Filters extends BaseConfig
    {
        public array $aliases = [
            'csrf' => CSRF::class,
            // ...
            'csrfToken' => CsrfToken::class,
        ];
    
        public array $globals = [
            'before' => [
                // ...
                'csrf',
                // ...
            ],
            'after' => [
                // ...
                'csrfToken',
            ],
        ];
    
        // ...
    }
    
    • app/Filters/CsrfToken.php
    <?php
    
    namespace App\Filters;
    
    use CodeIgniter\Filters\FilterInterface;
    use CodeIgniter\HTTP\RequestInterface;
    use CodeIgniter\HTTP\ResponseInterface;
    
    class CsrfToken implements FilterInterface
    {
        public function before(RequestInterface $request, $arguments = null)
        {
        }
    
        public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
        {
            $method           = strtoupper($request->getMethod());
            $methodsProtected = ["POST", "PUT", "DELETE", "PATCH"];
    
            if (in_array($method, $methodsProtected, true)) {
                $response->setHeader(csrf_header(), csrf_hash());
            }
    
        }
    }
    
  2. STEP 4: On your front-end, set up global jQuery AJAX events to automatically handle the sending and updating of the CSRF Token for all CSRF-protected HTTP methods.

    $(document).on("ajaxSend", function (event, jqXHR, ajaxOptions) {
    
       if ((ajaxOptions.method?.toLowerCase() === "post")) {
           jqXHR.setRequestHeader($("#csrf-field").attr("name"), $("#csrf-field").attr("content"));
       }
    
    });
    
    $(document).on("ajaxComplete", function (event, jqXHR, ajaxOptions) {
    
        const csrfToken = jqXHR.getResponseHeader($("#csrf-field").attr("name"));
    
        if ((ajaxOptions.method?.toLowerCase() === "post") && csrfToken) {
            $("#csrf-field").attr("content", csrfToken);
        }
    
    });
    

Conclusion: With the above setup, you no longer have to manually send a CRSF Token in your AJAX POST request body or pollute your Controller method's response data. The latest Token will automatically be sent on your behalf from STEP 4.

steven7mwesigwa
  • 5,701
  • 3
  • 20
  • 34
  • 1
    Good Stuff... This is why I asked for the OP to turn off redirect to see if an actual error pops up. Which it did :) – DeanE10 Jul 05 '23 at 17:08
  • I get 403 error on ajax action with message 'The action you requested is not allowed.' – Tanzeem Jul 11 '23 at 05:56
  • Also i found that ajaxOptions.method is undefined – Tanzeem Jul 11 '23 at 06:02
  • I replaced `ajaxOptions.method` with `if (ajaxOptions.type && ajaxOptions.type.toLowerCase() === "post")` and ajax send works, but in ajaxcomplete, csrfToken is null – Tanzeem Jul 11 '23 at 06:27
  • @Tanzeem What version of jQuery are you using? In your `$.ajax();` call, change `type:"POST",` to `method: "POST",`. The AJAX`type` option is deprecated. https://stackoverflow.com/a/43543968/7376590 – steven7mwesigwa Jul 11 '23 at 12:22
  • ok, but **csrfToken** is null – Tanzeem Jul 13 '23 at 06:20
0

Update the csrftoken in the ajax call in onload of Department/getDesignations.

inside Department/getDesignations I changed the data by added a csrftoken and designation data separately.

$data['designation']=$designations;
$data['token']=csrf_hash();

return $this->response->setJSON($data);

At the ajax response side i added the following also

$('input[name="csrf_test_name"]').val(response.token);
Tanzeem
  • 29
  • 8