Database Schema for Sensitive Data in TeslaMate: Private Schemas and Cloak Encryption

TeslaMate stores Tesla API tokens in a private PostgreSQL schema with AES-GCM encryption using the Cloak library, ensuring sensitive credentials are never persisted in plain text or exposed in application logs.

TeslaMate, the open-source Tesla data logger, handles sensitive authentication credentials through a carefully architected database design. Understanding the database schema for sensitive data in TeslaMate reveals how the application protects your Tesla API tokens using PostgreSQL private schemas and transparent encryption. This analysis examines the actual source code in the teslamate-org/teslamate repository to explain the security implementation.

Private Schema Architecture for Credential Isolation

TeslaMate isolates sensitive authentication data in a dedicated PostgreSQL schema rather than the default public schema. This architectural decision creates a security boundary that separates credential storage from operational vehicle data.

In lib/teslamate/auth/tokens.ex, the Ecto schema explicitly declares the private prefix:

@schema_prefix :private

schema "tokens" do
  field :refresh, Encrypted.Binary, redact: true
  field :access,  Encrypted.Binary, redact: true

  timestamps()
end

The @schema_prefix :private directive instructs Ecto to create and query the tokens table within the PostgreSQL private schema. This isolation prevents accidental exposure through broad queries against the public schema and supports granular access control at the database level.

The Tokens Table Schema Definition

Encrypted Field Types

The tokens table stores exactly two sensitive values: the Tesla API refresh token and access token. Both fields use Encrypted.Binary, a custom Ecto type provided by the Cloak library that handles transparent encryption and decryption.

Key characteristics of this schema:

  • Transparent encryption: Data is automatically encrypted before insertion and decrypted when fetched
  • AES-GCM algorithm: The Cloak vault configured in lib/teslamate/vault.ex uses AES-256-GCM authenticated encryption
  • Binary storage: Underlying PostgreSQL columns use the bytea type to store ciphertext

Redaction Protection

The redact: true option on both fields ensures that token values are omitted from all Ecto logging and inspection output. Even if debug logging is enabled, the actual token strings appear as **redacted** in application logs, preventing credential leakage through log files.

Cloak Vault Configuration

The encryption layer is centralized in lib/teslamate/vault.ex, which configures the Cloak vault for the application. The vault generates a cryptographically secure random key when the ENCRYPTION_KEY environment variable is not provided during initial setup.

For Docker deployments, the vault persists the generated key to a temporary file (and optionally an import folder) to survive container restarts. This design ensures that:

  1. Fresh installations without explicit configuration still receive encryption
  2. The encryption key remains consistent across application restarts
  3. Users can optionally specify their own ENCRYPTION_KEY for key rotation scenarios

Database Migration Strategy

The migration file priv/repo/migrations/20220123131732_encrypt_api_tokens.exs handles the transition from plain-text to encrypted storage. This migration implements a zero-downtime strategy for existing deployments:

  1. Creates new encrypted_refresh and encrypted_access columns as :binary (PostgreSQL bytea)
  2. Migrates existing plain-text token values to the encrypted representation using the Cloak vault
  3. Drops the original plain-text columns
  4. Renames the encrypted columns to refresh and access to maintain the public API

The migration also includes helper modules for key generation and vault configuration, ensuring that the encryption setup completes successfully even on fresh installations.

Working with Encrypted Tokens

Creating Token Records

When the Tesla authentication flow completes successfully, the application creates a token record like this:

%TeslaMate.Auth.Tokens{}
|> TeslaMate.Auth.Tokens.changeset(%{
  access:  access_token,   # plain-text, encrypted by Ecto/Cloak

  refresh: refresh_token   # plain-text, encrypted by Ecto/Cloak

})
|> Repo.insert!()

The plain-text values are automatically encrypted by the Encrypted.Binary type before the SQL INSERT executes, ensuring the database never stores unencrypted credentials.

Reading Token Data

When fetching tokens for API requests, the decryption happens transparently:

tokens = Repo.get_by(TeslaMate.Auth.Tokens, id: 1)

# tokens.access and tokens.refresh are plain strings,

# automatically decrypted by Cloak on load

The application code works with plain strings while the database layer handles cryptographic operations, maintaining clean separation between business logic and security implementation.

Summary

  • Private schema isolation: The tokens table resides in the PostgreSQL private schema, separate from vehicle telemetry data
  • AES-GCM encryption: TeslaMate uses the Cloak library with AES-256-GCM authenticated encryption for all token storage
  • Automatic redaction: The redact: true schema option prevents token values from appearing in application logs or debug output
  • Migration safety: The 20220123131732_encrypt_api_tokens.exs migration safely converts existing plain-text tokens to encrypted storage without data loss
  • Vault key management: The lib/teslamate/vault.ex configuration handles key generation, storage, and rotation support through environment variables

Frequently Asked Questions

Where are Tesla API tokens stored in TeslaMate?

Tesla API tokens are stored in the tokens table within the private PostgreSQL schema, defined in lib/teslamate/auth/tokens.ex. This table uses the @schema_prefix :private directive to ensure physical and logical separation from other application data, and all token values are encrypted using the Cloak library before persistence.

What encryption algorithm does TeslaMate use for sensitive data?

TeslaMate uses AES-256-GCM (Galois/Counter Mode) authenticated encryption provided by the Cloak library. The encryption keys are managed through the vault configuration in lib/teslamate/vault.ex, which supports both environment variable-based keys and automatically generated keys for Docker deployments.

How does TeslaMate prevent API tokens from appearing in logs?

The Ecto schema in lib/teslamate/auth/tokens.ex marks both token fields with redact: true. This Ecto feature ensures that whenever the struct is inspected or logged, the sensitive values display as **redacted** rather than the actual token strings, preventing accidental credential exposure through log files or error reports.

Can I rotate the encryption key for existing TeslaMate tokens?

Yes, you can rotate encryption keys by setting a new ENCRYPTION_KEY environment variable and running a re-encryption migration. The process involves configuring the new key in lib/teslamate/vault.ex, fetching all existing token records (which decrypts them with the old key), and re-inserting them to encrypt with the new key. Always back up your database before performing key rotation operations.

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 →