# How the Impersonation Cookie Flows Between Edge Middleware and Database-Backed Support Sessions in DeskcommCRM

> Discover how the impersonation cookie flows from Edge middleware to database helpers in DeskcommCRM. Learn about server-side creation, verification, and tenant isolation without altering Supabase sessions.

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

---

**The impersonation cookie flow uses a signed HttpOnly cookie that is created server-side, verified in the Edge middleware, and then read by database helpers to enforce tenant isolation without modifying the underlying Supabase session.**

DeskcommCRM implements a secure platform-admin impersonation feature that allows administrators to act on behalf of tenants without altering the original authentication state. This article breaks down the complete impersonation cookie flow between the Next.js Edge middleware and the database-backed support session, referencing the actual implementation in the `melgarafael/DeskcommCRM` repository.

## Cookie Creation and Signing on the Server

When a platform admin initiates impersonation via the `POST /api/v1/admin/tenants/[id]/impersonate` route, the server generates a cryptographically signed token containing the tenant ID, admin ID, and expiry timestamp. The `signImpersonateCookie` function in [`lib/impersonate/cookie.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/impersonate/cookie.ts) constructs this token using HMAC-SHA-256.

The payload format follows a strict structure: `<base64url(payload)>.<base64url(hmac)>`. The function retrieves the `IMPERSONATE_COOKIE_SECRET` from environment variables, validates it meets the minimum 32-character requirement, and produces a signature that prevents tampering.

```typescript
// lib/impersonate/cookie.ts – signImpersonateCookie
export function signImpersonateCookie(payload: ImpersonatePayload): string {
  const secret = env.IMPERSONATE_COOKIE_SECRET;
  if (!isSecretConfigured(secret)) {
    throw new Error("IMPERSONATE_COOKIE_SECRET missing or <32 chars");
  }
  const json = JSON.stringify(payload);
  const payloadB64 = b64urlEncode(Buffer.from(json, "utf8"));
  const sigB64 = b64urlEncode(hmac(payloadB64, secret));
  return `${payloadB64}.${sigB64}`;
}

```

The resulting token is stored in an HttpOnly, Secure, SameSite-Lax cookie named **`deskcomm-impersonate`**. This configuration prevents JavaScript access while ensuring the cookie only transmits over HTTPS and restricts cross-site request risks.

## Edge Middleware Verification

Every request matching `/app/*` passes through the Next.js Edge middleware defined in [`proxy.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/proxy.ts). This middleware extracts the `deskcomm-impersonate` cookie and validates it using the `verifyImpersonateCookieEdge` function from [`lib/impersonate/cookie-edge.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/impersonate/cookie-edge.ts), which implements Web Crypto API equivalents for the Edge runtime.

The verification process uses a manual `constantTimeEqual` comparison to prevent timing attacks, matching the security posture of the server-side implementation. If validation succeeds, the middleware injects impersonation metadata directly into the request context, making the override visible to downstream handlers without touching the Supabase session.

```typescript
// proxy.ts – part of the middleware chain
import { verifyImpersonateCookieEdge } from "@/lib/impersonate/cookie-edge";

export async function middleware(request) {
  const token = request.cookies.get(IMPERSONATE_COOKIE_NAME_EDGE);
  const result = await verifyImpersonateCookieEdge(token?.value ?? "", env.IMPERSONATE_COOKIE_SECRET);
  if (!result.valid) {
    // clear invalid cookie, continue as normal user
    request.cookies.delete(IMPERSONATE_COOKIE_NAME_EDGE);
  } else {
    // inject impersonation data for downstream handlers
    request.context.impersonating = true;
    request.context.tenantIdOverride = result.payload!.tenantId;
    request.context.platformAdminId = result.payload!.platformAdminId;
  }
  return NextResponse.next();
}

```

This Edge-runtime verification ensures that impersonation context is available immediately at the request boundary, allowing subsequent server components and API routes to access the override without re-parsing the cookie manually.

## Database Session Resolution with Support Context

Server-side code that requires tenant isolation or audit logging consumes the impersonation state through the `readSupportContext` helper in [`lib/impersonate/support.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/impersonate/support.ts). This function reads the cookie from request headers, runs the classic `verifyImpersonateCookie` verification, and returns a `SupportContext` object containing the `tenantId` and `platformAdminId`.

Database queries then use this context to enforce Row-Level Security (RLS) policies and override `organization_id` parameters. All audit logs generated during impersonation include `acting_as_platform_admin = true`, creating a complete forensic trail of administrative actions.

```typescript
// lib/impersonate/support.ts (simplified)
export async function readSupportContext(req: NextRequest): Promise<SupportContext | null> {
  const token = req.cookies.get(IMPERSONATE_COOKIE_NAME)?.value;
  if (!token) return null;
  const { valid, payload } = verifyImpersonateCookie(token);
  return valid ? { tenantId: payload!.tenantId, platformAdminId: payload!.platformAdminId } : null;
}

// Example usage in an API handler
export async function POST(req) {
  const support = await readSupportContext(req);
  if (support?.tenantId) {
    // override tenant for DB query
    const rows = await supabase.from("orders")
      .select("*")
      .eq("organization_id", support.tenantId);
    // audit as platform admin
    await auditLog({ action: "order.list", acting_as_platform_admin: true });
    return ok(rows);
  }
  // normal handling…
}

```

The support session remains additive—it supplements rather than replaces the existing Supabase authentication—ensuring that the platform admin retains their original identity while operating within the tenant's data scope.

## Security Implementation Details

The impersonation cookie flow implements several critical security controls to prevent privilege escalation and session hijacking:

- **Constant-time comparison**: Both server (`timingSafeEqual`) and Edge (`constantTimeEqual`) verifications use constant-time string comparison to prevent timing side-channel attacks.
- **Ephemeral tokens**: Expiry validation occurs after signature verification; correctly signed but expired cookies are rejected with an explicit `"expired"` reason.
- **Secrets management**: The `IMPERSONATE_COOKIE_SECRET` must be at least 32 characters; the application throws if this requirement is not met.
- **Cookie attributes**: HttpOnly prevents XSS theft, Secure enforces HTTPS transmission, and SameSite-Lax mitigates CSRF vectors.

## Summary

- **`signImpersonateCookie`** in [`lib/impersonate/cookie.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/impersonate/cookie.ts) creates HMAC-SHA-256 signed tokens combining a JSON payload with a base64url signature.
- The **`deskcomm-impersonate` cookie** uses HttpOnly, Secure, and SameSite-Lax attributes to protect the token in transit and at rest.
- **`verifyImpersonateCookieEdge`** in [`lib/impersonate/cookie-edge.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/impersonate/cookie-edge.ts) validates cookies in the Next.js Edge runtime using Web Crypto API primitives.
- **[`proxy.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/proxy.ts)** middleware injects impersonation context into `request.context`, making tenant overrides available to downstream handlers.
- **`readSupportContext`** in [`lib/impersonate/support.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/lib/impersonate/support.ts) provides server-side code with validated `SupportContext` for database queries and audit logging.
- The flow maintains **additive authorization**, leaving the underlying Supabase session untouched while enforcing tenant isolation through explicit context overrides.

## Frequently Asked Questions

### How does the Edge middleware pass impersonation data to API routes?

The Edge middleware in [`proxy.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/proxy.ts) attaches impersonation metadata directly to the `request.context` object, setting `impersonating` to `true`, `tenantIdOverride` to the payload's tenant ID, and `platformAdminId` to the admin identifier. Downstream API routes and server components read this context without needing to re-verify the cookie signature, though they may call `readSupportContext` to explicitly fetch the `SupportContext` object for database operations.

### What happens if the impersonation cookie expires while the user is active?

The verification logic in both `verifyImpersonateCookieEdge` and `verifyImpersonateCookie` checks expiry after validating the HMAC signature. An expired but correctly signed cookie returns a validation result with `valid: false` and reason `"expired"`, causing the middleware to clear the invalid cookie via `request.cookies.delete()`. The user continues under their original authentication context without the tenant override, preventing access to stale impersonation sessions.

### Why does DeskcommCRM use separate verification functions for Edge and Node.js runtimes?

The Edge runtime ([`cookie-edge.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/cookie-edge.ts)) uses the Web Crypto API (`crypto.subtle`), while the Node.js server implementation ([`cookie.ts`](https://github.com/melgarafael/DeskcommCRM/blob/main/cookie.ts)) uses Node's native `crypto` module and `Buffer` utilities for base64url encoding. Both implementations share identical payload formats and HMAC-SHA-256 logic, but the separation ensures compatibility with Next.js Edge Middleware constraints while maintaining performance in server-side Node.js environments.

### How does the system prevent platform admins from impersonating arbitrary tenants without authorization?

While the cookie mechanism itself only validates cryptographic integrity and expiry, authorization checks occur at the route level before `signImpersonateCookie` is ever called. The `POST /api/v1/admin/tenants/[id]/impersonate` endpoint validates that the requesting user has platform-admin privileges and that the target tenant ID exists in the admin's authorized scope before issuing the signed cookie. Additionally, RLS policies enforce that queries using the `tenantId` from `SupportContext` can only access rows where `organization_id` matches, preventing cross-tenant data leakage even if a cookie were somehow forged.