# How to Configure CIDR Whitelisting for API Access Control in OpenWA

> Learn to configure CIDR whitelisting for API access control in OpenWA. Secure your API by restricting access to specific IP addresses and networks using the allowedIps array.

- Repository: [Yudhi Armyndharis/OpenWA](https://github.com/rmyndharis/OpenWA)
- Tags: how-to-guide
- Published: 2026-05-21

---

**OpenWA implements CIDR whitelisting through the `allowedIps` array on API key entities, validating client IPs via the `isIpAllowed` and `ipInCidr` methods in `AuthService` to restrict HTTP API access to specific networks or exact addresses.**

OpenWA (rmyndharis/OpenWA) secures its HTTP API using scoped API keys that support network-level access restrictions. Understanding how to configure CIDR whitelisting for API access control in OpenWA allows you to limit key usage to specific datacenters, VPN ranges, or individual client machines.

## Understanding the Whitelist Data Model

The CIDR whitelist configuration resides on the `ApiKey` entity and passes through Data Transfer Objects (DTOs) during creation and updates.

### Storage in the API Key Entity

The whitelist persists in [`src/modules/auth/entities/api-key.entity.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/auth/entities/api-key.entity.ts) as a nullable text array:

```typescript
@Column({ type: 'text', nullable: true, array: true })
allowedIps: string[];

```

### DTO Validation

The `CreateApiKeyDto` and `UpdateApiKeyDto` in [`src/modules/auth/dto/api-key.dto.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/auth/dto/api-key.dto.ts) expose the field for API input:

```typescript
allowedIps?: string[];

```

## IP Validation Logic in AuthService

The core validation occurs in [`src/modules/auth/auth.service.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/auth/auth.service.ts). When `AuthService.validateApiKey` processes a request, it extracts the client IP and delegates to the IP-whitelist guard.

### The isIpAllowed Method

Located at lines 206-221, `isIpAllowed` iterates over the `allowedIps` array:

- If an entry contains `/`, it treats the entry as a CIDR range and delegates to `ipInCidr`
- Otherwise, it performs an exact string match against the client IP

### The ipInCidr Implementation

The `ipInCidr` method (lines 229-247) parses the CIDR string, constructs a 32-bit network mask, and compares the numeric representation of the client IP against the network range. It handles malformed CIDR values by logging a warning and returning false.

If no entries match, the service throws `UnauthorizedException('IP address not allowed')`.

## Configuring CIDR Ranges on API Keys

You can configure CIDR whitelisting when creating or updating API keys via REST endpoints or programmatically through the NestJS service layer.

### Creating a Key via REST API

Send a POST request to `/api/auth/api-keys` with mixed exact IPs and CIDR blocks:

```http
POST /api/auth/api-keys
Content-Type: application/json

{
  "name": "Internal Service",
  "role": "OPERATOR",
  "allowedIps": ["10.0.0.0/24", "203.0.113.5"]
}

```

### Updating Keys Programmatically

Use the `AuthService` to append new ranges to existing keys:

```typescript
import { AuthService } from './auth.service';

await authService.update(keyId, {
  allowedIps: [
    ...existing.allowedIps,
    '172.16.0.0/16'
  ],
});

```

### Manual IP Verification

You can reuse the validation logic directly for custom checks:

```typescript
const clientIp = '10.0.0.42';
const whitelist = ['10.0.0.0/24'];

if (authService.isIpAllowed(clientIp, whitelist)) {
  console.log('IP allowed');
} else {
  console.log('IP rejected');
}

```

## Extending Whitelisting in Custom Guards

For advanced use cases such as checking `X-Forwarded-For` headers, inject `AuthService` into custom guards:

```typescript
@Injectable()
export class CustomIpGuard implements CanActivate {
  constructor(private readonly auth: AuthService) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const req = context.switchToHttp().getRequest();
    const ip = req.headers['x-forwarded-for']?.split(',')[0] ?? req.ip;
    const apiKey = req.apiKey;

    return apiKey.allowedIps
      ? this.auth.isIpAllowed(ip, apiKey.allowedIps)
      : true;
  }
}

```

## Summary

- Store whitelist entries in the `allowedIps` array on the `ApiKey` entity defined in [`src/modules/auth/entities/api-key.entity.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/auth/entities/api-key.entity.ts)
- Use `AuthService.isIpAllowed` and `ipInCidr` in [`src/modules/auth/auth.service.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/auth/auth.service.ts) to validate IPv4 addresses against CIDR ranges or exact matches
- Configure CIDR whitelisting via the REST API by posting string arrays containing formats like `10.0.0.0/24` to the `/api/auth/api-keys` endpoint
- Handle malformed CIDR gracefully through warning logs without crashing the validation chain
- Note that IPv6 is not supported by the built-in logic; the documentation in [`docs/04-security-design.md`](https://github.com/rmyndharis/OpenWA/blob/main/docs/04-security-design.md) suggests using [`ipaddr.js`](https://github.com/rmyndharis/OpenWA/blob/main/ipaddr.js) for IPv6 networks

## Frequently Asked Questions

### Does OpenWA support IPv6 CIDR notation?

No, the built-in `ipInCidr` method in [`src/modules/auth/auth.service.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/auth/auth.service.ts) only handles 32-bit IPv4 masks. According to [`docs/04-security-design.md`](https://github.com/rmyndharis/OpenWA/blob/main/docs/04-security-design.md), you must integrate a library like [`ipaddr.js`](https://github.com/rmyndharis/OpenWA/blob/main/ipaddr.js) if you need to validate IPv6 address ranges.

### What happens if I provide an invalid CIDR format?

The `ipInCidr` method catches parsing errors, logs a warning message, and returns false for that specific entry. The validation continues checking other entries in the `allowedIps` array, and only rejects the request with `UnauthorizedException('IP address not allowed')` if no valid matches are found.

### Can I mix exact IP addresses and CIDR ranges in the same API key?

Yes, the `isIpAllowed` method handles both formats simultaneously. Entries without a forward slash (`/`) are compared as exact strings, while entries containing `/` are processed as CIDR ranges, allowing you to whitelist both individual servers and entire subnets in one configuration.

### Where is the whitelist enforced during the request lifecycle?

The `AuthService.validateApiKey` method enforces the whitelist immediately after API key authentication. It extracts the client IP from the request and validates it against the key's `allowedIps` array before allowing access to protected endpoints.