← Back to DevBytes

Authentication and Authorization in CherryPy Applications

Introduction to Authentication and Authorization in CherryPy

Authentication and authorization are two of the most critical security layers in any web application. In CherryPy, a minimalist yet powerful Python web framework, these concepts are implemented with remarkable flexibility and control. This tutorial will guide you through building secure authentication and authorization systems from scratch, explain why they matter, and show you production-ready patterns.

What Is Authentication and Authorization?

Authentication answers the question: "Who are you?" It is the process of verifying the identity of a user, typically through credentials such as a username and password, API keys, or OAuth tokens. Without authentication, your application cannot distinguish between different users or, worse, between a legitimate user and an attacker.

Authorization answers the question: "What are you allowed to do?" Once a user is authenticated, authorization determines which resources, actions, or data that user can access. This is where roles, permissions, and policies come into play. A regular user might view their profile, while an admin can delete accounts. Authorization ensures that even authenticated users cannot exceed their privileges.

Why It Matters

Setting Up a Basic CherryPy Application

Before diving into security, let's create a minimal CherryPy application to serve as our foundation. Install CherryPy if you haven't already:

pip install cherrypy

Create a file named app.py with the following code:

import cherrypy

class Root:
    @cherrypy.expose
    def index(self):
        return "<h1>Welcome to CherryPy</h1><a href='/login'>Login</a>"

    @cherrypy.expose
    def login(self):
        return "<h1>Login Page</h1>"

if __name__ == '__main__':
    cherrypy.quickstart(Root())

Run the application:

python app.py

Visit http://localhost:8080 in your browser. You should see the welcome message. This bare-bones app has no security whatsoever — anyone can access any page. Let's change that.

Implementing Authentication in CherryPy

CherryPy does not enforce any particular authentication method. Instead, it provides hooks, tools, and session management that let you build exactly what you need. The most common approach is session-based authentication using a login form.

Enabling Sessions

Sessions allow you to persist user state across requests. Enable the session tool globally or per-application:

import cherrypy

class Root:
    @cherrypy.expose
    def index(self):
        if 'username' in cherrypy.session:
            return f"<h1>Hello, {cherrypy.session['username']}!</h1>"
        return "<h1>Please log in</h1><a href='/login'>Login</a>"

if __name__ == '__main__':
    conf = {
        '/': {
            'tools.sessions.on': True,
            'tools.sessions.timeout': 60  # minutes
        }
    }
    cherrypy.quickstart(Root(), '/', conf)

Now cherrypy.session behaves like a dictionary that persists across requests. The timeout value controls how long a session remains valid without activity.

Login with Credential Verification

Let's implement a real login flow. We'll use a simple in-memory user store for demonstration — in production, you would query a database.

import cherrypy
import hashlib

# Simulated user database — never store plain-text passwords in production!
USERS = {
    'alice': {
        'password_hash': hashlib.sha256('password123'.encode()).hexdigest(),
        'role': 'user'
    },
    'bob': {
        'password_hash': hashlib.sha256('admin456'.encode()).hexdigest(),
        'role': 'admin'
    }
}

def verify_password(username, password):
    if username not in USERS:
        return False
    expected_hash = USERS[username]['password_hash']
    actual_hash = hashlib.sha256(password.encode()).hexdigest()
    return actual_hash == expected_hash

class Root:
    @cherrypy.expose
    def index(self):
        if 'username' in cherrypy.session:
            username = cherrypy.session['username']
            role = USERS.get(username, {}).get('role', 'unknown')
            return f"<h1>Welcome, {username} (role: {role})</h1>" \
                   f"<a href='/logout'>Logout</a>"
        return "<h1>Please log in</h1><a href='/login'>Login</a>"

    @cherrypy.expose
    def login(self, username=None, password=None):
        if cherrypy.request.method == 'POST':
            if username and password and verify_password(username, password):
                cherrypy.session['username'] = username
                raise cherrypy.HTTPRedirect('/')
            else:
                return "<h1>Invalid credentials</h1><a href='/login'>Try again</a>"
        # Show login form
        return """
        <form method='post'>
            Username: <input type='text' name='username'><br>
            Password: <input type='password' name='password'><br>
            <input type='submit' value='Log in'>
        </form>
        """

    @cherrypy.expose
    def logout(self):
        cherrypy.session.clear()
        raise cherrypy.HTTPRedirect('/')

if __name__ == '__main__':
    conf = {
        '/': {
            'tools.sessions.on': True,
            'tools.sessions.timeout': 60
        }
    }
    cherrypy.quickstart(Root(), '/', conf)

Test this application. Log in as alice with password password123 or bob with admin456. The session persists, and the index page shows your username and role. Clicking "Logout" clears the session.

Using CherryPy's Built-in check_a

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles