# How DeskcommCRM Handles Plaintext WAHA Bearer Tokens: Security, Storage, and Implementation

> Discover how DeskcommCRM secures plaintext WAHA bearer tokens by storing them in memory for runtime use only, never on disk or logs. Learn about implementation.

- Repository: [Rafael Melgaço/DeskcommCRM](https://github.com/melgarafael/DeskcommCRM)
- Tags: security
- Published: 2026-09-12

---

**DeskcommCRM handles WAHA bearer tokens as plaintext environment variables, keeping them only in memory during runtime while injecting them into the `X-Api-Key` header for all API requests, never persisting them to disk or logs.**

The open-source **DeskcommCRM** repository integrates with **WAHA** (a self-hosted WhatsApp engine) using a straightforward plaintext authentication approach. Understanding how plaintext bearer tokens are handled and stored for WAHA integration is critical for operators deploying this CRM system securely, as the implementation prioritizes operational simplicity while enforcing strict runtime security boundaries.

## Environment Variable Configuration

DeskcommCRM loads the WAHA bearer token exclusively through environment variables. In [`lib/env.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/env.ts) (approximately line 141), the system declares `WAHA_API_KEY` as a required environment variable using the `required()` validator:

```typescript
// lib/env.ts (line ~141)
WAHA_API_KEY: required("WAHA_API_KEY"),

```

The repository includes a placeholder value in `.env.example` to remind operators to configure the token before starting the container:

```bash

# .env.example

WAHA_API_KEY=dev_plaintext_change_me

```

If the variable is missing at startup, the `getWahaClient()` factory function returns `null`, triggering UI components to render a "Docker is not up" banner rather than crashing the application.

## In-Memory Token Storage

The token resides **only in memory** inside `WahaClient` instances and is never persisted to a database or written to disk. The `WahaClient` class in [`lib/waha/client.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/waha/client.ts) receives the plaintext key through its constructor:

```typescript
// lib/waha/client.ts (constructor)
constructor(
  private readonly baseUrl: string,
  private readonly apiKey: string,
  opts: WahaClientOpts = {},
) { … }

```

This design ensures that sensitive credentials exist solely as runtime variables within the Node.js process, leaving no residual token data on the filesystem if the container restarts.

## HTTP Header Transmission

All WAHA REST API calls transmit the token via the **`X-Api-Key`** header. The `WahaClient` class injects the plaintext key into every request headers object:

```typescript
// lib/waha/client.ts (lines ~204, 212, 246…)
headers: { "X-Api-Key": this.apiKey }

```

When creating messages or managing sessions, the client automatically attaches this header. For example, sending a text message through WAHA works as follows:

```typescript
import { WahaClient } from "@/lib/waha/client";

const waha = new WahaClient(
  process.env.WAHA_API_BASE_URL!,   // base URL of the WAHA container
  process.env.WAHA_API_KEY!          // plaintext API key from .env
);

await waha.sendText({
  to: phoneNumber,
  text: "Olá! Seu pedido está pronto.",
});

```

## Validation and Error Handling

The integration implements defensive checks to prevent operations against unconfigured WAHA endpoints. Channel adapters such as [`lib/channels/transporte.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/channels/transporte.ts) and worker processes verify client availability before executing WhatsApp operations:

```typescript
const client = getWahaClient(); // returns null if WAHA_API_KEY or BASE_URL missing
if (!client) {
  // UI: show banner "Docker is not up – configure WAHA_API_KEY"
}

```

This pattern ensures that missing configuration results in graceful degradation rather than runtime exceptions or authentication failures against the WAHA engine.

## Security Measures and Logging

DeskcommCRM enforces a strict security policy preventing token exposure in logs. The logger configuration in [`lib/logger.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/logger.ts) explicitly includes the rule: *"Never log secrets, raw tokens…"*. Consequently, the plaintext `WAHA_API_KEY` is never written to log files, stdout, or error traces even when debugging is enabled.

Additionally, the codebase performs presence checks for both `WAHA_API_KEY` and `WAHA_API_BASE_URL` before client instantiation, emitting clear error messages when either value is absent.

## Summary

- **Environment-only configuration**: The `WAHA_API_KEY` variable is declared as required in [`lib/env.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/env.ts) and loaded from the host environment.
- **Memory-only storage**: Tokens exist only within `WahaClient` instances and are never persisted to databases or filesystems.
- **Header-based transmission**: All requests include the plaintext token in the `X-Api-Key` header as implemented in [`lib/waha/client.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/waha/client.ts).
- **Graceful degradation**: Missing configuration causes `getWahaClient()` to return `null`, displaying user-friendly UI banners instead of crashing.
- **Log sanitization**: The logger configuration in [`lib/logger.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/logger.ts) explicitly prohibits logging raw tokens, preventing accidental credential leaks.

## Frequently Asked Questions

### Where is the WAHA_API_KEY stored in DeskcommCRM?

The `WAHA_API_KEY` is stored only as an environment variable and exists solely in memory during runtime. According to the [`lib/env.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/env.ts) validation schema and the `WahaClient` constructor in [`lib/waha/client.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/waha/client.ts), the token is never written to disk, databases, or configuration files beyond the initial `.env` injection.

### What happens if WAHA_API_KEY is missing at startup?

If `WAHA_API_KEY` is undefined, the `getWahaClient()` function returns `null`, causing UI components to render a "Docker is not up" banner. This validation occurs across channel adapters like [`lib/channels/transporte.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/channels/transporte.ts) and background workers to prevent authentication failures against the WAHA engine.

### How does DeskcommCRM prevent WAHA tokens from leaking in logs?

The project’s logger implementation in [`lib/logger.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/logger.ts) enforces a strict policy: *"Never log secrets, raw tokens…"*. This rule ensures that even during verbose debugging or error stack traces, the plaintext bearer token remains excluded from log outputs.

### Is the WAHA token encrypted at rest in DeskcommCRM?

No, the token is not encrypted at rest because DeskcommCRM does not persist the token at all. The plaintext value lives only in memory within active `WahaClient` instances. The system relies on container-level security and environment variable management rather than application-layer encryption for this integration.