Friday, August 12, 2016

CodeIgniter: Build JWT authentication REST server

1. About CodeIgniter

CodeIgniter (CI) was created by EllisLab, and is now a project of the British Columbia Institute of Technology. its website is https://www.codeigniter.com.

It is a light weight PHP framework but very flexible and fast. You can read more info about CI and why it is good for you at here. Beside that, from my experience, I see CI is good for:
  • Building REST / RESTFull APIs
  • Building concept apps quickly
  • Creating beautiful and fast web apps with AngularJS or React easily
2. Installation

You can read its installation instruction on its website. Here I just high light some important notes:

2.1 Make friendly URL without index.php:
+ Apache: create .htaccess file in root folder with below content:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]


+ IIS: create web.config file in root folder with below content:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
 <system.webServer>
  <rewrite>
    <rules>
   <rule name="CI Rule" stopProcessing="true">
     <match url="^(.*)$" ignoreCase="false" />
     <conditions>
    <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
    <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
    <add input="{URL}" pattern="^/favicon.ico$" ignoreCase="false" negate="true" />
     </conditions>
     <action type="Rewrite" url="index.php/{R:1}" appendQueryString="true" />
   </rule>
    </rules>
  </rewrite>
 </system.webServer>
</configuration>


2.2 Set up multiple domains using HTTP or HTTPS
Read here: https://www.codeigniter.com/userguide3/installation/upgrade_303.html

2.3 Handling errors and show customized 404 page
Read here: https://www.codeigniter.com/userguide3/general/errors.html?highlight=#show_404

3. Folder structure, app flow and URI
CI has top folder structure as the following:
Almost your code will be under application folder, which has below folders:
The controller folder contains classes which can be invoked via URIs. To understand roles of folders under application, let see the flow of CI application:
Read here for more info about its app flow.

Its URI segment is based on this rule: website.com/class/function/var, in which:
  • class: a controller class, it is in a file of application/controllers folder
  • function: an invoked function in above class
  • var: a variable passed to above function, it is optional in the URI
Read more at: https://www.codeigniter.com/userguide3/general/urls.html

4. PHP JWT classes for CI
JSON Web Tokens is new industry standard for securely transmitting information between parties (e.g. client and server). It is becoming popular in authenticating, especially in mobile apps world.

To provide this feature for CI, we need to create some classes for implementing JWT standard. I don't want to reinvent the wheel, so let copy JWT classes from php-jwt (these classes are in src folder) into application/libraries folder of your CI.

5. REST server, users and authentication:
Next step, we need to build a REST server which will use php-jwt to authenticate and create access token after user logins successfully.

Luckily, there is a good REST server built by chriskacerguis. Please see the installation guide on its Github to install into your project. In the case you want to allow CORS, let open application/config/rest.php then set:

$config['check_cors'] = TRUE;
...
$config['allow_any_cors_domain'] = TRUE;

Now we have 2 libraries: php-jwt and REST server ready for using. Then we need a model to manage our users database. Let create your users table firstly:

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) NOT NULL,
  `password` varchar(20) NOT NULL,
  `email` varchar(50) NOT NULL,
  PRIMARY KEY (`id`,`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `users`(`id`,`username`,`password`,`email`) VALUES (1,'gonto','gonto','gonto@me.com');

Create Users_model in application/models (remember config your DB in application\config\database.php)

class Users_model extends CI_Model {
    public function __construct() {
        $this->load->database();
    }

    public function login($username, $password) {
        $this->db->select('*');
  $this->db->from('users');
  $this->db->where('username', $username);
  $query = $this->db->get();
        if ($query->num_rows() == 1) {
            $result = $query->result();
            return $result[0]->id;
        }
        return false;
    }
}


Make an API for checking user login (User.php) in application/controllers/api:

require_once APPPATH . '/libraries/REST_Controller.php';
require_once APPPATH . '/libraries/JWT.php';

use \Firebase\JWT\JWT;
class User extends REST_Controller {
    public function __construct() {
        parent::__construct();
        $this->load->model('Users_model');
    }

    public function login_post() {
        $username = $this->post('username');
        $password = $this->post('password');
        $invalidLogin = ['invalid' => $username];
        if(!$username || !$password) $this->response($invalidLogin, REST_Controller::HTTP_NOT_FOUND);
        $id = $this->Users_model->login($username,$password);
        if($id) {
            $token['id'] = $id;
            $token['username'] = $username;
            $date = new DateTime();
            $token['iat'] = $date->getTimestamp();
            $token['exp'] = $date->getTimestamp() + 60*60*5;
            $output['id_token'] = JWT::encode($token, "my Secret key!");
            $this->set_response($output, REST_Controller::HTTP_OK);
        }
        else {
            $this->set_response($invalidLogin, REST_Controller::HTTP_NOT_FOUND);
        }
    }
}


Yeah! We can login and get the token now!!!. Let check it on Postman tool:

That's all for today!

In next article, I'll present an Ionic 2 app which uses this REST server for authenticating with JWT.

Happy coding!




Subscribe to RSS Feed Follow me on Twitter!