REST APIs are the backbone of modern web and mobile applications. When building APIs, ensuring security is essential to protect resources and manage authenticated access. One of the most widely used techniques is Token-Based Authentication using JSON Web Tokens (JWT).
In this complete tutorial, we’ll learn how to build secure REST APIs in CodeIgniter 4 with JWT Authentication manually and without relying on third-party packages to give you full control over your authentication workflow.
We’ll cover all these given points:
- API route setup
- User registration and login via API
- Token generation using JWT
- Validating tokens on protected routes
Let’s get started.
📌 Install JWT Library via Composer
First, we’ll install the firebase/php-jwt
package for token generation and verification.
Run this command:
composer require firebase/php-jwt
👉 Explanation: This command downloads and installs the official JWT library into your project’s vendor/
directory, making JWT encoding and decoding functions available for your controllers.
📌 Database Table for Users
We’ll need a users
table to store user credentials. Run this spark cli command to create a migration,
Create a Migration:
php spark make:migration CreateUsersTable
👉 Explanation: This command generates a new migration file inside app/Database/Migrations/
. We’ll use this file to define the structure of our users
table.
Migration Code:
public function up()
{
$this->forge->addField([
'id' => ['type' => 'INT', 'auto_increment' => true],
'username' => ['type' => 'VARCHAR', 'constraint' => '100'],
'email' => ['type' => 'VARCHAR', 'constraint' => '100', 'unique' => true],
'password' => ['type' => 'VARCHAR', 'constraint' => '255'],
'created_at' => ['type' => 'DATETIME', 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->createTable('users');
}
Run Migration:
php spark migrate
👉 Explanation: Applies all pending migrations in the app/Database/Migrations/
folder to your database. This creates a users
table based on your migration file.
📌 User Model
Create a model for interacting with the users
table.
Command:
php spark make:model UserModel
👉 Explanation: Generates a new model file inside app/Models/UserModel.php
which we’ll use for database operations like inserting and querying user records.
Model Code:
namespace App\Models;
use CodeIgniter\Model;
class UserModel extends Model
{
protected $table = 'users';
protected $primaryKey = 'id';
protected $allowedFields = ['username', 'email', 'password', 'created_at'];
}
📌 Create API Controller
Run this command to create a controller file,
php spark make:controller Api/Auth
👉 Explanation: This command creates a new controller file at app/Controllers/Api with name Auth.php.
We’ll define all our API routes here – user registration, login, and token-protected endpoints.
Load JWT Library in Controller:
use \Firebase\JWT\JWT;
use \Firebase\JWT\Key;
>> Controller Structure:
- register() → for API signup
- login() → for API login and token generation
- profile() → a protected route for authenticated users
>> API Registration Method
public function register()
{
$model = new \App\Models\UserModel();
$data = [
'username' => $this->request->getVar('username'),
'email' => $this->request->getVar('email'),
'password' => password_hash($this->request->getVar('password'), PASSWORD_DEFAULT),
];
$model->save($data);
return $this->response->setJSON(['status' => true, 'message' => 'User registered successfully']);
}
>> API Login & Token Generation
public function login()
{
$model = new \App\Models\UserModel();
$user = $model->where('email', $this->request->getVar('email'))->first();
if ($user && password_verify($this->request->getVar('password'), $user['password'])) {
$key = 'YOUR_SECRET_KEY';
$payload = [
'iss' => 'localhost',
'aud' => 'localhost',
'iat' => time(),
'exp' => time() + 3600,
'data' => [
'id' => $user['id'],
'username' => $user['username'],
'email' => $user['email']
]
];
$token = JWT::encode($payload, $key, 'HS256');
return $this->response->setJSON(['status' => true, 'token' => $token]);
}
return $this->response->setJSON(['status' => false, 'message' => 'Invalid credentials']);
}
👉 Explanation: Generates a JWT token on successful login containing user data and expiry info.
>> Protected API Route (Profile Route)
public function profile()
{
$key = 'YOUR_SECRET_KEY';
$authHeader = $this->request->getServer('HTTP_AUTHORIZATION');
if ($authHeader) {
$token = explode(' ', $authHeader)[1];
try {
$decoded = JWT::decode($token, new Key($key, 'HS256'));
return $this->response->setJSON(['status' => true, 'user' => $decoded->data]);
} catch (\Exception $e) {
return $this->response->setJSON(['status' => false, 'message' => 'Invalid Token']);
}
}
return $this->response->setJSON(['status' => false, 'message' => 'Token not provided']);
}
👉 Explanation:
- Checks for token in the Authorization header.
- Validates the token.
- Returns user data if valid, else error.
📌 Define API Routes
Open app/Config/Routes.php
and add:
$routes->group('api', function($routes){
$routes->post('register', 'Api/Auth::register');
$routes->post('login', 'Api/Auth::login');
$routes->get('profile', 'Api/Auth::profile');
});
👉 Explanation: Groups API endpoints under /api
prefix for a cleaner and organized API structure. Each route maps directly to the corresponding method in Api/Auth
controller.
📌 Conclusion
We’ve now built a secure, token-based authentication system for REST APIs in CodeIgniter 4 using JWT. This covers registration, login with token generation, protected routes with token validation, and clean API structure – all without relying on third-party packages for auth.
Our app is now ready to communicate safely with mobile apps, frontends, or other services via REST APIs!