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

> Learn how TeslaMate secures sensitive data with a private PostgreSQL schema and Cloak encryption. Protect your API tokens from plain text exposure.

- Repository: [TeslaMate/teslamate](https://github.com/teslamate-org/teslamate)
- Tags: internals
- Published: 2026-06-16

---

**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`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/auth/tokens.ex), the Ecto schema explicitly declares the private prefix:

```elixir
@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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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:

```elixir
%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:

```elixir
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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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.