Skip to content

Webhook signature verification requires instantiating a client with an apiKey #726

Description

@wv-odola

Summary

webhooks.verifySignature (and unwrap / parse) never read anything off this._client except
the default webhookSecret, but they are only reachable through a Lithic instance, and the
constructor throws when no apiKey is resolvable. A service that only receives and verifies
webhooks, and never calls the API, has to pass a placeholder key to get at them.

Reproduction

import Lithic from 'lithic';

// throws, even though nothing below needs credentials
const client = new Lithic();

client.webhooks.verifySignature(rawBody, headers, webhookSecret);
LithicError: The LITHIC_API_KEY environment variable is missing or empty; either provide it, or
instantiate the Lithic client with an apiKey option, like new Lithic({ apiKey: 'My Lithic API Key' }).

The check sits in the constructor (src/client.ts), so it fires before any request is made.

Current workaround:

const client = new Lithic({ apiKey: 'unused-webhook-verification-only' });

Why this is worth changing

A webhook receiver is often deployed as its own service with no API credentials provisioned for it
at all. Forcing a placeholder puts a string that reads like an API key into source, which is
misleading to anyone auditing the code and easy to mistake for a leaked credential.

Webhooks is also not exported from the package root, so there is no way to reach the verification
logic without going through a client.

Possible fixes

  1. Make apiKey optional and move the error to where auth is actually needed (authHeaders /
    first request) instead of the constructor. Smallest change, no new public surface.
  2. Export a standalone verifier that takes the secret directly, e.g.
    import { verifyWebhookSignature } from 'lithic'.
  3. Accept an explicit webhook-only construction, e.g. new Lithic({ webhookSecret, apiKey: null }).

Option 1 matches what the code already does today.

Environment

  • lithic 0.145.0
  • Node 22, TypeScript

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions