Sessions & Security

HTTP itself is stateless — every request arrives with no memory of the one before it. Anything that feels "persistent" while a visitor browses your site — being logged in, a shopping cart, a "Saved successfully" message that appears after a redirect — is being carried across requests deliberately, usually via sessions. This page covers CodeIgniter's Session library, then moves into three of the most important security habits for any CI4 application: CSRF protection, XSS-aware output, and basic rate limiting for sensitive endpoints.

1. The Session Library

Like the other core services covered on the previous page, Sessions are reached either through the Config\Services factory or, far more commonly, through the short global session() helper function, which is available everywhere without any extra loading step:

$session = session(); // equivalent to \Config\Services::session()

Under the hood, CodeIgniter stores a session identifier in a cookie on the visitor's browser and keeps the actual data server-side (by default in a file under writable/session, though database or Redis-backed session handlers are also supported for production and multi-server setups).

2. Setting, Getting, and Removing Session Data

The Session library's API is deliberately small and easy to remember — three methods cover nearly everything:

// Store a value for this visitor, available on every future request
session()->set('user_id', 42);

// Read it back on any later request
$userId = session()->get('user_id');

// Remove it entirely (e.g. on logout)
session()->remove('user_id');

You can also store several values at once by passing an associative array to set(), and check whether a key exists before reading it with has():

session()->set([
    'user_id' => 42,
    'username' => 'sonu',
]);

if (session()->has('user_id')) {
    // visitor is logged in
}

3. Flashdata: One-Time Messages

A very common pattern is redirecting after a form submits successfully, then showing a "Saved!" message on the page the user lands on. Storing that message as regular session data would leave it sitting around forever until manually removed. Flashdata solves this exactly: it's session data that automatically deletes itself after being read on the very next request.

// In the controller, right before redirecting
session()->setFlashdata('success', 'Article saved successfully!');
return redirect()->to('/articles');

Then, in the view rendered by the page the visitor is redirected to:

<?php if (session()->getFlashdata('success')): ?>
  <div class="alert alert-success">
    <?= esc(session()->getFlashdata('success')) ?>
  </div>
<?php endif; ?>
Tip: Flashdata survives exactly one redirect. Load that page again by refreshing and the message is gone — which is exactly the behaviour you want for a one-off confirmation notice.

4. CSRF Protection

Cross-Site Request Forgery tricks a logged-in visitor's browser into submitting a request to your site from somewhere else, without the visitor's knowledge. CodeIgniter 4 defends against this by requiring every state-changing request to carry a secret, per-session CSRF token that only your own pages know how to generate. CSRF protection is toggled on globally in app/Config/Filters.php:

// app/Config/Filters.php
public array $required = [
    'before' => ['forcehttps', 'csrf'],
    'after'  => [],
];

With the csrf filter active, CodeIgniter rejects any POST (or other unsafe-method) request that doesn't include a valid token. That means every single HTML form on your site that submits data must include the hidden token field, which the csrf_field() helper function generates for you:

<form method="post" action="/articles">
  <?= csrf_field() ?>
  <input type="text" name="title">
  <button type="submit">Save</button>
</form>
Note: Forget csrf_field() on even one form and every submission through it will fail with a 403 error once the filter is active. Get in the habit of adding it to every <form> the moment you write it, the same way you'd never forget a closing tag.

5. XSS Awareness: Escape on Output, Not Just Input

Cross-Site Scripting happens when unescaped user input containing HTML or JavaScript gets echoed back into a page and the browser executes it. CodeIgniter does offer some input-side filtering helpers, but the framework's own official recommendation — and the approach used throughout this entire track — is to filter on the way out, at the point where data is displayed, using the esc() function covered in depth on the Views page:

<h1><?= esc($article['title']) ?></h1>

The reasoning is simple: input filtering has to guess, at the moment data arrives, every context it might ever be displayed in later (plain HTML? inside an attribute? inside a <script> block?), and guessing wrong either breaks legitimate data or leaves a gap. Escaping at output time instead lets you choose the exact right escaping for the exact place the data is being printed, and it protects you even from data that entered the database through some other path entirely. Combined with validation (previous page) rejecting malformed input up front, and CSRF protection guarding state changes, output escaping closes the loop on the three most common web vulnerabilities.

6. Basic Rate Limiting for Sensitive Endpoints

Login forms, password-reset requests, and public API endpoints are common targets for brute-force and abuse attempts. CodeIgniter includes a lightweight Throttler service specifically for capping how often a given action can be performed, which you can drop into a controller or a filter:

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

// Allow at most 3 attempts per minute per visitor IP
if ($throttler->check($this->request->getIPAddress(), 3, 60) === false) {
    return $this->response->setStatusCode(429)->setBody('Too many attempts, try again later.');
}

This is only a first line of defense — it slows down and discourages casual abuse rather than replacing a full authentication or WAF strategy — but for a login page or a public form endpoint it's a small amount of code for a meaningful reduction in risk.

Next steps: With sessions and the core security habits in place, move on to Building a REST API to see CodeIgniter used to serve JSON instead of HTML views.