> For the complete documentation index, see [llms.txt](https://docs.digitalapi.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.digitalapi.ai/api-gateway/plugin-reference/plugins-authentication.md).

# Authentication plugins

Plugins in this category check who is calling the gateway before the request reaches the upstream. Attach exactly one authentication plugin to a route or an API to require credentials; the Helix developer portal lets your developers manage those credentials themselves. The catalogue ships 12 Authentication plugins.

{% hint style="info" %}
**In this category:** [`authz-casbin`](#authz-casbin), [`authz-casdoor`](#authz-casdoor), [`authz-keycloak`](#authz-keycloak), [`basic-auth`](#basic-auth), [`cas-auth`](#cas-auth), [`forward-auth`](#forward-auth), [`helix-auth`](#helix-auth), [`hmac-auth`](#hmac-auth), [`ldap-auth`](#ldap-auth), [`multi-auth`](#multi-auth), [`opa`](#opa), [`openid-connect`](#openid-connect)
{% endhint %}

### `authz-casbin`

The `authz-casbin` Plugin is an authorization Plugin based on [Casbin](https://casbin.org/). It supports powerful authorization scenarios based on various [access control models](https://casbin.org/docs/en/supported-models).

{% hint style="info" %}
**Priority** `2560` · **Category** Authentication
{% endhint %}

<details>

<summary>Configuration and details</summary>

| Name         | Type   | Required | Description                                                                            |
| ------------ | ------ | -------- | -------------------------------------------------------------------------------------- |
| model\_path  | string | True     | Path of the Casbin model configuration file.                                           |
| policy\_path | string | True     | Path of the Casbin policy file.                                                        |
| model        | string | True     | Casbin model configuration in text format.                                             |
| policy       | string | True     | Casbin policy in text format.                                                          |
| username     | string | True     | Header in the request that will be used in the request to pass the username (subject). |

**Sample configuration**

Inline model and policy defined directly in the plugin config, with the subject taken from the `username` header:

```json
{
  "authz-casbin": {
    "model": "[request_definition]\nr = sub, obj, act\n[policy_definition]\np = sub, obj, act\n[policy_effect]\ne = some(where (p.eft == allow))\n[matchers]\nm = r.sub == p.sub && r.obj == p.obj && r.act == p.act",
    "policy": "p, alice, /api/v1/*, GET\np, admin, /api/v1/*, POST",
    "username": "user"
  }
}
```

Model and policy loaded from files on the gateway instead of inline text:

```json
{
  "authz-casbin": {
    "model_path": "/helix/casbin/model.conf",
    "policy_path": "/helix/casbin/policy.csv",
    "username": "user"
  }
}
```

</details>

### `authz-casdoor`

The `authz-casdoor` Plugin can be used to add centralized authentication with [Casdoor](https://casdoor.org/).

{% hint style="info" %}
**Priority** `2559` · **Category** Authentication · **Required** `callback_url`, `endpoint_addr`, `client_id`, `client_secret`
{% endhint %}

<details>

<summary>Configuration and details</summary>

| Name           | Type   | Required | Description                                  |
| -------------- | ------ | -------- | -------------------------------------------- |
| endpoint\_addr | string | True     | URL of Casdoor.                              |
| client\_id     | string | True     | Client ID in Casdoor.                        |
| client\_secret | string | True     | Client secret in Casdoor.                    |
| callback\_url  | string | True     | Callback URL used to receive state and code. |

**Sample configuration**

Centralized authentication against a Casdoor instance:

```json
{
  "authz-casdoor": {
    "endpoint_addr": "https://casdoor.example.com",
    "client_id": "294b09fbc17f95daf2fe",
    "client_secret": "my-casdoor-client-secret",
    "callback_url": "https://api.example.com/callback"
  }
}
```

</details>

### `authz-keycloak`

The `authz-keycloak` Plugin can be used to add authentication with [Keycloak Identity Server](https://www.keycloak.org/).

{% hint style="info" %}
**Priority** `2000` · **Category** Authentication · **Required** `client_id`
{% endhint %}

<details>

<summary>Configuration and details</summary>

:::tip

Although this Plugin was developed to work with Keycloak, it should work with any OAuth/OIDC and UMA compliant identity providers as well.

:::

Refer to [Authorization Services Guide](https://www.keycloak.org/docs/latest/authorization_services/) for more information on Keycloak.

| Name                                              | Type           | Required | Default                                       | Valid values                                                     | Description                                                                                                                                                                                                                                                |
| ------------------------------------------------- | -------------- | -------- | --------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| discovery                                         | string         | False    |                                               | <https://host.domain/realms/foo/.well-known/uma2-configuration>  | URL to [discovery document](https://www.keycloak.org/docs/latest/authorization_services/index.html) of Keycloak Authorization Services.                                                                                                                    |
| token\_endpoint                                   | string         | False    |                                               | <https://host.domain/realms/foo/protocol/openid-connect/token>   | An OAuth2-compliant token endpoint that supports the `urn:ietf:params:oauth:grant-type:uma-ticket` grant type. If provided, overrides the value from discovery.                                                                                            |
| resource\_registration\_endpoint                  | string         | False    |                                               | <https://host.domain/realms/foo/authz/protection/resource\\_set> | A UMA-compliant resource registration endpoint. If provided, overrides the value from discovery.                                                                                                                                                           |
| client\_id                                        | string         | True     |                                               |                                                                  | The identifier of the resource server to which the client is seeking access.                                                                                                                                                                               |
| client\_secret                                    | string         | False    |                                               |                                                                  | The client secret, if required. You can use Helix secret to store and reference this value. Helix currently supports storing secrets in two ways. Environment Variables and HashiCorp Vault                                                                |
| grant\_type                                       | string         | False    | "urn:ietf:params:oauth:grant-type:uma-ticket" | \["urn:ietf:params:oauth:grant-type:uma-ticket"]                 |                                                                                                                                                                                                                                                            |
| policy\_enforcement\_mode                         | string         | False    | "ENFORCING"                                   | \["ENFORCING", "PERMISSIVE"]                                     |                                                                                                                                                                                                                                                            |
| permissions                                       | array\[string] | False    |                                               |                                                                  | An array of strings, each representing a set of one or more resources and scopes the client is seeking access.                                                                                                                                             |
| lazy\_load\_paths                                 | boolean        | False    | false                                         |                                                                  | When set to true, dynamically resolves the request URI to resource(s) using the resource registration endpoint instead of the static permission.                                                                                                           |
| http\_method\_as\_scope                           | boolean        | False    | false                                         |                                                                  | When set to true, maps the HTTP request type to scope of the same name and adds to all requested permissions.                                                                                                                                              |
| timeout                                           | integer        | False    | 3000                                          | \[1000, ...]                                                     | Timeout in ms for the HTTP connection with the Identity Server.                                                                                                                                                                                            |
| access\_token\_expires\_in                        | integer        | False    | 300                                           | \[1, ...]                                                        | Expiration time(s) of the access token.                                                                                                                                                                                                                    |
| access\_token\_expires\_leeway                    | integer        | False    | 0                                             | \[0, ...]                                                        | Expiration leeway(s) for access\_token renewal. When set, the token will be renewed access\_token\_expires\_leeway seconds before expiration. This avoids errors in cases where the access\_token just expires when reaching the OAuth Resource Server.    |
| refresh\_token\_expires\_in                       | integer        | False    | 3600                                          | \[1, ...]                                                        | The expiration time(s) of the refresh token.                                                                                                                                                                                                               |
| refresh\_token\_expires\_leeway                   | integer        | False    | 0                                             | \[0, ...]                                                        | Expiration leeway(s) for refresh\_token renewal. When set, the token will be renewed refresh\_token\_expires\_leeway seconds before expiration. This avoids errors in cases where the refresh\_token just expires when reaching the OAuth Resource Server. |
| ssl\_verify                                       | boolean        | False    | true                                          |                                                                  | When set to true, verifies if TLS certificate matches hostname.                                                                                                                                                                                            |
| cache\_ttl\_seconds                               | integer        | False    | 86400 (equivalent to 24h)                     | positive integer >= 1                                            | Maximum time in seconds up to which the Plugin caches discovery documents and tokens used by the Plugin to authenticate to Keycloak.                                                                                                                       |
| keepalive                                         | boolean        | False    | true                                          |                                                                  | When set to true, enables HTTP keep-alive to keep connections open after use. Set to `true` if you are expecting a lot of requests to Keycloak.                                                                                                            |
| keepalive\_timeout                                | integer        | False    | 60000                                         | positive integer >= 1000                                         | Idle time after which the established HTTP connections will be closed.                                                                                                                                                                                     |
| keepalive\_pool                                   | integer        | False    | 5                                             | positive integer >= 1                                            | Maximum number of connections in the connection pool.                                                                                                                                                                                                      |
| access\_denied\_redirect\_uri                     | string         | False    |                                               | \[1, 2048]                                                       | URI to redirect the user to instead of returning an error message like `"error_description":"not_authorized"`.                                                                                                                                             |
| password\_grant\_token\_generation\_incoming\_uri | string         | False    |                                               | /api/token                                                       | Set this to generate token using the password grant type. The Plugin will compare incoming request URI to this value.                                                                                                                                      |

**Sample configuration**

Minimal setup using the discovery document to resolve the Keycloak endpoints:

```json
{
  "authz-keycloak": {
    "discovery": "https://keycloak.example.com/realms/helix/.well-known/uma2-configuration",
    "client_id": "helix-gateway",
    "client_secret": "my-keycloak-client-secret"
  }
}
```

Explicit endpoints that override the discovery document, with a static permission and permissive enforcement:

```json
{
  "authz-keycloak": {
    "token_endpoint": "https://keycloak.example.com/realms/helix/protocol/openid-connect/token",
    "resource_registration_endpoint": "https://keycloak.example.com/realms/helix/authz/protection/resource_set",
    "client_id": "helix-gateway",
    "client_secret": "my-keycloak-client-secret",
    "permissions": ["resource#scope"],
    "policy_enforcement_mode": "PERMISSIVE"
  }
}
```

Dynamic path resolution with HTTP method mapped to scope, plus TLS verification and tuned timeout:

```json
{
  "authz-keycloak": {
    "discovery": "https://keycloak.example.com/realms/helix/.well-known/uma2-configuration",
    "client_id": "helix-gateway",
    "client_secret": "my-keycloak-client-secret",
    "lazy_load_paths": true,
    "http_method_as_scope": true,
    "ssl_verify": true,
    "timeout": 5000
  }
}
```

</details>

### `basic-auth`

The `basic-auth` Plugin adds [basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) so callers authenticate themselves before reaching Upstream resources. The username and password are held by an **App** (see [Apps](/api-gateway/api-gateway/apps.md)); attach this plugin to a route or an API to require them.

{% hint style="info" %}
**Priority** `2520` · **Category** Authentication
{% endhint %}

<details>

<summary>Configuration and details</summary>

When an App is successfully authenticated, Helix adds identity headers (for example `X-Consumer-Username` and `X-Credential-Identifier`) to the request before proxying it to the Upstream service, so the upstream can tell callers apart. If a value is not available, its header is not added.

**App credential**

| Name     | Type   | Required | Description                             |
| -------- | ------ | -------- | --------------------------------------- |
| username | string | True     | Unique basic-auth username for the App. |
| password | string | True     | Basic-auth password for the App.        |

**Route**

| Name                | Type    | Required | Default | Description                                                                      |
| ------------------- | ------- | -------- | ------- | -------------------------------------------------------------------------------- |
| hide\_credentials   | boolean | False    | false   | If true, do not pass the authorization request header to Upstream services.      |
| anonymous\_consumer | boolean | False    | false   | If set, allow anonymous requests to bypass authentication.                       |
| realm               | string  | False    | basic   | The realm to include in the `WWW-Authenticate` header when authentication fails. |

**Sample configuration**

Enable basic authentication on the route with defaults (the plugin takes no required fields at the route level):

```json
{
  "basic-auth": {}
}
```

Hide the `Authorization` header from the upstream and set a custom realm:

```json
{
  "basic-auth": {
    "hide_credentials": true,
    "realm": "helix-api"
  }
}
```

Each App holds its own credential; the credential carries the `basic-auth` plugin with the username and password:

```json
{
  "plugins": {
    "basic-auth": {
      "username": "app-client",
      "password": "my-basic-auth-password"
    }
  }
}
```

</details>

### `cas-auth`

The `cas-auth` Plugin can be used to access CAS (Central Authentication Service 2.0) IdP (Identity Provider) to do authentication, from the SP (service provider) perspective.

{% hint style="info" %}
**Priority** `2597` · **Category** Authentication · **Required** `idp_uri`, `cas_callback_uri`, `logout_uri`
{% endhint %}

<details>

<summary>Configuration and details</summary>

| Name               | Type   | Required | Description                                                          |
| ------------------ | ------ | -------- | -------------------------------------------------------------------- |
| `idp_uri`          | string | True     | URI of IdP.                                                          |
| `cas_callback_uri` | string | True     | redirect uri used to callback the SP from IdP after login or logout. |
| `logout_uri`       | string | True     | logout uri to trigger logout.                                        |

**Sample configuration**

Delegate authentication to a CAS 2.0 identity provider:

```json
{
  "cas-auth": {
    "idp_uri": "https://cas.example.com/cas",
    "cas_callback_uri": "/api/v1/cas/callback",
    "logout_uri": "/api/v1/cas/logout"
  }
}
```

</details>

### `forward-auth`

The `forward-auth` Plugin implements a classic external authentication model. When authentication fails, you can have a custom error message or redirect the user to an authentication page.

{% hint style="info" %}
**Priority** `2002` · **Category** Authentication · **Required** `uri`
{% endhint %}

<details>

<summary>Configuration and details</summary>

This Plugin moves the authentication and authorization logic to a dedicated external service. Helix forwards the user's requests to the external service, blocks the original request, and replaces the result when the external service responds with a non 2xx status code.

| Name               | Type           | Required | Default | Valid values    | Description                                                                                                                                                                                                                                                                            |
| ------------------ | -------------- | -------- | ------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| uri                | string         | True     |         |                 | URI of the authorization service.                                                                                                                                                                                                                                                      |
| ssl\_verify        | boolean        | False    | true    |                 | When set to `true`, verifies the SSL certificate.                                                                                                                                                                                                                                      |
| request\_method    | string         | False    | GET     | \["GET","POST"] | HTTP method for a client to send requests to the authorization service. When set to `POST` the request body is sent to the authorization service. (not recommended - see section on [Using data from POST body](#using-data-from-post-body-to-make-decision-on-authorization-service)) |
| request\_headers   | array\[string] | False    |         |                 | Client request headers to be sent to the authorization service. If not set, only the headers provided by Helix are sent (for example, `X-Forwarded-XXX`).                                                                                                                              |
| extra\_headers     | object         | False    |         |                 | Extra headers to be sent to the authorization service passed in key-value format. The value can be a variable like `$request_uri`, `$post_arg.xyz`                                                                                                                                     |
| upstream\_headers  | array\[string] | False    |         |                 | Authorization service response headers to be forwarded to the Upstream. If not set, no headers are forwarded to the Upstream service.                                                                                                                                                  |
| client\_headers    | array\[string] | False    |         |                 | Authorization service response headers to be sent to the client when authorization fails. If not set, no headers will be sent to the client.                                                                                                                                           |
| timeout            | integer        | False    | 3000ms  | \[1, 60000]ms   | Timeout for the authorization service HTTP call.                                                                                                                                                                                                                                       |
| keepalive          | boolean        | False    | true    |                 | When set to `true`, keeps the connection alive for multiple requests.                                                                                                                                                                                                                  |
| keepalive\_timeout | integer        | False    | 60000ms | \[1000, ...]ms  | Idle time after which the connection is closed.                                                                                                                                                                                                                                        |
| keepalive\_pool    | integer        | False    | 5       | \[1, ...]ms     | Connection pool limit.                                                                                                                                                                                                                                                                 |
| allow\_degradation | boolean        | False    | false   |                 | When set to `true`, allows authentication to be skipped when authentication server is unavailable.                                                                                                                                                                                     |
| status\_on\_error  | integer        | False    | 403     | \[200,...,599]  | Sets the HTTP status that is returned to the client when there is a network error to the authorization service. The default status is “403” (HTTP Forbidden).                                                                                                                          |

**Sample configuration**

Minimal setup that forwards each request to an external authorization service:

```json
{
  "forward-auth": {
    "uri": "https://auth.example.com/verify"
  }
}
```

Forward selected client headers and pass the authorization service response headers to the upstream:

```json
{
  "forward-auth": {
    "uri": "https://auth.example.com/verify",
    "request_headers": ["Authorization", "X-Request-Id"],
    "upstream_headers": ["X-User-Id", "X-User-Role"],
    "client_headers": ["Location"]
  }
}
```

Send the request body to the authorization service using POST, with tuned timeout and graceful degradation:

```json
{
  "forward-auth": {
    "uri": "https://auth.example.com/verify",
    "request_method": "POST",
    "timeout": 5000,
    "allow_degradation": true,
    "status_on_error": 500
  }
}
```

</details>

### `helix-auth`

The `helix-auth` Plugin authenticates callers for Helix API products. It is a dual-mode OAuth2 Client Credentials plugin: **generate mode** issues JWTs from a token endpoint, and **validate mode** authenticates protected routes with either a Bearer JWT or an API key, so you do not need a separate JWT plugin.

{% hint style="info" %}
**Priority** `2450` · **Category** Authentication
{% endhint %}

<details>

<summary>Configuration and details</summary>

**Generate mode** (`mode: "generate"`): used on token endpoints (for example `/oauth/token`). The client sends `Authorization: Basic base64(client_id:client_secret)`. The plugin resolves the App credential, verifies the secret, signs a JWT, and returns a JSON token response (`access_token`, `token_type`, `expires_in`).

**Validate mode** (`mode: "validate"`): used on protected API routes. Choose how clients present identity with `validate_auth_type`:

| `validate_auth_type`   | Client presents                                       | Route needs                                                                 |
| ---------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------- |
| `"jwt-auth"` (default) | `Authorization: Bearer <JWT>` from the token endpoint | `signing_secret` (same secret used to sign tokens)                          |
| `"key-auth"`           | Credential `key` in a header or query parameter       | `apikey.source` (and optional `apikey.key`); no JWT and no `signing_secret` |

In both validate paths the plugin resolves the credential by client id (`key`), calls `attach_consumer`, then selects the top-ranked matching product for the current `service_id` into `ctx.helix.<ctx_namespace>.*` (default `helix_auth`) for downstream plugins (for example [`helix-analytics`](/api-gateway/plugin-reference/plugins-observability.md#helix-analytics) and [`api-product-enforcer`](/api-gateway/plugin-reference/plugins-traffic.md#api-product-enforcer)). Downstream readers auto-resolve the namespace via `ctx.helix._namespaces["helix-auth"]`. Requests with no product subscriptions or no product covering the route `service_id` are rejected with **403** in the access phase.

:::note

By default, key-auth validate does **not** check the credential `secret`. The value sent in the header or query is the credential **`key`** (client id), looked up the same way JWT claims and Basic auth use `key`. The `secret` is still stored on the credential (the schema requires it) and is only verified in **generate** mode.

You can opt in to a secret fallback with `secret_validation`. When it is `true` and the API key is **absent** from the request, the plugin accepts the credential `secret` as an alternative credential, read from the header or query named in `apisecret`. The secret is never consulted while an API key is present, and a rejected API key never falls through to it. The `401` message is identical for a missing or invalid API key and for the secret fallback, so a rejection never discloses which credential failed.

:::

**Route-level configuration**

| Name                 | Type    | Required    | Default      | Description                                                                                                                                                                                                                              |
| -------------------- | ------- | ----------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| mode                 | string  | False       | `"validate"` | `"generate"` for token issuance, `"validate"` for authenticating protected routes (JWT or API key).                                                                                                                                      |
| validate\_auth\_type | string  | False       | `"jwt-auth"` | Validate mode only: `"jwt-auth"` (Bearer JWT) or `"key-auth"` (API key in header or query). Ignored in generate mode.                                                                                                                    |
| client\_id\_claim    | string  | False       | `"key"`      | JWT payload field that stores the client id. Used in generate (when signing) and jwt-auth validate (when reading claims).                                                                                                                |
| algorithm            | string  | False       | `"HS256"`    | Signing algorithm for generate / jwt-auth: `"HS256"` or `"RS256"`. Not used for key-auth.                                                                                                                                                |
| signing\_secret      | string  | Conditional |              | Shared secret for HS256 signing (generate) and JWT verification (jwt-auth validate). Required for validate when `validate_auth_type` is `jwt-auth`. Must match between generate and jwt-auth validate routes. Not required for key-auth. |
| base64\_secret       | boolean | False       | `false`      | When true, `signing_secret` is base64-decoded before use.                                                                                                                                                                                |
| private\_key         | string  | Conditional |              | PEM private key for RS256 signing. Required when `algorithm` is `"RS256"` in generate mode.                                                                                                                                              |
| base64\_private\_key | boolean | False       | `false`      | When true, `private_key` is base64-decoded before use.                                                                                                                                                                                   |
| token\_ttl           | integer | False       | `3600`       | Token lifetime in seconds (JWT `exp` = `iat` + token\_ttl). Minimum 1. Generate mode only.                                                                                                                                               |
| payload              | object  | False       |              | Extra claims merged into the JWT with the client id claim, `iat`, and `exp`. Generate mode only.                                                                                                                                         |
| apikey               | object  | Conditional |              | Key-auth validate only. See the `apikey` table below. Required when `validate_auth_type` is `key-auth`.                                                                                                                                  |
| secret\_validation   | boolean | False       | `false`      | Key-auth validate only. When `true`, the credential `secret` is accepted as an alternative credential if the API key is absent. Requires `apisecret`.                                                                                    |
| apisecret            | object  | Conditional |              | Key-auth validate only. See the `apisecret` table below. Required when `secret_validation` is `true`.                                                                                                                                    |
| ctx\_namespace       | string  | False       | `helix_auth` | Namespace under `ctx.helix` where plugin ctx fields are stored. Registered in `ctx.helix._namespaces["helix-auth"]` for downstream readers.                                                                                              |

**`apikey`** (used only when `mode` is `"validate"` and `validate_auth_type` is `"key-auth"`)

| Name   | Type   | Required | Default    | Description                                                                                                                            |
| ------ | ------ | -------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| source | string | True     |            | Where to read the API key: `"header"` or `"query"`. Only the configured source is checked (header-only ignores query, and vice versa). |
| key    | string | False    | `"apikey"` | Name of the header or query parameter that carries the credential **`key`** (client id).                                               |

**`apisecret`** (used only when `mode` is `"validate"`, `validate_auth_type` is `"key-auth"`, and `secret_validation` is `true`)

| Name   | Type   | Required | Default       | Description                                                                                                                        |
| ------ | ------ | -------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| source | string | True     |               | Where to read the secret fallback: `"header"` or `"query"`.                                                                        |
| key    | string | False    | `"apisecret"` | Name of the header or query parameter that carries the credential **`secret`**. Must not use the same source and name as `apikey`. |
| prefix | string | False    |               | Optional prefix stripped from the value before comparison. Once set, the prefix is required on the incoming value.                 |

NOTE: `encrypt_fields = {"signing_secret", "private_key"}`: these values are stored encrypted at rest.

Dependencies:

* **Generate mode:** for `algorithm` = `HS256`, `signing_secret` is required. For `RS256`, `private_key` is required.
* **Validate + jwt-auth:** `signing_secret` is required.
* **Validate + key-auth:** `apikey` with `source` is required; `signing_secret` is not used. To also accept the credential `secret` as a fallback, set `secret_validation` to `true` and add `apisecret` (with a `source` and a name distinct from `apikey`).

**App credential configuration**

| Name   | Type   | Required | Description                                                                                                                                      |
| ------ | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| key    | string | True     | The client id. Lookup key for Basic auth (generate), JWT `client_id_claim` (jwt-auth validate), and the API key value (key-auth validate).       |
| secret | string | True     | The client secret. Verified only in generate mode (Basic auth). Required by schema even when the credential is used only with key-auth validate. |

NOTE: `encrypt_fields = {"secret"}`: the secret is stored encrypted at rest.

The credential request body must include the plugin directly with both `key` and `secret`. They are validated on creation and `secret` is encrypted at rest.

**How it works**

* **Generate mode** (token endpoint): the client presents its `client_id` and `client_secret` as HTTP Basic auth. The plugin verifies the credential, signs a JWT (HS256 or RS256), and returns a JSON token response with `access_token`, `token_type`, and `expires_in`.
* **Validate mode with JWT** (`jwt-auth`): the client calls the protected API with the issued token as `Authorization: Bearer <JWT>`. The plugin verifies the token, identifies the calling application, and authorizes it against the API products it is subscribed to for that route.
* **Validate mode with API key** (`key-auth`): the client sends its credential `key` in a header or query parameter instead of a JWT. The plugin identifies the application the same way and applies the same API-product authorization.

In both validate modes, a client that presents no valid credential is rejected with **401**, and a valid credential with no product covering the route is rejected with **403**. After a successful validate call, the selected API product is made available to downstream plugins such as [`api-product-enforcer`](/api-gateway/plugin-reference/plugins-traffic.md#api-product-enforcer) and [`helix-analytics`](/api-gateway/plugin-reference/plugins-observability.md#helix-analytics) through `ctx.helix.<ctx_namespace>`.

**Request context variables**

After successful authentication, the plugin populates the following request context fields.

| Variable                               | Type          | Description                                                                                      | Example                                                 | Request lifecycle                                    |
| -------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------- | ---------------------------------------------------- |
| `ctx.consumer`                         | table         | Resolved consumer merged with credential fields when auth matches a credential.                  | `{ id = "rank-dev", credential_id = "rank-app", ... }`  | rewrite, after successful auth via `attach_consumer` |
| `ctx.consumer_name`                    | string        | Consumer username (same as consumer `id`).                                                       | `rank-dev`                                              | rewrite, after `attach_consumer`                     |
| `ctx.consumer_group_id`                | string or nil | Consumer group id when the consumer belongs to a group.                                          | `premium-group`                                         | rewrite, after `attach_consumer`                     |
| `ctx.consumer_ver`                     | number        | Consumer configuration version used for cache invalidation.                                      | `42`                                                    | rewrite, after `attach_consumer`                     |
| `ctx.consumer.credential_id`           | string        | Credential id derived from the credential configuration path.                                    | `rank-app`                                              | rewrite, when auth resolves a credential             |
| `ctx.consumer.credential_name`         | string        | Credential display name from the configuration store.                                            | `rank-app`                                              | rewrite, when auth resolves a credential             |
| `ctx.consumer.credential_products`     | object        | Map of product id to rank for the credential subscription.                                       | `{ "rank-prod-a": 1, "rank-prod-b": 2 }`                | rewrite, when auth resolves a credential             |
| `ctx.consumer.credential_callback_url` | string or nil | Optional callback URL stored on the credential.                                                  | `https://example.com/callback`                          | rewrite, when set on the credential                  |
| `ctx.consumer.auth_conf`               | object        | Credential plugin config containing client id and secret.                                        | `{ key = "rank-client", secret = "..." }`               | rewrite, when auth resolves a credential             |
| `ctx.helix.helix_auth._route_conf`     | object        | Stashed route-level signing config for generate mode before consumer merge replaces plugin conf. | `{ mode = "generate", signing_secret = "...", ... }`    | rewrite, generate mode only                          |
| `ctx.helix.helix_auth.product_id`      | string        | Top-ranked product id whose `service_ids` cover the route `service_id`.                          | `rank-prod-a`                                           | access, validate mode (jwt-auth and key-auth)        |
| `ctx.helix.helix_auth.product_name`    | string        | Display name of the selected product (`name` or `displayName` fallback).                         | `rank-a`                                                | access, validate mode                                |
| `ctx.helix.helix_auth.product`         | object        | Full product definition from `/products` including quota and `service_ids`.                      | `{ name = "rank-a", quota = { limit = 10, ... }, ... }` | access, validate mode                                |
| `ctx.helix.helix_auth.access_token`    | string        | Signed JWT issued to the client.                                                                 | `eyJhbGciOiJIUzI1NiIs...`                               | access, generate mode, before token response         |
| `ctx.helix.helix_auth.token_type`      | string        | OAuth2 token type for the issued token.                                                          | `Bearer`                                                | access, generate mode                                |
| `ctx.helix.helix_auth.expires_in`      | integer       | Token lifetime in seconds (`token_ttl`).                                                         | `3600`                                                  | access, generate mode                                |

**Examples**

The examples below demonstrate generate mode, jwt-auth validate, and key-auth validate. Attach the plugin configuration shown to the route (or the whole API revision) from the portal's plugin form; see [Browsing the plugin catalogue](/api-gateway/api-gateway/browsing-the-plugin-catalogue.md) for the attach workflow.

**Full flow: generate + validate with HS256 (jwt-auth)**

Step 1: create a **Developer** (the gateway consumer), for example `app-client`, under **API Distribution → Developers**.

Step 2: bundle the API into an **API product** that allows `helix-auth`, and deploy that product to your environment. See [API products](/api-gateway/api-gateway/api-products.md).

Step 3: create an **App** under that developer, subscribed to the deployed product, with `helix-auth` as its authentication method. The app's credential carries the `key` and `secret`. See [Apps](/api-gateway/api-gateway/apps.md):

```json
{
  "plugins": {
    "helix-auth": {
      "key": "client-key-1",
      "secret": "client-secret-123"
    }
  },
  "products": { "gold-plan": 1 }
}
```

Step 3: on the token route (for example `POST /oauth/token`), attach `helix-auth` in generate mode:

```json
{
  "helix-auth": {
    "mode": "generate",
    "signing_secret": "my-hs256-signing-secret-32chars!",
    "client_id_claim": "sub",
    "token_ttl": 3600
  }
}
```

Step 4: on the protected route (for example `/api/*`), attach `helix-auth` in validate mode together with `api-product-enforcer`:

```json
{
  "helix-auth": {
    "mode": "validate",
    "validate_auth_type": "jwt-auth",
    "signing_secret": "my-hs256-signing-secret-32chars!",
    "client_id_claim": "sub"
  },
  "api-product-enforcer": {}
}
```

:::important

The `signing_secret` must be **identical** on both the generate and jwt-auth validate routes. The generate route signs the JWT with it; the validate route verifies the signature with it.

:::

Step 5: the client requests a token from the environment's gateway hostname:

```shell
curl -i -X POST "https://<your-gateway-host>/oauth/token" \
  -H "Authorization: Basic $(echo -n 'client-key-1:client-secret-123' | base64)"
```

You should receive `HTTP/1.1 200 OK` with a JSON body:

```json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

Step 6: the client accesses a protected API:

```shell
curl -i "https://<your-gateway-host>/api/resource" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
```

The validate mode verifies the JWT, attaches **`ctx.consumer`**, and sets **`ctx.helix.helix_auth.product_id`**, **`ctx.helix.helix_auth.product_name`**, and **`ctx.helix.helix_auth.product`** for `api-product-enforcer` quota enforcement and `helix-analytics`.

**Validate mode with API key (key-auth)**

Use the same Consumer/Credential as above (the API key value is the credential `key`, for example `client-key-1`). No token endpoint or `signing_secret` is required on the protected route.

Header source, plugin configuration on the protected route:

```json
{
  "helix-auth": {
    "mode": "validate",
    "validate_auth_type": "key-auth",
    "apikey": {
      "source": "header",
      "key": "apikey"
    }
  },
  "api-product-enforcer": {}
}
```

Client request:

```shell
curl -i "https://<your-gateway-host>/api/resource" -H "apikey: client-key-1"
```

With `source: "header"`, a query parameter named `apikey` is **ignored**.

Query source, plugin configuration on the protected route:

```json
{
  "helix-auth": {
    "mode": "validate",
    "validate_auth_type": "key-auth",
    "apikey": {
      "source": "query",
      "key": "api_key"
    }
  },
  "api-product-enforcer": {}
}
```

Client request:

```shell
curl -i "https://<your-gateway-host>/api/resource?api_key=client-key-1"
```

With `source: "query"`, a matching header is **ignored**.

After a successful key-auth call, product context is set the same way as jwt-auth (`product_id`, `product_name`, `product` under `ctx.helix.helix_auth`).

**Invalid credentials**

```shell
curl -i -X POST "https://<your-gateway-host>/oauth/token" \
  -H "Authorization: Basic $(echo -n 'client-key-1:wrong-secret' | base64)"
```

You should receive `HTTP/1.1 401 Unauthorized`:

```json
{"error": "invalid_client"}
```

**Token endpoint with RS256**

Generate an RSA key pair:

```shell
openssl genrsa -out rs256-private.pem 2048
openssl rsa -in rs256-private.pem -pubout -out rs256-public.pem
```

Plugin configuration on the token route:

```json
{
  "helix-auth": {
    "mode": "generate",
    "signing_secret": "placeholder",
    "algorithm": "RS256",
    "private_key": "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----",
    "token_ttl": 7200
  }
}
```

:::tip

For PEM keys, use `\n` for newlines in the JSON value. For large keys, set `base64_private_key` to `true` and provide the key base64-encoded.

:::

**Custom payload claims**

Add extra claims to the JWT via the plugin's `payload` on the token route:

```json
{
  "helix-auth": {
    "mode": "generate",
    "signing_secret": "my-hs256-signing-secret-32chars!",
    "token_ttl": 3600,
    "payload": {
      "scope": "read write",
      "iss": "https://my-gateway.example.com"
    }
  }
}
```

The issued JWT will include the `client_id_claim`, `iat`, `exp`, plus `scope` and `iss` (and any other keys in `payload`).

**Error reference: generate mode**

| Status | Body                                                                          | Condition                                          |
| ------ | ----------------------------------------------------------------------------- | -------------------------------------------------- |
| 401    | `{ "error": "invalid_client" }`                                               | Missing or malformed `Authorization: Basic` header |
| 401    | `{ "error": "invalid_client" }`                                               | Unknown client\_id (no matching credential)        |
| 401    | `{ "error": "invalid_client" }`                                               | Incorrect client\_secret                           |
| 500    | `{ "error": "server_error", "error_description": "Token generation failed" }` | JWT signing failure                                |

**Error reference: validate mode, jwt-auth (rewrite phase)**

| Status | Body                                                        | Condition                                   |
| ------ | ----------------------------------------------------------- | ------------------------------------------- |
| 401    | `{ "message": "Missing or invalid authorization" }`         | Missing or malformed Bearer token           |
| 401    | `{ "message": "Invalid or expired token" }`                 | JWT verification failed                     |
| 401    | `{ "message": "Invalid token: missing client identifier" }` | Configured `client_id_claim` missing in JWT |
| 401    | `{ "message": "Unknown client" }`                           | client\_id from JWT has no credential       |

**Error reference: validate mode, key-auth (rewrite phase)**

| Status | Body                                          | Condition                                            |
| ------ | --------------------------------------------- | ---------------------------------------------------- |
| 401    | `{ "message": "Missing API key in request" }` | No value in the configured header or query parameter |
| 401    | `{ "message": "Invalid API key in request" }` | Value present but no credential with matching `key`  |

**Error reference: validate mode (access phase, product resolution)**

Applies to both **jwt-auth** and **key-auth** after authentication succeeds.

| Status | Body                                                                     | Condition                                                      |
| ------ | ------------------------------------------------------------------------ | -------------------------------------------------------------- |
| 403    | `{ "message": "This credential is not subscribed to any API product." }` | Empty or missing `credential_products`                         |
| 403    | `{ "message": "This credential is not authorized to access this API." }` | Credential has products, but none cover the route `service_id` |

</details>

### `hmac-auth`

The `hmac-auth` Plugin supports HMAC (Hash-based Message Authentication Code) authentication as a mechanism to ensure the integrity of requests, preventing them from being modified during transmissions. To use the Plugin, you configure the HMAC key id and secret key on an **App** (see [Apps](/api-gateway/api-gateway/apps.md)) and enable the Plugin on Routes or APIs.

{% hint style="info" %}
**Priority** `2530` · **Category** Authentication
{% endhint %}

<details>

<summary>Configuration and details</summary>

When an App is successfully authenticated, Helix adds identity headers (for example `X-Consumer-Username` and `X-Credential-Identifier`) to the request before proxying it to the Upstream service, so the upstream can tell callers apart. If a value is not available, its header is not added.

Once enabled, the Plugin verifies the HMAC signature in the request's `Authorization` header and checks that incoming requests are from trusted sources. Specifically, when Helix receives an HMAC-signed request, the key id is extracted from the `Authorization` header. Helix then looks up the matching App credential, including its secret key. If the key id is valid and exists, Helix generates an HMAC signature using the request's `Date` header and the secret key. If this generated signature matches the signature provided in the `Authorization` header, the request is authenticated and forwarded to Upstream services.

The Plugin implementation is based on [draft-cavage-http-signatures](https://www.ietf.org/archive/id/draft-cavage-http-signatures-12.txt).

| Name        | Type   | Required | Default | Valid values | Description                                                                                                                  |
| ----------- | ------ | -------- | ------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| key\_id     | string | True     |         |              | Unique identifier for the App credential (the key id a caller presents), which identifies its associated secret key.         |
| secret\_key | string | True     |         |              | Secret key used to generate an HMAC. This field supports saving the value in Secret Manager using the Helix Secret resource. |

| Name                    | Type           | Required | Default                                    | Valid values                                               | Description                                                                                                                                                                                                                                                                                                                                               |
| ----------------------- | -------------- | -------- | ------------------------------------------ | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| allowed\_algorithms     | array\[string] | False    | \["hmac-sha1","hmac-sha256","hmac-sha512"] | combination of "hmac-sha1","hmac-sha256",and "hmac-sha512" | The list of HMAC algorithms allowed.                                                                                                                                                                                                                                                                                                                      |
| clock\_skew             | integer        | False    | 300                                        | >=1                                                        | Maximum allowable time difference in seconds between the client request's timestamp and Helix server's current time. This helps account for discrepancies in time synchronization between the client’s and server’s clocks and protect against replay attacks. The timestamp in the Date header (must be in GMT format) will be used for the calculation. |
| signed\_headers         | array\[string] | False    |                                            |                                                            | The list of HMAC-signed headers that should be included in the client request's HMAC signature.                                                                                                                                                                                                                                                           |
| validate\_request\_body | boolean        | False    | false                                      |                                                            | If true, validate the integrity of the request body to ensure it has not been tampered with during transmission. Specifically, the Plugin creates a SHA-256 base64-encoded digest and compare it to the `Digest` header. If the `Digest` header is missing or if the digests do not match, the validation fails.                                          |
| hide\_credentials       | boolean        | False    | false                                      |                                                            | If true, do not pass the authorization request header to Upstream services.                                                                                                                                                                                                                                                                               |
| anonymous\_consumer     | string         | False    |                                            |                                                            | If set, allow anonymous requests to bypass authentication.                                                                                                                                                                                                                                                                                                |
| realm                   | string         | False    | hmac                                       |                                                            | The realm to include in the `WWW-Authenticate` header when authentication fails.                                                                                                                                                                                                                                                                          |

**Sample configuration**

Enable HMAC verification on the route with defaults (all allowed algorithms, 300s clock skew):

```json
{
  "hmac-auth": {}
}
```

Restrict to SHA-256, require specific signed headers, and validate the request body against the `Digest` header:

```json
{
  "hmac-auth": {
    "allowed_algorithms": ["hmac-sha256"],
    "clock_skew": 60,
    "signed_headers": ["date", "host", "digest"],
    "validate_request_body": true,
    "hide_credentials": true
  }
}
```

Each App holds its own credential; the credential carries the `hmac-auth` plugin with the key id and secret key:

```json
{
  "plugins": {
    "hmac-auth": {
      "key_id": "app-client-1",
      "secret_key": "my-hmac-secret-key"
    }
  }
}
```

</details>

### `ldap-auth`

The `ldap-auth` Plugin can be used to add LDAP authentication to a Route or an API.

{% hint style="info" %}
**Priority** `2540` · **Category** Authentication · **Required** `base_dn`, `ldap_uri`
{% endhint %}

<details>

<summary>Configuration and details</summary>

Callers authenticate against an LDAP server using [basic authentication](https://en.wikipedia.org/wiki/Basic_access_authentication). The App credential (see [Apps](/api-gateway/api-gateway/apps.md)) supplies the user dn, and this Plugin connects to the LDAP server to verify it.

**App credential**

| Name     | Type   | Required | Description                                                                                                                                                              |
| -------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| user\_dn | string | True     | User dn of the LDAP client. For example, `cn=user01,ou=users,dc=example,dc=org`. This field supports saving the value in Secret Manager using the Helix Secret resource. |

**Route**

| Name        | Type    | Required | Default | Description                                                                                                                                                                                                                 |
| ----------- | ------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| base\_dn    | string  | True     |         | Base dn of the LDAP server. For example, `ou=users,dc=example,dc=org`.                                                                                                                                                      |
| ldap\_uri   | string  | True     |         | URI of the LDAP server.                                                                                                                                                                                                     |
| use\_tls    | boolean | False    | `false` | If set to `true` uses TLS.                                                                                                                                                                                                  |
| tls\_verify | boolean | False    | `false` | Whether to verify the server certificate when `use_tls` is enabled; If set to `true`, you must set `ssl_trusted_certificate` in `config.yaml`, and make sure the host of `ldap_uri` matches the host in server certificate. |
| uid         | string  | False    | `cn`    | uid attribute.                                                                                                                                                                                                              |
| realm       | string  | False    | ldap    | The realm to include in the `WWW-Authenticate` header when authentication fails.                                                                                                                                            |

**Sample configuration**

Authenticate callers against an LDAP server over a plain connection:

```json
{
  "ldap-auth": {
    "base_dn": "ou=users,dc=example,dc=org",
    "ldap_uri": "ldap.example.com:389",
    "uid": "cn"
  }
}
```

Connect over TLS and verify the server certificate:

```json
{
  "ldap-auth": {
    "base_dn": "ou=users,dc=example,dc=org",
    "ldap_uri": "ldap.example.com:636",
    "use_tls": true,
    "tls_verify": true,
    "uid": "cn"
  }
}
```

Each App maps to an LDAP user; the credential carries the `ldap-auth` plugin with the user dn:

```json
{
  "plugins": {
    "ldap-auth": {
      "user_dn": "cn=user01,ou=users,dc=example,dc=org"
    }
  }
}
```

</details>

### `multi-auth`

The `multi-auth` Plugin is used to add multiple authentication methods to a Route or an API. It supports plugins of type 'auth'. You can combine different authentication methods using `multi-auth` plugin.

{% hint style="info" %}
**Priority** `2600` · **Category** Authentication · **Required** `auth_plugins`
{% endhint %}

<details>

<summary>Configuration and details</summary>

This plugin provides a flexible authentication mechanism by iterating through the list of authentication plugins specified in the `auth_plugins` attribute. It allows different callers to share the same route while using different authentication methods. For example, one caller can authenticate using basic authentication, while another authenticates with an API key.

**Route**

| Name          | Type  | Required | Default | Description                                                           |
| ------------- | ----- | -------- | ------- | --------------------------------------------------------------------- |
| auth\_plugins | array | True     | -       | Add supporting auth plugins configuration. expects at least 2 plugins |

**Sample configuration**

Allow callers to authenticate with either basic authentication or LDAP on the same route. Each entry in `auth_plugins` is an object keyed by the auth plugin name:

```json
{
  "multi-auth": {
    "auth_plugins": [
      { "basic-auth": {} },
      { "ldap-auth": { "base_dn": "ou=users,dc=example,dc=org", "ldap_uri": "ldap.example.com:389", "uid": "cn" } }
    ]
  }
}
```

</details>

### `opa`

The `opa` Plugin can be used to integrate with [Open Policy Agent (OPA)](https://www.openpolicyagent.org). OPA is a policy engine that helps defininig and enforcing authorization policies, which determines whether a user or application has the necessary permissions to perform a particular action or access a particular resource. Using OPA with Helix decouples authorization logics from Helix.

{% hint style="info" %}
**Priority** `2001` · **Category** Authentication · **Required** `host`, `policy`
{% endhint %}

<details>

<summary>Configuration and details</summary>

| Name               | Type    | Required | Default | Valid values   | Description                                                                                                                                                                                                                                             |
| ------------------ | ------- | -------- | ------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| host               | string  | True     |         |                | Host address of the OPA service. For example, `https://localhost:8181`.                                                                                                                                                                                 |
| ssl\_verify        | boolean | False    | true    |                | When set to `true` verifies the SSL certificates.                                                                                                                                                                                                       |
| policy             | string  | True     |         |                | OPA policy path. A combination of `package` and `decision`. While using advanced features like custom response, you can omit `decision`. When specifying a namespace, use the slash format (`examples/echo`) instead of dot notation (`examples.echo`). |
| timeout            | integer | False    | 3000ms  | \[1, 60000]ms  | Timeout for the HTTP call.                                                                                                                                                                                                                              |
| keepalive          | boolean | False    | true    |                | When set to `true`, keeps the connection alive for multiple requests.                                                                                                                                                                                   |
| keepalive\_timeout | integer | False    | 60000ms | \[1000, ...]ms | Idle time after which the connection is closed.                                                                                                                                                                                                         |
| keepalive\_pool    | integer | False    | 5       | \[1, ...]ms    | Connection pool limit.                                                                                                                                                                                                                                  |
| with\_route        | boolean | False    | false   |                | When set to true, sends information about the current Route.                                                                                                                                                                                            |
| with\_service      | boolean | False    | false   |                | When set to true, sends information about the current API.                                                                                                                                                                                              |
| with\_consumer     | boolean | False    | false   |                | When set to true, sends information about the current Consumer. Note that this may send sensitive information like the API key. Make sure to turn it on only when you are sure it is safe.                                                              |

**Sample configuration**

Delegate the authorization decision to an OPA service, referencing a policy by package and decision:

```json
{
  "opa": {
    "host": "https://opa.example.com:8181",
    "policy": "example/allow"
  }
}
```

Include Route, Service, and Consumer information in the request sent to OPA, with tuned timeout and certificate verification:

```json
{
  "opa": {
    "host": "https://opa.example.com:8181",
    "policy": "example/allow",
    "ssl_verify": true,
    "timeout": 5000,
    "with_route": true,
    "with_service": true,
    "with_consumer": true
  }
}
```

</details>

### `openid-connect`

The `openid-connect` Plugin supports the integration with [OpenID Connect (OIDC)](https://openid.net/connect/) identity providers, such as Keycloak, Auth0, Microsoft Entra ID, Google, Okta, and more. It allows Helix to authenticate clients and obtain their information from the identity provider before allowing or denying their access to upstream protected resources.

{% hint style="info" %}
**Priority** `2599` · **Category** Authentication · **Required** `client_id`, `client_secret`, `discovery`
{% endhint %}

<details>

<summary>Configuration and details</summary>

| Name                                              | Type           | Required | Default               | Valid values                      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ------------------------------------------------- | -------------- | -------- | --------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| client\_id                                        | string         | True     |                       |                                   | OAuth client ID.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| client\_secret                                    | string         | True     |                       |                                   | OAuth client secret.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| discovery                                         | string         | True     |                       |                                   | URL to the well-known discovery document of the OpenID provider, which contains a list of OP API endpoints. The Plugin can directly utilize the endpoints from the discovery document. You can also configure these endpoints individually, which takes precedence over the endpoints supplied in the discovery document.                                                                                                                                                                                               |
| scope                                             | string         | False    | openid                |                                   | OIDC scope that corresponds to information that should be returned about the authenticated user, also known as [claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). This is used to authorize users with proper permission. The default value is `openid`, the required scope for OIDC to return a `sub` claim that uniquely identifies the authenticated user. Additional scopes can be appended and delimited by spaces, such as `openid email profile`.                                   |
| required\_scopes                                  | array\[string] | False    |                       |                                   | Scopes required to be present in the access token. Used in conjunction with the introspection endpoint when `bearer_only` is `true`. If any required scope is missing, the Plugin rejects the request with a 403 forbidden error.                                                                                                                                                                                                                                                                                       |
| realm                                             | string         | False    | helix                 |                                   | Realm in [`WWW-Authenticate`](https://www.rfc-editor.org/rfc/rfc6750#section-3) response header accompanying a 401 unauthorized request due to invalid bearer token.                                                                                                                                                                                                                                                                                                                                                    |
| bearer\_only                                      | boolean        | False    | false                 |                                   | If true, strictly require bearer access token in requests for authentication.                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| logout\_path                                      | string         | False    | /logout               |                                   | Path to activate the logout.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| post\_logout\_redirect\_uri                       | string         | False    |                       |                                   | URL to redirect users to after the `logout_path` receive a request to log out.                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| redirect\_uri                                     | string         | False    |                       |                                   | URI to redirect to after authentication with the OpenID provider. Note that the redirect URI should not be the same as the request URI, but a sub-path of the request URI. For example, if the `uri` of the Route is `/api/v1/*`, `redirect_uri` can be configured as `/api/v1/redirect`. If `redirect_uri` is not configured, Helix will append `/.helix/redirect` to the request URI to determine the value for `redirect_uri`.                                                                                       |
| timeout                                           | integer        | False    | 3                     | \[1,...]                          | Request timeout time in seconds.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| ssl\_verify                                       | boolean        | False    | false                 |                                   | If true, verify the OpenID provider 's SSL certificates.                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| introspection\_endpoint                           | string         | False    |                       |                                   | URL of the [token introspection](https://datatracker.ietf.org/doc/html/rfc7662) endpoint for the OpenID provider used to introspect access tokens. If this is unset, the introspection endpoint presented in the well-known discovery document is used as a fallback.                                                                                                                                                                                                                                                   |
| introspection\_endpoint\_auth\_method             | string         | False    | client\_secret\_basic |                                   | Authentication method for the token introspection endpoint. The value should be one of the authentication methods specified in the `introspection_endpoint_auth_methods_supported` [authorization server metadata](https://www.rfc-editor.org/rfc/rfc8414.html) as seen in the well-known discovery document, such as `client_secret_basic`, `client_secret_post`, `private_key_jwt`, and `client_secret_jwt`.                                                                                                          |
| token\_endpoint\_auth\_method                     | string         | False    | client\_secret\_basic |                                   | Authentication method for the token endpoint. The value should be one of the authentication methods specified in the `token_endpoint_auth_methods_supported` [authorization server metadata](https://www.rfc-editor.org/rfc/rfc8414.html) as seen in the well-known discovery document, such as `client_secret_basic`, `client_secret_post`, `private_key_jwt`, and `client_secret_jwt`. If the configured method is not supported, fall back to the first method in the `token_endpoint_auth_methods_supported` array. |
| public\_key                                       | string         | False    |                       |                                   | Public key used to verify JWT signature id asymmetric algorithm is used. Providing this value to perform token verification will skip token introspection in client credentials flow. You can pass the public key in `-----BEGIN PUBLIC KEY-----\\n……\\n-----END PUBLIC KEY-----` format.                                                                                                                                                                                                                               |
| use\_jwks                                         | boolean        | False    | false                 |                                   | If true and if `public_key` is not set, use the JWKS to verify JWT signature and skip token introspection in client credentials flow. The JWKS endpoint is parsed from the discovery document.                                                                                                                                                                                                                                                                                                                          |
| use\_pkce                                         | boolean        | False    | false                 |                                   | If true, use the Proof Key for Code Exchange (PKCE) for Authorization Code Flow as defined in [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636).                                                                                                                                                                                                                                                                                                                                                                |
| token\_signing\_alg\_values\_expected             | string         | False    |                       |                                   | Algorithm used for signing JWT, such as `RS256`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| set\_access\_token\_header                        | boolean        | False    | true                  |                                   | If true, set the access token in a request header. By default, the `X-Access-Token` header is used.                                                                                                                                                                                                                                                                                                                                                                                                                     |
| access\_token\_in\_authorization\_header          | boolean        | False    | false                 |                                   | If true and if `set_access_token_header` is also true, set the access token in the `Authorization` header.                                                                                                                                                                                                                                                                                                                                                                                                              |
| set\_id\_token\_header                            | boolean        | False    | true                  |                                   | If true and if the ID token is available, set the value in the `X-ID-Token` request header.                                                                                                                                                                                                                                                                                                                                                                                                                             |
| set\_userinfo\_header                             | boolean        | False    | true                  |                                   | If true and if user info data is available, set the value in the `X-Userinfo` request header.                                                                                                                                                                                                                                                                                                                                                                                                                           |
| set\_refresh\_token\_header                       | boolean        | False    | false                 |                                   | If true and if the refresh token is available, set the value in the `X-Refresh-Token` request header.                                                                                                                                                                                                                                                                                                                                                                                                                   |
| session                                           | object         | False    |                       |                                   | Session configuration used when `bearer_only` is `false` and the Plugin uses Authorization Code flow.                                                                                                                                                                                                                                                                                                                                                                                                                   |
| session.secret                                    | string         | True     |                       | 16 or more characters             | Key used for session encryption and HMAC operation when `bearer_only` is `false`.                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| session.cookie                                    | object         | False    |                       |                                   | Cookie configurations.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| session.cookie.lifetime                           | integer        | False    | 3600                  |                                   | Cookie lifetime in seconds.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| session\_contents                                 | object         | False    |                       |                                   | Session content configurations. If unconfigured, all data will be stored in the session.                                                                                                                                                                                                                                                                                                                                                                                                                                |
| session\_contents.access\_token                   | boolean        | False    |                       |                                   | If true, store the access token in the session.                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| session\_contents.id\_token                       | boolean        | False    |                       |                                   | If true, store the ID token in the session.                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| session\_contents.enc\_id\_token                  | boolean        | False    |                       |                                   | If true, store the encrypted ID token in the session.                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| session\_contents.user                            | boolean        | False    |                       |                                   | If true, store the user info in the session.                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| unauth\_action                                    | string         | False    | auth                  | \["auth","deny","pass"]           | Action for unauthenticated requests. When set to `auth`, redirect to the authentication endpoint of the OpenID provider. When set to `pass`, allow the request without authentication. When set to `deny`, return 401 unauthenticated responses rather than start the authorization code grant flow.                                                                                                                                                                                                                    |
| proxy\_opts                                       | object         | False    |                       |                                   | Configurations for the proxy server that the OpenID provider is behind.                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| proxy\_opts.http\_proxy                           | string         | False    |                       |                                   | Proxy server address for HTTP requests, such as `http://<proxy_host>:<proxy_port>`.                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| proxy\_opts.https\_proxy                          | string         | False    |                       |                                   | Proxy server address for HTTPS requests, such as `http://<proxy_host>:<proxy_port>`.                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| proxy\_opts.http\_proxy\_authorization            | string         | False    |                       | Basic \[base64 username:password] | Default `Proxy-Authorization` header value to be used with `http_proxy`. Can be overridden with custom `Proxy-Authorization` request header.                                                                                                                                                                                                                                                                                                                                                                            |
| proxy\_opts.https\_proxy\_authorization           | string         | False    |                       | Basic \[base64 username:password] | Default `Proxy-Authorization` header value to be used with `https_proxy`. Cannot be overridden with custom `Proxy-Authorization` request header since with HTTPS, the authorization is completed when connecting.                                                                                                                                                                                                                                                                                                       |
| proxy\_opts.no\_proxy                             | string         | False    |                       |                                   | Comma separated list of hosts that should not be proxied.                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| authorization\_params                             | object         | False    |                       |                                   | Additional parameters to send in the request to the authorization endpoint.                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| client\_rsa\_private\_key                         | string         | False    |                       |                                   | Client RSA private key used to sign JWT for authentication to the OP. Required when `token_endpoint_auth_method` is `private_key_jwt`.                                                                                                                                                                                                                                                                                                                                                                                  |
| client\_rsa\_private\_key\_id                     | string         | False    |                       |                                   | Client RSA private key ID used to compute a signed JWT. Optional when `token_endpoint_auth_method` is `private_key_jwt`.                                                                                                                                                                                                                                                                                                                                                                                                |
| client\_jwt\_assertion\_expires\_in               | integer        | False    | 60                    |                                   | Life duration of the signed JWT for authentication to the OP, in seconds. Used when `token_endpoint_auth_method` is `private_key_jwt` or `client_secret_jwt`.                                                                                                                                                                                                                                                                                                                                                           |
| renew\_access\_token\_on\_expiry                  | boolean        | False    | true                  |                                   | If true, attempt to silently renew the access token when it expires or if a refresh token is available. If the token fails to renew, redirect user for re-authentication.                                                                                                                                                                                                                                                                                                                                               |
| access\_token\_expires\_in                        | integer        | False    |                       |                                   | Lifetime of the access token in seconds if no `expires_in` attribute is present in the token endpoint response.                                                                                                                                                                                                                                                                                                                                                                                                         |
| refresh\_session\_interval                        | integer        | False    |                       |                                   | Time interval to refresh user ID token without requiring re-authentication. When not set, it will not check the expiration time of the session issued to the client by the gateway. If set to 900, it means refreshing the user's id\_token (or session in the browser) after 900 seconds without requiring re-authentication.                                                                                                                                                                                          |
| iat\_slack                                        | integer        | False    | 120                   |                                   | Tolerance of clock skew in seconds with the `iat` claim in an ID token.                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| accept\_none\_alg                                 | boolean        | False    | false                 |                                   | Set to true if the OpenID provider does not sign its ID token, such as when the signature algorithm is set to `none`.                                                                                                                                                                                                                                                                                                                                                                                                   |
| accept\_unsupported\_alg                          | boolean        | False    | true                  |                                   | If true, ignore ID token signature to accept unsupported signature algorithm.                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| access\_token\_expires\_leeway                    | integer        | False    | 0                     |                                   | Expiration leeway in seconds for access token renewal. When set to a value greater than 0, token renewal will take place the set amount of time before token expiration. This avoids errors in case the access token just expires when arriving to the resource server.                                                                                                                                                                                                                                                 |
| force\_reauthorize                                | boolean        | False    | false                 |                                   | If true, execute the authorization flow even when a token has been cached.                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| use\_nonce                                        | boolean        | False    | false                 |                                   | If true, enable nonce parameter in authorization request.                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| revoke\_tokens\_on\_logout                        | boolean        | False    | false                 |                                   | If true, notify the authorization server a previously obtained refresh or access token is no longer needed at the revocation endpoint.                                                                                                                                                                                                                                                                                                                                                                                  |
| jwk\_expires\_in                                  | integer        | False    | 86400                 |                                   | Expiration time for JWK cache in seconds.                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| jwt\_verification\_cache\_ignore                  | boolean        | False    | false                 |                                   | If true, force re-verification for a bearer token and ignore any existing cached verification results.                                                                                                                                                                                                                                                                                                                                                                                                                  |
| cache\_segment                                    | string         | False    |                       |                                   | Optional name of a cache segment, used to separate and differentiate caches used by token introspection or JWT verification.                                                                                                                                                                                                                                                                                                                                                                                            |
| introspection\_interval                           | integer        | False    | 0                     |                                   | TTL of the cached and introspected access token in seconds. The default value is 0, which means this option is not used and the Plugin defaults to use the TTL passed by expiry claim defined in `introspection_expiry_claim`. If `introspection_interval` is larger than 0 and less than the TTL passed by expiry claim defined in `introspection_expiry_claim`, use `introspection_interval`.                                                                                                                         |
| introspection\_expiry\_claim                      | string         | False    | exp                   |                                   | Name of the expiry claim, which controls the TTL of the cached and introspected access token.                                                                                                                                                                                                                                                                                                                                                                                                                           |
| introspection\_addon\_headers                     | array\[string] | False    |                       |                                   | Used to append additional header values to the introspection HTTP request. If the specified header does not exist in origin request, value will not be appended.                                                                                                                                                                                                                                                                                                                                                        |
| claim\_validator                                  | object         | False    |                       |                                   | JWT claim validation configurations.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| claim\_validator.issuer.valid\_issuers            | array\[string] | False    |                       |                                   | An array of trusted JWT issuers. If unconfigured, the issuer returned by discovery endpoint will be used. If both are unavailable, the issuer will not be validated.                                                                                                                                                                                                                                                                                                                                                    |
| claim\_validator.audience                         | object         | False    |                       |                                   | [Audience claim](https://openid.net/specs/openid-connect-core-1_0.html) validation configurations.                                                                                                                                                                                                                                                                                                                                                                                                                      |
| claim\_validator.audience.claim                   | string         | False    | aud                   |                                   | Name of the claim that contains the audience.                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| claim\_validator.audience.required                | boolean        | False    | false                 |                                   | If true, audience claim is required and the name of the claim will be the name defined in `claim`.                                                                                                                                                                                                                                                                                                                                                                                                                      |
| claim\_validator.audience.match\_with\_client\_id | boolean        | False    | false                 |                                   | If true, require the audience to match the client ID. If the audience is a string, it must exactly match the client ID. If the audience is an array of strings, at least one of the values must match the client ID. If no match is found, you will receive a `mismatched audience` error. This requirement is stated in the OpenID Connect specification to ensure that the token is intended for the specific client.                                                                                                 |
| claim\_schema                                     | object         | False    |                       |                                   | JSON schema of OIDC response claim. Example: `{"type":"object","properties":{"access_token":{"type":"string"}},"required":["access_token"]}` - validates that the response contains a required string field `access_token`.                                                                                                                                                                                                                                                                                             |

**Sample configuration**

Minimal setup that resolves the provider endpoints from the discovery document:

```json
{
  "openid-connect": {
    "client_id": "helix-gateway",
    "client_secret": "my-oidc-client-secret",
    "discovery": "https://idp.example.com/.well-known/openid-configuration"
  }
}
```

Bearer-only mode for API access, requiring specific scopes and introspecting access tokens:

```json
{
  "openid-connect": {
    "client_id": "helix-gateway",
    "client_secret": "my-oidc-client-secret",
    "discovery": "https://idp.example.com/.well-known/openid-configuration",
    "bearer_only": true,
    "required_scopes": ["read", "write"],
    "unauth_action": "deny"
  }
}
```

Authorization Code flow with browser sessions, redirect URI, and PKCE:

```json
{
  "openid-connect": {
    "client_id": "helix-gateway",
    "client_secret": "my-oidc-client-secret",
    "discovery": "https://idp.example.com/.well-known/openid-configuration",
    "scope": "openid email profile",
    "bearer_only": false,
    "redirect_uri": "/api/v1/redirect",
    "use_pkce": true,
    "session": {
      "secret": "my-16-char-session-secret"
    }
  }
}
```

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.digitalapi.ai/api-gateway/plugin-reference/plugins-authentication.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
