cgit — Authentication

Overview

cgit supports cookie-based authentication through the auth-filter mechanism. The authentication system intercepts requests before page rendering and delegates all credential validation to an external filter (exec or Lua script).

Source file: cgit.c (authentication hooks), filter.c (filter execution).

Architecture

Authentication is entirely filter-driven. cgit itself stores no credentials, sessions, or user databases. The auth filter is responsible for:

  1. Rendering login forms
  2. Validating credentials
  3. Setting/reading session cookies
  4. Determining authorization per-repository

Configuration

auth-filter=lua:/path/to/auth.lua
# or
auth-filter=exec:/path/to/auth.sh

The auth filter type is AUTH_FILTER (constant 4) and receives 12 arguments.

Authentication Flow

Request Processing in cgit.c

Authentication is checked in process_request() after URL parsing and command dispatch:

/* In process_request() */
if (ctx.cfg.auth_filter) {
    /* Step 1: Check current authentication state */
    authenticate_cookie();

    /* Step 2: Handle POST login attempts */
    if (ctx.env.request_method &&
        !strcmp(ctx.env.request_method, "POST"))
        authenticate_post();

    /* Step 3: Run the auth filter to decide access */
    cmd->fn(&ctx);
}

authenticate_cookie()

Opens the auth filter to check the current session cookie:

static void authenticate_cookie(void)
{
    /* Open auth filter with current request context */
    cgit_open_filter(ctx.cfg.auth_filter,
        ctx.env.http_cookie,      /* current cookies */
        ctx.env.request_method,   /* GET/POST */
        ctx.env.query_string,     /* full query */
        ctx.env.http_referer,     /* referer header */
        ctx.env.path_info,        /* request path */
        ctx.env.http_host,        /* hostname */
        ctx.env.https ? "1" : "0", /* HTTPS flag */
        ctx.qry.repo,             /* repository name */
        ctx.qry.page,             /* page/command */
        ctx.env.http_accept,      /* accept header */
        "cookie"                  /* authentication phase */
    );
    /* Read filter's response to determine auth state */
    ctx.env.authenticated = /* filter exit code */;
    cgit_close_filter(ctx.cfg.auth_filter);
}

authenticate_post()

Handles login form submissions:

static void authenticate_post(void)
{
    /* Read POST body for credentials */
    /* Open auth filter with phase="post" */
    cgit_open_filter(ctx.cfg.auth_filter,
        /* ... same 11 args ... */
        "post"                    /* authentication phase */
    );
    /* Filter processes credentials, may set cookies */
    cgit_close_filter(ctx.cfg.auth_filter);
}

Authorization Check

After authentication, the auth filter is called again before rendering each page to determine if the authenticated user has access to the requested repository and page:

static int open_auth_filter(const char *repo, const char *page)
{
    cgit_open_filter(ctx.cfg.auth_filter,
        /* ... request context ... */
        "authorize"               /* authorization phase */
    );
    int authorized = cgit_close_filter(ctx.cfg.auth_filter);
    return authorized == 0;  /* 0 = authorized */
}

Auth Filter Arguments

The auth filter receives 12 arguments in total:

# Argument Description
1 filter_cmd The filter command itself
2 http_cookie Raw HTTP_COOKIE header value
3 request_method HTTP method (GET, POST)
4 query_string Raw query string
5 http_referer HTTP Referer header
6 path_info PATH_INFO from CGI
7 http_host Hostname
8 https "1" if HTTPS, "0" if HTTP
9 repo Repository URL
10 page Page/command name
11 http_accept HTTP Accept header
12 phase "cookie", "post", or "authorize"

Filter Phases

cookie Phase

Called on every request. The filter should:

  1. Read the session cookie from argument 2
  2. Validate the session
  3. Return exit code 0 if authenticated, non-zero otherwise

post Phase

Called when the request method is POST. The filter should:

  1. Read POST body from stdin
  2. Validate credentials
  3. If valid, output a Set-Cookie header
  4. Output a redirect response (302)

