How to Send AJAX request with CSRF token in CodeIgniter 3
Cross-Site Request Forgery (CSRF) is a way to trick the server that a request sent to it is legitimate while it actually is an unauthorized attempt.
In CodeIgniter, CSRF protection is not enabled by default.
If it is been enabled then CodeIgniter generates a hash for each active user and this is used to verify the request.
Require to send the hash with the AJAX request otherwise, it gives an error – “The action you have requested is not allowed.”.
In this tutorial, I show how you can enable CSRF protection and regenerate hash for the next AJAX request and pass hash in AJAX request in the CodeIgniter project.
1. Table structure
In this example, I am using users
table and added some records –
CREATE TABLE `users` ( `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, `name` varchar(80) NOT NULL, `username` varchar(80) NOT NULL, `gender` varchar(10) NOT NULL, `email` varchar(80) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2. Configuration
Enable CSRF protection –
Open application/config/config.php
file and update the values of $config['csrf_protection']
, $config['csrf_token_name']
, and $config['csrf_regenerate']
like this –
$config['csrf_protection'] = TRUE; // Enable CSRF $config['csrf_token_name'] = 'csrf_hash_name'; // Token name (You can update it) $config['csrf_regenerate'] = TRUE; // Set TRUE to regenerate Hash
- Set
TRUE
the$config['csrf_protection']
, this will enable CSRF. - You can change the value of
$config['csrf_token_name']
default it is set to'csrf_test_name'
. I changed it to'csrf_has_name'
. This name is used in AJAX request to pass the hash. - Set
TRUE
the$config['csrf_regenerate']
if you want to regenerate CSRF hash after each AJAX request otherwise set itFALSE
.
Open application/config/database.php
and define the Database connection.
$db['default'] = array( 'dsn' => '', 'hostname' => 'localhost', 'username' => 'root', // Username 'password' => '', // Password 'database' => 'tutorial', // Database name 'dbdriver' => 'mysqli', 'dbprefix' => '', 'pconnect' => FALSE, 'db_debug' => (ENVIRONMENT !== 'production'), 'cache_on' => FALSE, 'cachedir' => '', 'char_set' => 'utf8', 'dbcollat' => 'utf8_general_ci', 'swap_pre' => '', 'encrypt' => FALSE, 'compress' => FALSE, 'stricton' => FALSE, 'failover' => array(), 'save_queries' => TRUE );
Default controller
Open application/config/routes.php
and edit default_controller
value to User
.
$route['default_controller'] = 'User';
Load Database
To access the MySQL database require loading database
library.
Open application/config/autoload.php
and add the database
in libraries array()
.
$autoload['libraries'] = array("database");
3. Model
Create a Main_model.php
file in the application/models/
directory.
Create getUserDetails()
method which takes a single parameter.
Check if $postData['username']
is set or not. If set then fetch a record from users
table where username=$postData['username']
.
Return the $response
Array.
Completed Code
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); class Main_model extends CI_Model { function getUserDetails($postData){ $response = array(); if(isset($postData['username']) ){ // Select record $this->db->select('*'); $this->db->where('username', $postData['username']); $q = $this->db->get('users'); $response = $q->result_array(); } return $response; } }
4. Controller
Create User.php
file in application/controllers/
directory.
Create 2 methods –
- index – Load
url
helper anduser_view
view. - userDetails – This method is used to handle the AJAX request and return a response.
Read POST values and assign in $postData
. Load Main_model
Model and call getUserDetails()
method where pass $postData
.
Assign return value in $data
and read the new CSRF hash by calling $this->security->get_csrf_hash()
for next AJAX request and assign in $data['token']
.
Return $data
Array in JSON format.
Completed Code
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class User extends CI_Controller { public function index(){ // load base_url $this->load->helper('url'); // load view $this->load->view('user_view'); } public function userDetails(){ // POST data $postData = $this->input->post(); // load model $this->load->model('Main_model'); // get data $data = $this->Main_model->getUserDetails($postData); // Read new token and assing in $data['token'] $data['token'] = $this->security->get_csrf_hash(); echo json_encode($data); } }
5. View
Create user_view.php
file in application/views/
directory.
Create a text element and store token name which is specified in application/config.php
file in name
attribute using <?= $this->security->get_csrf_token_name(); ?>
. Store CSRF hash in the element by calling <?= $this->security->get_csrf_hash(); ?>
.
Added some user names in the <select > <option>
. Used username in the <option >
value.
To display selected user details created <span >
elements.
Script –
Define change
event on #sel_user
selector.
Read name
attribute of .txt_csrfname
selector and assign in csrfName
variable. Assign .txt_csrfname
selector value in csrfHash
variable.
Assign selected option value in username
variable.
Send AJAX POST request to '<?=base_url()?>index.php/User/userDetails'
where pass {username:username,[csrfName]:csrfHash }
as data
.
Here, hash will pass like – [csrfName]: csrfHash
.
On successful callback read the token from response
and update the .txt_csrfname
selector value.
Loop on the response[0]
and update <span >
elements text.
Completed Code
<!doctype html> <html> <head> <title>How to Send AJAX request with CSRF token in CodeIgniter 3</title> </head> <body> <!-- CSRF token (Here, name is 'csrf_hash_name' which is specified in $config['csrf_token_name'] in cofig.php file ) --> <input type="text" class="txt_csrfname" name="<?= $this->security->get_csrf_token_name(); ?>" value="<?= $this->security->get_csrf_hash(); ?>"><br> Select Username : <select id='sel_user'> <option value='yssyogesh'>yssyogesh</option> <option value='sonarika'>sonarika</option> <option value='vishal'>vishal</option> <option value='sunil'>sunil</option> </select> <!-- User details --> <div > Username : <span id='suname'></span><br/> Name : <span id='sname'></span><br/> Email : <span id='semail'></span><br/> </div> <!-- Script --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script type='text/javascript'> // baseURL variable var baseURL= "<?= base_url();?>"; $(document).ready(function(){ $('#sel_user').change(function(){ // CSRF Hash var csrfName = $('.txt_csrfname').attr('name'); // Value specified in $config['csrf_token_name'] var csrfHash = $('.txt_csrfname').val(); // CSRF hash // Username var username = $(this).val(); // AJAX request $.ajax({ url:'<?=base_url()?>index.php/User/userDetails', method: 'post', data: {username: username,[csrfName]: csrfHash }, dataType: 'json', success: function(response){ // Update CSRF hash $('.txt_csrfname').val(response.token); // Empty the elements $('#suname,#sname,#semail').text(''); // Loop on response $(response[0]).each(function(key,value){ var uname = value.username; var name = value.name; var email = value.email; $('#suname').text(uname); $('#sname').text(name); $('#semail').text(email); }); } }); }); }); </script> </body> </html>
6. Demo
7. Conclusion
If you don’t want to regenerate hash for every AJAX then set FALSE
to $config['csrf_regenerate']
in config.php
file. In this case, the new hash will be generated according to the CSRF expiry time set.
You can view this tutorial to know how to send an AJAX request with CSRF token in CodeIgniter 4.