# How TeslaMate Handles User Sessions and Authentication in Its Web Interface

> Learn how TeslaMate secures your data with signed HTTP cookie sessions and encrypted OAuth tokens for robust web interface authentication and API access.

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

---

**TeslaMate uses a signed HTTP cookie session managed by Phoenix LiveView combined with encrypted OAuth tokens stored in the database to maintain secure user access and authenticate API calls to Tesla.**

TeslaMate's web interface is built on the Phoenix framework and follows a conventional session-plus-token strategy to balance security with usability. The application separates transient browser session state from sensitive authentication credentials, ensuring that **user sessions and authentication** remain persistent across page loads while keeping OAuth tokens encrypted at rest. This architecture enables seamless interaction with the Tesla API without exposing tokens to the client-side browser.

## HTTP Session Configuration

The foundation of TeslaMate's session handling lies in [`lib/teslamate_web/endpoint.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate_web/endpoint.ex), where the application configures a signed cookie store for all browser connections. The `@session_options` module attribute defines a strict same-site cookie policy to prevent cross-site request forgery.

```elixir

# lib/teslamate_web/endpoint.ex

@session_options [
  store: :cookie,
  key: "_teslamate_key",
  signing_salt: "yt5O3CAQ",
  same_site: "Strict"
]

plug Plug.Session, @session_options

```

This configuration creates a signed cookie named `_teslamate_key` that persists the user's session ID and locale preferences. The `same_site: "Strict"` setting ensures the cookie is never sent in cross-origin requests, mitigating CSRF attacks.

## Router Pipeline and Session Loading

Every HTTP request passes through the `:browser` pipeline defined in [`lib/teslamate_web/router.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate_web/router.ex), which loads the session data and makes it available to LiveViews. The pipeline combines standard Phoenix plugs with custom locale handling.

```elixir

# lib/teslamate_web/router.ex

pipeline :browser do
  plug :accepts, ["html"]
  plug :fetch_session          # <-- loads the cookie into conn.session

  plug :fetch_live_flash
  plug Cldr.Plug.AcceptLanguage, cldr_backend: TeslaMateWeb.Cldr, no_match_log_level: :debug
  plug Cldr.Plug.PutLocale, apps: [:cldr, :gettext], from: [:query, :session, :accept_language], gettext: TeslaMateWeb.Gettext, cldr: TeslaMateWeb.Cldr
  plug TeslaMateWeb.Plugs.PutSession   # stores locale values in the session

  plug :protect_from_forgery
  plug :put_secure_browser_headers
  plug :fetch_settings                # puts global settings into conn.assigns and session

end

```

The `fetch_session` plug decodes the signed cookie, while `TeslaMateWeb.Plugs.PutSession` persists CLDR and Gettext locale selections back into the session for subsequent requests. The custom `fetch_settings` plug additionally loads global configuration from the database into both connection assigns and the session, ensuring settings remain available across LiveView reconnections.

## OAuth Token Storage and Encryption

Unlike the transient session cookie, Tesla OAuth tokens receive persistent encrypted storage in the database. The `TeslaMate.Auth` context in [`lib/teslamate/auth.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/auth.ex) handles all create, read, update, and delete operations for authentication tokens.

```elixir

# lib/teslamate/auth.ex

def save(%{token: access, refresh_token: refresh}) do
  attrs = %{access: access, refresh: refresh}

  maybe_created_or_updated =
    case get_tokens() do
      nil -> create_tokens(attrs)
      tokens -> update_tokens(tokens, attrs)
    end

  with {:ok, _tokens} <- maybe_created_or_updated, do: :ok
end

```