authorize Phase

Called after authentication to check per-repository access. The filter should:

  1. Check if the authenticated user can access the requested repo/page
  2. Return exit code 0 if authorized
  3. Return non-zero to deny access (cgit will show an error page)

Filter Return Codes

Exit Code Meaning
0 Success (authenticated/authorized)
Non-zero Failure (unauthenticated/unauthorized)

Environment Variables

The auth filter also has access to standard CGI environment variables:

struct cgit_environment {
    const char *cgit_config;       /* $CGIT_CONFIG */
    const char *http_host;         /* $HTTP_HOST */
    const char *https;             /* $HTTPS */
    const char *no_http;           /* $NO_HTTP */
    const char *http_cookie;       /* $HTTP_COOKIE */
    const char *request_method;    /* $REQUEST_METHOD */
    const char *query_string;      /* $QUERY_STRING */
    const char *http_referer;      /* $HTTP_REFERER */
    const char *path_info;         /* $PATH_INFO */
    const char *script_name;       /* $SCRIPT_NAME */
    const char *server_name;       /* $SERVER_NAME */
    const char *server_port;       /* $SERVER_PORT */
    const char *http_accept;       /* $HTTP_ACCEPT */
    int authenticated;             /* set by auth filter */
};

Shipped Auth Filter

cgit ships a Lua-based hierarchical authentication filter:

filters/simple-hierarchical-auth.lua

This filter implements path-based access control using a simple user database and repository permission map.

Features:

  • Cookie-based session management
  • Per-repository access control
  • Hierarchical path matching
  • Password hashing

Usage:

auth-filter=lua:/usr/lib/cgit/filters/simple-hierarchical-auth.lua

Cache Interaction

Authentication affects cache keys. The cache key includes the authentication state and cookie:

static const char *cache_key(void)
{
    return fmt("%s?%s?%s?%s?%s",
        ctx.qry.raw,
        ctx.env.http_host,
        ctx.env.https ? "1" : "0",
        ctx.env.authenticated ? "1" : "0",
        ctx.env.http_cookie ? ctx.env.http_cookie : "");
}

This ensures that:

  • Authenticated and unauthenticated users get separate cache entries
  • Different authenticated users (different cookies) get separate entries
  • The cache never leaks restricted content to unauthorized users

Security Considerations

  1. HTTPS: Always use HTTPS when authentication is enabled to protect cookies and credentials in transit
  2. Cookie flags: Auth filter scripts should set Secure, HttpOnly, and SameSite cookie flags
  3. Session expiry: Implement session timeouts in the auth filter
  4. Password storage: Never store passwords in plain text; use bcrypt or similar hashing
  5. CSRF protection: The auth filter should implement CSRF tokens for POST login forms
  6. Cache poisoning: The cache key includes auth state, but ensure the auth filter is deterministic for the same cookie

Disabling Authentication

By default, no auth filter is configured and all repositories are publicly accessible. To restrict access, set up the auth filter and optionally combine with strict-export for file-based visibility control.

Example: Custom Auth Filter (Shell)

#!/bin/bash
# Simple auth filter skeleton
PHASE="${12}"

case "$PHASE" in
    cookie)
        COOKIE="$2"
        if validate_session "$COOKIE"; then
            exit 0   # authenticated
        fi
        exit 1       # not authenticated
        ;;
    post)
        read -r POST_BODY
        # Parse username/password from POST_BODY
        # Validate credentials
        # Set cookie header
        echo "Status: 302 Found"
        echo "Set-Cookie: session=TOKEN; HttpOnly; Secure"
        echo "Location: $6"
        echo
        exit 0
        ;;
    authorize)
        REPO="$9"
        # Check if current user can access $REPO
        exit 0  # authorized
        ;;
esac

Was this handbook page helpful?

This page is part of the Project Tick Handbook, which is licensed under the Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license. View full license details.
Last updated: April 18, 2026