Middleware Authentication(JWT TOKEN) using hooks in CodeIgniter 3

Subin Babukuttan
4 min readJan 4, 2022

Pre requisites

  • Basic knowledge of CodeIgniter 3.
  • Basic knowledge of using hooks.
  • Basic knowledge of JWT.

We are going to implement a hook that validates the incoming request by verifying the JWT token that is passed in the headers.

The authentication hook executes before our request gets processed in the controller, kind of middleware for our incoming requests, once the authentication hook extracts the JWT token,it validates the token , if the token is not valid then appropriate json response is sent or else the requested controller is executed and the controller can access the decoded JWT token, we will shortly see how to pass the decoded token data from our authentication hook .

If you are new to codeigniter hooks , you can refer to this article (https://mark38igorsbk.medium.com/log-sql-queries-using-hooks-in-codeigniter-3-5b1fbf2401c0) I have published on medium, basics of using hooks, to log sql queries.

Let’s start with configuring hooks.

First we need to enable hooks in application\config\config.php, by setting

$config[‘enable_hooks’] = TRUE;

Then we need to define our hook whether it is a pre system or post system and its relevant definitions like which file to be looked up for execution ,which function to be called. All these we are going to define in application\config\hooks.php

$hook[‘post_controller_constructor’][] = array(‘class’ => ‘AuthenticateTokenHook’,‘function’ => ‘authenticate’,‘filename’ => ‘AuthenticateTokenHook.php’,‘filepath’ => ‘hooks’);

We are using a post_controller_constructor hook that executes when a request is made and the controller object has been instantiated but the controller requested method is not executed.

A post_controller_constructor hook ,defined by key name and an associative array,containing details like

  • The class key holds the name of a class that holds the code that needs to be executed.
  • The function key holds the name of the method that’ll be called upon the hook execution.
  • The filename key points to the file that defines the complete hook code.
  • The file path defines the directory path of the file declared under the filename key, and it’s relative to the application directory.

Now lets define our Authentication hook in application\hooks\AuthenticateTokenHook.php

<?phpclass AuthenticateTokenHook{  public function authenticate() {   // load ci instance   $ci = &get_instance();   if(isset($ci->is_token_verify_hookable)){    if($ci->is_token_verify_hookable){     $headers = $ci->input->request_headers();     if(!isset($headers['Authorization'])){       $ci->output->set_status_header(401);       $response = ['status' => 401, 'msg' => 'Unauthorized Access!'];      $ci->output->set_content_type('application/json');      $ci->output>set_output(json_encode($response,JSON_PRETTY_PRINT   |JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))->_display();      exit;     }    $token = $headers['Authorization'];    try {    $data = JWT::decode($token, $ci->config->item('jwt_key'));    if ($data === false) {      $ci->output->set_status_header(401);      $response = ['status' => 401, 'msg' => 'Unauthorized Access!@'];      $ci->output->set_content_type('application/json');
$ci->output>set_output(json_encode($response,JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))->_display();;
exit(); } else { $ci->token_data=$data; } } catch (Exception $e) { $response = ['status' => 401, 'msg' => 'Unauthorized Access!']; $ci->output->set_content_type('application/json');
$ci->output->set_output(json_encode($response,JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))->_display();;
exit; } }}}}

Lets understand the code.In the authenticate method we load our ci instance by $ci = &get_instance(); .We then check if the public variable is_token_verify_hookable in the controller is defined and set to TRUE. The public variable is used as a flag for the hook when to execute, our hook is called every time a request is passed to the controller , we may want our only specific controllers to be validated, for that purpose we are using a public variable to check.

If the variable is defined and set to TRUE then the authenticate method in the hook, extracts the token from headers.To get headers, we call the Input class method request_headers, $ci->input->request_headers() .Then we check if Authorization header is set or not , if not set then we output an error message using the Output class.

$ci->output->set_status_header(401);$response = [‘status’ => 401, ‘msg’ => ‘Unauthorized Access!’];$ci->output->set_content_type(‘application/json’);$ci->output->set_output(json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))->_display();exit;

If the Authorization header is set then we decode the JWT token and the decoded data is set in the ci instance object, as key token_data, so that we can use the decoded token data in the controller method.

$data = JWT::decode($token, $ci->config->item(‘jwt_key’));$ci->token_data=$data;

Now lets see our controller , how to set our public variable that is used to determine whether the controller needs to be authenticated by our hook and how we can use the data that’s been decoded by our hook.

<?phpdefined('BASEPATH') or exit('No direct script access allowed');require APPPATH . 'libraries/REST_Controller.php';
class User extends REST_Controller
{public $is_token_verify_hookable=TRUE;public function __construct(){
parent::__construct();
}
public function index_get(){$CI = &get_instance();if (!empty($CI->token_data->response->email)) { // Code to be executed when request made} else {$this->response(['msg' => 'Unauthorized request!', 'status' => 401], parent::HTTP_UNAUTHORIZED);}}}

public $is_token_verify_hookable=TRUE; is used as a flag to indicate the hook that the controllers method needs to be authenticated by executing the authenticate method defined in the hook.

In our controller method we can get the decoded data by hook , through loading the ci instance and getting the data through the key that is set in our hook authenticate method.

$CI = &get_instance();
var_dump($CI->token_data); // output our decoded data

That’s it , we have validated our controller method and decoded the JWT token data through hooks , that act as a middleware function. No need to write the code and maintain it in our controller if we want to validate our incoming request.

--

--