Skip to content

Environments

Every issued key carries an environment of either live (default) or test. The guard rejects requests whose key environment doesn't match the route's requirement with api_key_environment_mismatch (HTTP 403).

Marking a route live-only

typescript
import { Post, UseGuards } from '@nestjs/common';
import { ApiKeysGuard, RequireEnvironment, RequireScope } from '@nestarc/api-keys';

@UseGuards(ApiKeysGuard)
export class PublishController {
  @Post()
  @RequireEnvironment('live')
  @RequireScope('publish', 'write')
  publish() {
    /* ... */
  }
}

Routes without @RequireEnvironment accept both environments.

Issuing a test key

typescript
await apiKeys.create({
  tenantId: 'tenant_123',
  name: 'Sandbox',
  environment: 'test',
  scopes: [{ resource: 'publish', level: 'write' }],
});

The issued key begins with your namespace + _test_, making it visually distinguishable in logs and customer dashboards.

Why bother

Isolating environments at the key level (not just at the application config level) means:

  • A leaked test key cannot reach live endpoints, even if the same service serves both.
  • Customer-facing sandbox traffic can be billed or rate-limited separately without branching at the business logic.
  • You can ship "try it out" docs and CLIs that generate test keys on the fly without risk of live-data calls.

A test key hitting a @RequireEnvironment('live') route, or a live key hitting a @RequireEnvironment('test') route, always fails closed with api_key_environment_mismatch.

Released under the MIT License.