Skip to main content
The Home Assistant authentication system provides a flexible, secure framework for managing user access, credentials, and permissions. The auth system is built around several key components that work together to provide comprehensive access control.

Core Architecture

The authentication system is centered around the AuthManager class, which coordinates all authentication operations.

AuthManager

Location: homeassistant/auth/__init__.py:174 The AuthManager is the central hub for all authentication operations:
class AuthManager:
    """Manage the authentication for Home Assistant."""
    
    def __init__(self, hass, store, providers, mfa_modules):
        self.hass = hass
        self._store = store  # AuthStore instance
        self._providers = providers  # Dict of auth providers
        self._mfa_modules = mfa_modules  # Dict of MFA modules
        self.login_flow = AuthManagerFlowManager(hass, self)
Key Responsibilities:
  • Managing authentication providers and MFA modules
  • Creating and managing users, groups, and credentials
  • Handling refresh tokens and access tokens
  • Validating authentication attempts
  • Coordinating login flows

Authentication Models

Location: homeassistant/auth/models.py

User Model

The User class represents a Home Assistant user:
@attr.s(slots=False)
class User:
    name: str | None
    perm_lookup: PermissionLookup
    id: str  # UUID hex string
    is_owner: bool = False
    is_active: bool = False
    system_generated: bool = False
    local_only: bool = False
    groups: list[Group] = []  # User's group memberships
    credentials: list[Credentials] = []  # Authentication credentials
    refresh_tokens: dict[str, RefreshToken] = {}  # Active tokens
Key Properties:
  • permissions: Returns permission object based on user’s owner status or group policies
  • is_admin: Cached property indicating if user is owner or member of admin group
  • invalidate_cache(): Must be called when permission-affecting attributes change

Credentials Model

Location: homeassistant/auth/models.py:135
@attr.s(slots=True)
class Credentials:
    auth_provider_type: str  # e.g., "homeassistant", "trusted_networks"
    auth_provider_id: str | None
    data: dict  # Provider-specific credential data
    id: str  # UUID hex string
    is_new: bool = True  # Whether credentials are newly created
Credentials link users to authentication providers and store provider-specific data.

RefreshToken Model

Location: homeassistant/auth/models.py:106
@attr.s(slots=True)
class RefreshToken:
    user: User
    client_id: str | None
    access_token_expiration: timedelta
    client_name: str | None = None
    client_icon: str | None = None
    token_type: str = TOKEN_TYPE_NORMAL  # normal, system, long_lived_access_token
    id: str
    created_at: datetime
    token: str  # 64-byte hex token
    jwt_key: str  # 64-byte hex JWT signing key
    last_used_at: datetime | None = None
    last_used_ip: str | None = None
    expire_at: float | None = None  # Unix timestamp
    credential: Credentials | None = None
    version: str | None = __version__
Token Types:
  • TOKEN_TYPE_NORMAL: Standard user tokens (expire after 90 days)
  • TOKEN_TYPE_SYSTEM: System-generated user tokens (no expiration)
  • TOKEN_TYPE_LONG_LIVED_ACCESS_TOKEN: Long-lived access tokens for integrations

Group Model

Location: homeassistant/auth/models.py:42
@attr.s(slots=True)
class Group:
    name: str | None
    policy: PolicyType  # Permission policy
    id: str
    system_generated: bool = False
Built-in Groups:
  • system-admin (GROUP_ID_ADMIN): Full access administrators
  • system-users (GROUP_ID_USER): Standard users
  • system-read-only (GROUP_ID_READ_ONLY): Read-only access

Token Management

The auth system uses a two-token approach:

Refresh Tokens

  • Long-lived tokens stored securely
  • Used to generate short-lived access tokens
  • Can be revoked independently
  • Track usage metadata (IP, timestamp)
Creating a Refresh Token: Location: homeassistant/auth/__init__.py:453
await auth_manager.async_create_refresh_token(
    user=user,
    client_id="http://localhost:8123",
    client_name="My App",
    access_token_expiration=ACCESS_TOKEN_EXPIRATION
)

