Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apisix-master-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ dependencies = {
"api7-lua-resty-jwt = 0.2.6-0",
"lua-resty-hmac-ffi = 0.06-1",
"lua-resty-cookie = 0.4.1-1",
"lua-resty-session = 4.1.5-1",
"lua-resty-session = 4.2.0-1",
"lua-resty-openapi-validator = 1.0.6-1",
"opentracing-openresty = 0.1-0",
"lua-resty-radixtree = 2.9.2-0",
"lua-protobuf = 0.5.3-1",
"lua-resty-openidc = 1.9.0-1",
"lua-resty-openidc = 1.9.1-1",
"lua-resty-saml = 0.2.6",
"luafilesystem = 1.8.0-1",
"nginx-lua-prometheus-api7 = 1.0.0-1",
Expand Down
52 changes: 51 additions & 1 deletion apisix/plugins/openid-connect.lua
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,33 @@ local schema = {
description = "keepalive timeout in milliseconds",
},
}
}
},
revocation = {
type = "string",
enum = {"redis"},
description = "Redis-backed revocation for cookie sessions.",
},
revocation_fail_mode = {
type = "string",
enum = {"open", "closed"},
Comment thread
Hockenba marked this conversation as resolved.
description =
"When the revocation store is unreachable, open treats the "
.. "session as not revoked and closed rejects open/destroy.",
},
revocation_cache_ttl = {
type = "integer",
minimum = 0,
Comment thread
Hockenba marked this conversation as resolved.
description =
"Worker-local TTL in seconds for successful revocation "
.. "lookups. 0 disables. Default is 5 in lua-resty-session.",
},
revocation_error_cache_ttl = {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Hockenba Hockenba Sep 16, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Still feel free to take a peak at to make sure that I implemented what was requested :)

type = "integer",
minimum = 0,
description =
"Worker-local TTL in seconds for revocation store errors. "
.. "0 disables. Default is 5 in lua-resty-session.",
},
},
required = {"secret"},
["if"] = {
Expand All @@ -305,6 +331,19 @@ local schema = {
["then"] = {
required = {"redis"},
},
allOf = {
{
["if"] = {
required = {"revocation"},
},
["then"] = {
required = {"redis"},
properties = {
storage = { const = "cookie" },
},
},
},
},
additionalProperties = false,
},
realm = {
Expand Down Expand Up @@ -1371,6 +1410,17 @@ function _M.rewrite(plugin_conf, ctx)
return 401
end

-- fail-closed only: resty.session appends the store error, so match
-- the prefix. Reject without destroying the cookie.
if core.string.find(err, "unable to check session revocation")
or core.string.find(err, "unable to mark session revoked") then
if session then
session:close()
end
core.log.error("OIDC session revocation store unavailable: ", err)
return 503
end

-- Recoverable authorization-callback failures: a stale state
-- (replayed or pruned callback), or the ID provider redirecting
-- back with error=temporarily_unavailable, e.g. Keycloak after
Expand Down
28 changes: 27 additions & 1 deletion docs/en/latest/plugins/openid-connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@ The `openid-connect` Plugin supports the integration with [OpenID Connect (OIDC)
| session.absolute_timeout | integer | False | | | Absolute session lifetime in seconds. Forwarded to lua-resty-session as `absolute_timeout`. |
| session.cookie.lifetime | integer | False | | | Deprecated. Mapped to `session.absolute_timeout` at runtime when `absolute_timeout` is not set. Use `session.absolute_timeout` instead. |
| session.storage | string | False | cookie | ["cookie", "redis"] | Session storage method. |
| session.redis | object | False | | | Redis configuration when `storage` is `redis`. |
| session.revocation | string | False | | ["redis"] | Session revocation backend. Set to `redis` to enable revocation for cookie sessions. Requires `session.redis` and cannot be used when `session.storage` is `redis`. |
| session.revocation_fail_mode | string | False | open | ["open", "closed"] | When the revocation store is unreachable, `open` treats the session as not revoked, while `closed` rejects session open and destroy operations. |
| session.revocation_cache_ttl | integer | False | | | Worker-local TTL in seconds for successful revocation lookups. `0` disables. lua-resty-session defaults to `5`. |
| session.revocation_error_cache_ttl | integer | False | | | Worker-local TTL in seconds for revocation store errors. `0` disables. lua-resty-session defaults to `5`. |
| session.redis | object | False | | | Redis connection. Required when `storage` is `redis`, or when `revocation` is `redis`. |
| session.redis.host | string | False | 127.0.0.1 | | Redis host. |
| session.redis.port | integer | False | 6379 | | Redis port. |
| session.redis.username | string | False | | | Redis username. |
Expand Down Expand Up @@ -354,6 +358,28 @@ spec:

See [Implement Authorization Code Grant](../tutorials/keycloak-oidc.md#implement-authorization-code-grant) for a complete example to use the `openid-connect` Plugin to integrate with Keycloak using the authorization code flow.

### Cookie Session Revocation

Cookie sessions are stored by the client and cannot normally be invalidated individually by APISIX. To enable server-side revocation, set `session.revocation` to `redis` and configure a Redis denylist:

```json
"session": {
"secret": "your-session-secret-min-16-chars",
"storage": "cookie",
"revocation": "redis",
"revocation_fail_mode": "closed",
"revocation_cache_ttl": 5,
"revocation_error_cache_ttl": 1,
"redis": {
"host": "127.0.0.1",
"port": 6379,
"prefix": "oidc:session:"
}
}
```

`revocation_fail_mode` defaults to `open`, which continues accepting sessions if the revocation store is unavailable. Use `closed` to reject session open and destroy operations instead. `revocation_cache_ttl` is the worker-local TTL for successful lookups; `revocation_error_cache_ttl` is the TTL for store errors. Omit `revocation` to leave cookie-session revocation disabled.

### Authorization Code Flow with PAR and DPoP

To use Pushed Authorization Requests (PAR), set `par.enabled` to `true`. If `par.endpoint` is not configured, the Plugin uses the PAR endpoint from the well-known discovery document.
Expand Down
28 changes: 27 additions & 1 deletion docs/zh/latest/plugins/openid-connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ import TabItem from '@theme/TabItem';
| session.absolute_timeout | integer | 否 | | | 会话绝对生存时间(秒)。作为 `absolute_timeout` 透传到 lua-resty-session。 |
| session.cookie.lifetime | integer | 否 | | | 已弃用。当未设置 `session.absolute_timeout` 时,运行时会将该值映射到 `session.absolute_timeout`。请改用 `session.absolute_timeout`。 |
| session.storage | string | 否 | cookie | ["cookie", "redis"] | 会话存储方式。 |
| session.redis | object | 否 | | | `storage` 为 `redis` 时的 Redis 配置。 |
| session.revocation | string | 否 | | ["redis"] | 会话吊销后端。设置为 `redis` 可为 Cookie 会话启用吊销功能。必须配置 `session.redis`,且不能在 `session.storage` 为 `redis` 时使用。 |
| session.revocation_fail_mode | string | 否 | open | ["open", "closed"] | 当吊销存储不可用时,`open` 将会话视为未吊销,`closed` 则拒绝打开和销毁会话。 |
| session.revocation_cache_ttl | integer | 否 | | | 成功吊销查询的 worker 本地缓存 TTL(秒)。`0` 禁用。lua-resty-session 默认为 `5`。 |
| session.revocation_error_cache_ttl | integer | 否 | | | 吊销存储错误的 worker 本地缓存 TTL(秒)。`0` 禁用。lua-resty-session 默认为 `5`。 |
| session.redis | object | 否 | | | Redis 连接配置。当 `storage` 为 `redis`,或 `revocation` 为 `redis` 时必填。 |
| session.redis.host | string | 否 | 127.0.0.1 | | Redis 主机。 |
| session.redis.port | integer | 否 | 6379 | | Redis 端口。 |
| session.redis.username | string | 否 | | | Redis 用户名。 |
Expand Down Expand Up @@ -353,6 +357,28 @@ spec:

详见[实现授权码授权](../tutorials/keycloak-oidc.md#实现-authorization-code-grant),获取使用 `openid-connect` 插件与 Keycloak 集成并使用授权码流程的完整示例。

### Cookie 会话吊销

Cookie 会话存储在客户端,APISIX 通常无法单独将其失效。要启用服务端吊销,请将 `session.revocation` 设置为 `redis` 并配置 Redis 拒绝列表:

```json
"session": {
"secret": "your-session-secret-min-16-chars",
"storage": "cookie",
"revocation": "redis",
"revocation_fail_mode": "closed",
"revocation_cache_ttl": 5,
"revocation_error_cache_ttl": 1,
"redis": {
"host": "127.0.0.1",
"port": 6379,
"prefix": "oidc:session:"
}
}
```

`revocation_fail_mode` 默认为 `open`,即吊销存储不可用时继续接受会话。使用 `closed` 则会拒绝打开和销毁会话。`revocation_cache_ttl` 是成功查询的 worker 本地 TTL;`revocation_error_cache_ttl` 是存储错误的 TTL。省略 `revocation` 即不启用 Cookie 会话吊销。

### 使用 PAR 和 DPoP 的授权码流程

如需使用 Pushed Authorization Requests (PAR),请将 `par.enabled` 设置为 `true`。如果未配置 `par.endpoint`,插件将使用 well-known 发现文档中的 PAR 端点。
Expand Down
Loading
Loading