The actual token schema in [`lib/teslamate/auth/tokens.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/auth/tokens.ex) utilizes the **Vault** library to encrypt the `access` and `refresh` tokens at rest. This ensures that even with database access, an attacker cannot use the stored credentials without the encryption key.

## Sign-In LiveView Process

User authentication occurs through `TeslaMateWeb.SignInLive.Index`, a LiveView module that renders the sign-in form and handles the OAuth flow. On mount, the view initializes a changeset for token fields and checks for environment-based configuration.

```elixir

# lib/teslamate_web/live/signin_live/index.ex

def mount(_params, _session, socket) do
  assigns = %{
    api: get_api(socket),
    page_title: gettext("Sign in"),
    error: nil,
    task: nil,
    changeset: Auth.change_tokens(),
    token: System.get_env("TOKEN", ""),
    provider: System.get_env("TESLA_AUTH_HOST", "https://auth.tesla.com")
  }

  {:ok, assign(socket, assigns)}
end

```

When a user submits credentials, the `handle_event("sign_in")` function spawns a background `Task` that calls the Tesla API. Upon successful authentication, the returned token pair passes to `Auth.save/1`, which encrypts and persists them to the database. The user then redirects to the main car view while the browser retains the original session cookie, preserving locale and UI state.

## API Request Authentication

All outbound requests to Tesla's API include the stored access token via middleware. The `TeslaApi.Middleware.TokenAuth` module in [`lib/tesla_api/middleware/token_auth.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/tesla_api/middleware/token_auth.ex) intercepts every request and injects the bearer token into the authorization header.

```elixir

# lib/tesla_api/middleware/token_auth.ex

def call(%Tesla.Env{} = env, next, _opts) do
  env =
    case env.opts[:access_token] do
      nil -> env
      token -> Tesla.put_header(env, "Authorization", "Bearer " <> token)
    end

  Tesla.run(env, next)
end

```

This middleware retrieves the decrypted access token from the database through the API module, ensuring that no token data ever reaches the client-side JavaScript or browser storage.

## End-to-End Session Lifecycle

The complete session and authentication flow follows these steps:

1. **Initial Request**: The browser hits `TeslaMateWeb.Endpoint`, which creates the signed `_teslamate_key` cookie.
2. **Pipeline Processing**: `Plug.Session` loads the cookie into `conn.session`, and `PutSession` persists locale data.
3. **Authentication**: The user visits `/sign_in` and submits credentials through `SignInLive.Index`.
4. **Token Persistence**: On successful API validation, `Auth.save/1` encrypts and stores tokens via the `Tokens` schema.
5. **API Usage**: Subsequent background syncs use `TokenAuth` middleware to attach the bearer token to Tesla API requests.
6. **Session Continuity**: Page reloads or LiveView reconnections restore state from the signed cookie without requiring re-authentication.

## Summary

- **Signed cookies** handle browser session state via `Plug.Session` configured in [`endpoint.ex`](https://github.com/teslamate-org/teslamate/blob/main/endpoint.ex) with strict same-site policies.
- **Encrypted database storage** protects OAuth tokens using the Vault library in the `Tokens` schema, accessed through the `Auth` context.
- **Phoenix LiveView** manages the sign-in flow through `SignInLive.Index`, spawning background tasks for API calls to prevent UI blocking.
- **Middleware injection** automatically adds bearer tokens to outbound requests via `TeslaApi.Middleware.TokenAuth`, keeping credentials server-side only.
- **Locale persistence** survives page reloads through the custom `PutSession` plug, storing CLDR and Gettext settings in the same signed cookie.

## Frequently Asked Questions

### How does TeslaMate secure OAuth tokens from unauthorized access?

TeslaMate stores OAuth tokens in a PostgreSQL database using the Vault library for encryption at rest. The `TeslaMate.Auth.Tokens` schema encrypts both the access and refresh tokens before persistence, ensuring that database access alone does not compromise account credentials.

### What maintains the user session during page reloads or browser restarts?

A signed HTTP cookie named `_teslamate_key` maintains the session, configured in [`lib/teslamate_web/endpoint.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate_web/endpoint.ex) with `same_site: "Strict"` protection. This cookie persists the session ID and locale preferences, allowing LiveViews to restore state without requiring repeated authentication.

### Does the Tesla API token ever reach the user's browser?

No, the Tesla API access token never leaves the server. The `TeslaApi.Middleware.TokenAuth` module injects the bearer token into API requests on the backend only. The browser receives only the signed session cookie, which contains no OAuth credentials.

### How does the application handle the initial sign-in process?

The `TeslaMateWeb.SignInLive.Index` LiveView renders a form backed by `Auth.change_tokens/0`. Upon submission, it spawns a background Task to call the Tesla API, then persists the returned tokens using `Auth.save/1` before redirecting the user to the dashboard.