Access Tokens

  • Short-lived JWT tokens (default: 30 minutes)
  • Generated from refresh tokens
  • Contain minimal claims: issuer (refresh token ID), issued at, expiration
  • Signed with refresh token’s JWT key
Creating an Access Token: Location: homeassistant/auth/__init__.py:599
access_token = auth_manager.async_create_access_token(
    refresh_token=refresh_token,
    remote_ip="192.168.1.100"
)
Validating an Access Token: Location: homeassistant/auth/__init__.py:654
refresh_token = auth_manager.async_validate_access_token(access_token)
if refresh_token and refresh_token.user.is_active:
    # Token is valid, proceed with request
    user = refresh_token.user

Authentication Storage

Location: homeassistant/auth/auth_store.py The AuthStore class provides persistent storage for all authentication data:
  • Users and their credentials
  • Groups and their policies
  • Refresh tokens
  • Permission lookup data
Key Features:
  • Lazy loading (loads on first access)
  • Atomic writes with configurable save delays
  • Migration support for data format changes
  • In-memory caching for performance

Login Flow

Location: homeassistant/auth/__init__.py:100 Authentication uses Home Assistant’s data entry flow framework:
  1. Flow Creation: Auth provider creates a LoginFlow instance
  2. Step Execution: Flow steps collect and validate credentials
  3. MFA Verification: Optional multi-factor authentication
  4. Credential Resolution: Flow result converted to Credentials object
  5. User Resolution: Credentials linked to or used to create a User
Flow Manager:
class AuthManagerFlowManager(FlowManager):
    async def async_create_flow(self, handler_key, *, context, data):
        auth_provider = self.auth_manager.get_auth_provider(*handler_key)
        return await auth_provider.async_login_flow(context)
    
    async def async_finish_flow(self, flow, result):
        # Convert flow result to credentials
        # Handle MFA if needed
        # Return final result with credentials

Key Constants

Location: homeassistant/auth/const.py
ACCESS_TOKEN_EXPIRATION = timedelta(minutes=30)
MFA_SESSION_EXPIRATION = timedelta(minutes=5)
REFRESH_TOKEN_EXPIRATION = timedelta(days=90).total_seconds()

GROUP_ID_ADMIN = "system-admin"
GROUP_ID_USER = "system-users"
GROUP_ID_READ_ONLY = "system-read-only"

Events

The auth system fires events on the event bus:
  • user_added: Fired when a new user is created
  • user_updated: Fired when a user is modified
  • user_removed: Fired when a user is deleted
Event data includes user_id field.

User Types

Regular Users

  • Created through normal authentication flows
  • Can have multiple credentials from different providers
  • Subject to group-based permissions
  • Can be owners (first user) or members of groups

System Users

Location: homeassistant/auth/__init__.py:262
  • Created programmatically via async_create_system_user()
  • Used by integrations for automated access
  • Cannot have MFA enabled
  • Must use system-type refresh tokens
  • Typically have specific, limited permissions

Initialization

Location: homeassistant/auth/__init__.py:50
auth_manager = await auth_manager_from_config(
    hass=hass,
    provider_configs=[
        {"type": "homeassistant"},
        {"type": "trusted_networks", "trusted_networks": ["192.168.1.0/24"]}
    ],
    module_configs=[
        {"type": "totp", "name": "Authenticator app"}
    ]
)
The auth manager is typically initialized during Home Assistant startup from the configuration file.

Security Features

  • Password Hashing: bcrypt with 12 rounds for password storage
  • Timing-Safe Comparison: Constant-time operations prevent timing attacks
  • Token Expiration: Automatic cleanup of expired refresh tokens
  • Revocation Callbacks: Components can be notified when tokens are revoked
  • IP Tracking: Last used IP address tracked for security monitoring
  • Version Tracking: Token version matches Home Assistant version

Best Practices

  1. Always validate tokens before processing requests
  2. Use refresh tokens for long-lived access, not access tokens
  3. Implement revocation callbacks for cleanup when tokens are revoked
  4. Check user.is_active before allowing operations
  5. Use system users for integration-to-integration communication
  6. Respect local_only flag for users restricted to local network
  7. Call invalidate_cache() when modifying user permissions

Build docs developers (and LLMs) love