How Authentication and Password Hashing Are Configured in Frigate

Frigate configures authentication using JWT-based sessions with PBKDF2-SHA256 password hashing (600,000 iterations by default), role-based access control, and declarative settings in AuthConfig.

Frigate is an open-source Network Video Recorder (NVR) that protects its web interface and API with native authentication mechanisms. Understanding how authentication and password hashing are configured in Frigate helps administrators secure video streams and user credentials effectively. The implementation is distributed across configuration models, API utilities, and database layers within the blakeblackshear/frigate repository.

AuthConfig Declarative Settings

All authentication behavior is governed by the AuthConfig class defined in [frigate/config/auth.py](https://github.com/blakeblackshear/frigate/blob/dev/frigate/config/auth.py#L10-L68). This Pydantic model validates settings at startup and exposes the following key fields:

  • enabled – Globally toggles authentication on or off.
  • hash_iterations – Configurable work factor for PBKDF2 (default 600000, aligning with OWASP recommendations).
  • roles – Dictionary mapping role names (e.g., admin, viewer) to lists of authorized cameras; an empty list grants access to all cameras.
  • session_length – JWT token lifetime in seconds (default 86400).
  • refresh_time – Window before expiry to refresh tokens (default 1800).
  • cookie_secure – Sets the Secure flag on JWT cookies; must be True when serving over TLS.
  • cookie_name – Configurable name for the session cookie (default frigate_token).

These values are sourced from your main config.yml and are immutable until the next restart.

PBKDF2-SHA256 Password Hashing

Password hashing and verification are implemented in [frigate/api/auth.py](https://github.com/blakeblackshear/frigate/blob/dev/frigate/api/auth.py#L64-L84) using Python’s standard library. Frigate uses PBKDF2-HMAC-SHA256 with a configurable iteration count and a random 16-byte salt.

Hash Generation

The hash_password function generates strings in the format pbkdf2_sha256$<iterations>$<salt>$<base64_hash>:

def hash_password(password: str, salt=None, iterations=600000):
    if salt is None:
        salt = secrets.token_hex(16)  # 16-byte random salt

    pw_hash = hashlib.pbkdf2_hmac(
        "sha256",
        password.encode("utf-8"),
        salt.encode("utf-8"),
        iterations
    )
    b64_hash = base64.b64encode(pw_hash).decode("ascii").strip()
    return f"{PASSWORD_HASH_ALGORITHM}${iterations}${salt}${b64_hash}"
  • PASSWORD_HASH_ALGORITHM is the constant pbkdf2_sha256.
  • iterations defaults to 600000 but is overridden by AuthConfig.hash_iterations when creating users.
  • salt is generated via secrets.token_hex(16) to ensure cryptographic randomness.

Hash Verification

The verify_password function prevents timing attacks by using secrets.compare_digest and validates the stored hash structure before computation:

def verify_password(password, password_hash):
    if (password_hash or "").count("$") != 3:
        return False
    algorithm, iterations, salt, b64_hash = password_hash.split("$", 3)
    iterations = int(iterations)
    assert algorithm == PASSWORD_HASH_ALGORITHM
    compare_hash = hash_password(password, salt, iterations)
    return secrets.compare_digest(password_hash, compare_hash)

This ensures constant-time comparison and rejects malformed hashes immediately.

JWT Session and Secret Management

Frigate issues JSON Web Tokens (JWT) upon successful login. The signing secret is retrieved by get_jwt_secret() in [frigate/api/auth.py](https://github.com/blakeblackshear/frigate/blob/dev/frigate/api/auth.py#L30-L61) using the following precedence:

  1. FRIGATE_JWT_SECRET environment variable.
  2. Docker secrets (mounted files).
  3. Home Assistant add-on context.
  4. A persistent file named .jwt_secret in the configuration directory (auto-generated on first run).

The create_encoded_jwt function generates tokens that are stored in HTTP-only cookies. The cookie name and security attributes are controlled by AuthConfig.cookie_name and AuthConfig.cookie_secure.

Role-Based Access Control

Frigate enforces coarse-grained authorization through the require_role dependency. Roles are resolved from the remote-role header (or proxy-mapped headers) and compared against the mappings defined in AuthConfig.roles.

The resolve_role helper translates proxy-provided claims into Frigate role definitions. Endpoints declare required roles via FastAPI dependencies; if the user’s role is absent from the required list, the request is rejected with a 403 error.

User Model and Lifecycle

Persistent user data is defined in [frigate/models.py](https://github.com/blakeblackshear/frigate/blob/dev/frigate/models.py#L44-L51) by the User SQLAlchemy model:

class User(Model):
    username = CharField(unique=True)
    role = CharField()
    password_hash = CharField()

When the application starts, [frigate/app.py](https://github.com/blakeblackshear/frigate/blob/dev/frigate/app.py#L520-L560) checks for the existence of an admin user or the reset_admin_password flag. If a new user is created or the admin password is reset, the backend invokes hash_password with iterations=self.config.auth.hash_iterations and commits the resulting string to the password_hash column.

Summary

  • Configuration: AuthConfig in frigate/config/auth.py centralizes hash iterations, session timing, and cookie settings.
  • Hashing: PBKDF2-SHA256 with 600,000 default iterations produces hashes in algorithm$iterations$salt$base64_hash format.
  • Security: Constant-time verification via secrets.compare_digest mitigates timing attacks.
  • Sessions: JWT tokens are signed with secrets from environment variables or filesystem storage and transmitted via configurable cookies.
  • Storage: User credentials reside in the User model (frigate/models.py), populated during startup logic in frigate/app.py.

Frequently Asked Questions

What hashing algorithm does Frigate use for passwords?

Frigate uses PBKDF2-HMAC-SHA256 with a default of 600,000 iterations, which aligns with current OWASP guidelines. The iteration count is configurable via the hash_iterations field in AuthConfig (frigate/config/auth.py).

How does Frigate store and retrieve the JWT signing secret?

Frigate attempts to load the JWT secret from the FRIGATE_JWT_SECRET environment variable first. If undefined, it checks Docker secrets, Home Assistant add-on contexts, or generates a random secret and persists it to a .jwt_secret file in the configuration directory (implemented in frigate/api/auth.py).

Can I enforce secure cookies and customize session timeouts?

Yes. Set cookie_secure: True in your config.yml to enforce the Secure flag on cookies (required for HTTPS deployments). Adjust session_length (default 86400 seconds) and refresh_time (default 1800 seconds) within AuthConfig to control token lifetimes.

Where are user passwords stored in the database?

User credentials are stored in the User table defined in frigate/models.py, specifically within the password_hash column. This column stores the complete PBKDF2 string including algorithm, iterations, salt, and hash, which is generated during user creation in frigate/app.py.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →