# Security Groups

A Security Group is where Sentinel's request-handling behavior is configured. The server's behavior is driven by **Rules** assigned to a Security Group — they decide what happens to a given request, and every [API Key](/docs/sentinel/configure/api-keys/) inherits the rules of the Security Group it's assigned to.

## Rules

Rules let you:

- **Allow** or **deny** access based on specific conditions.
- **Set** internal state — for example, adjusting proof-of-work complexity or enabling [Adaptive Captcha](/docs/sentinel/features/adaptive-captcha/).
- Apply penalties, rate limits, and algorithm preferences.
- Customize the response message returned when a request is denied.

Rule conditions support wildcard matching, so a single rule can apply across a group of routes, hostnames, or values rather than needing one rule per exact match.

## Access levels

Every Security Group has an access level, which determines what its API Keys are allowed to do:

- **Public** — access to public-facing endpoints only. Use this level for keys embedded in the [ALTCHA widget](/docs/integration/widget/), since the key is visible client-side.
- **Restricted** — access to non-administrative API endpoints. Recommended for server-to-server integrations that need more than public access but shouldn't manage the account itself.
- **Full** — administrative access to all API endpoints, including data management. Reserve this for trusted backend systems only.

## Endpoints

Which endpoints a key can call is determined by its Security Group's access level:

**Public** (used by the ALTCHA widget):

- `/v1/challenge`
- `/v1/inspect`
- `/v1/verify`

**Restricted** (server-side integrations):

- `/v1/blobs/*`
- `/v1/classifier`
- `/v1/context/*`
- `/v1/eml`
- `/v1/ip`
- `/v1/language`
- `/v1/phishing`
- `/v1/similarity`
- `/v1/timezone`
- `/v1/user-agent`

Every other endpoint requires **Full** access.

Sentinel determines a request's origin from the `Origin` header, falling back to `Referer` if `Origin` isn't present — relevant if you write an `origin` condition (see [Examples](#examples) below).

## Autopilot

[Autopilot](/docs/sentinel/features/autopilot/) is configured per Security Group — leave it on to let Sentinel tune challenge difficulty and policy automatically, or set bounds it can't cross.

## Examples

Rules are evaluated as `{ action, conditions, ... }` objects. A few common patterns:

**Allow only internal traffic**

```json
{
"name": "Allow internal traffic",
"action": "allow",
"conditions": [{ "field": "ip", "operator": "=", "value": ["10.0.0.0/24"] }]
}
```

**Block high-risk countries**

```json
{
"name": "Deny high-risk countries",
"action": "deny",
"conditions": [{ "field": "country", "operator": "=", "value": ["list:high_risk"] }]
}
```

**Block bots and AI agents**

```json
{
"name": "Deny bots",
"action": "deny",
"conditions": [{ "field": "bot", "operator": "=", "value": ["true"] }]
}
```

**Allow only a specific origin** (`conditionsOperator` combines multiple conditions with `or`/`and`; note the wildcard subdomain match)

```json
{
"name": "Allow origins",
"action": "allow",
"conditionsOperator": "or",
"conditions": [
{ "field": "origin", "operator": "=", "value": ["https://example.com"] },
{ "field": "origin", "operator": "=", "value": ["https://*.example.com"] }
]
}
```

**Deny a user agent matched from request headers**

```json
{
"name": "Deny bot User-Agent",
"action": "deny",
"conditions": [{ "field": "headers", "operator": "=", "value": ["User-Agent: *bot/*"] }]
}
```

**Apply a penalty for Tor traffic** (`set` actions adjust internal state instead of allowing/denying outright)

```json
{
"name": "Set penalty to TOR users",
"action": "set",
"conditions": [{ "field": "tor", "operator": "=", "value": ["true"] }],
"set": [{ "field": "penalty", "value": "+5" }]
}
```

**Custom denial message**

```json
{
"name": "Allow internal traffic",
"action": "allow",
"conditions": [{ "field": "ip", "operator": "=", "value": ["10.0.0.0/24"] }],
"message": "IP denied."
}
```

## Wildcards

Since version `1.12.0`, condition values support wildcard matching:

- `*` matches any sequence of characters — e.g. `https://*.example.com` matches any subdomain.
- `?` makes the immediately preceding character optional — e.g. `colou?r` matches both `color` and `colour`.

## Schema

```ts
interface Rule {
action: 'allow' | 'deny' | 'set';
conditionsOperator?: 'and' | 'or';
conditions: Condition[];
message?: string;
name?: string;
set?: Set[];
}

interface Condition {
field: ConditionField;
operator: Operator;
value: string[];
}

interface Set {
field: SetField;
value: string;
}

type ConditionField =
| 'bot'
| 'country'
| 'headers'
| 'hosting'
| 'ip'
| 'language'
| 'malicious'
| 'mobile'
| 'origin'
| 'penalty'
| 'proxy'
| 'tor';

type Operator = '=' | '!=' | '>' | '<' | '<=' | '>=';

type SetField =
| 'algorithm'
| 'autopilot'
| 'classifyFields'
| 'codeChallenge'
| 'codeChallengeAlphabet'
| 'codeChallengeMaxLength'
| 'codeChallengeMinLength'
| 'complexity'
| 'cost'
| 'counter'
| 'disableClassificationRules'
| 'enableClassificationRules'
| 'expires'
| 'headerEntropyLimit'
| 'headerEntropyRiskFactor'
| 'highRiskCountries'
| 'his'
| 'hisBlockThreshold'
| 'hisHashTTL'
| 'key'
| 'maxComplexity'
| 'memoryCost'
| 'parallelism'
| 'penalty'
| 'powVersion'
| 'probabilistic'
| 'rateLimit'
| 'supportedAlgorithms'
| 'threats'
| 'widgetConfiguration';
```

`ConditionField` covers what a rule can match on (IP, country, bot/proxy/Tor/hosting-provider detection, headers, origin, language, an accumulated `penalty` score, and more). `SetField` covers what a `set` action can adjust — proof-of-work parameters (`complexity`, `cost`, `memoryCost`, `parallelism`, `algorithm`, `supportedAlgorithms`, `powVersion`, `probabilistic`), [HIS](/docs/sentinel/features/human-interaction-signature/) behavior (`his`, `hisBlockThreshold`, `hisHashTTL`), the code challenge (`codeChallenge*`), [Autopilot](/docs/sentinel/features/autopilot/), [rate limits](/docs/sentinel/features/rate-limiters/), classification behavior (`classifyFields`, `enableClassificationRules`, `disableClassificationRules`), and more.

## Related

- **[API Keys](/docs/sentinel/configure/api-keys/)** — keys are created under a Security Group and inherit its access level and rules.
- **[Forms](/docs/sentinel/configure/forms/)** — form submissions are also subject to their Security Group's rules.
- **[Get Started](/docs/sentinel/get-started/)** — creating your first Security Group.
