Catalyst-Plugin-OpenIDConnect
view release on metacpan or search on metacpan
CHANGELOG.md view on Meta::CPAN
case verified to leave those fields absent.
- **`t/04_store_redis.t`** (updated) â `MockRedis` gained a `getdel` method;
tests confirm `GETDEL` is used (not `del`), consume returns data, second
consume returns `undef`. Added PKCE round-trip tests through JSON
serialization.
- **`t/06_pkce.t`** (new, 11 tests) â unit tests for `_verify_pkce`: correct
verifier/challenge pair accepted; wrong verifier rejected; verifier too short
(< 43) rejected; verifier too long (> 128) rejected; verifier with disallowed
characters rejected; `undef` verifier rejected; `undef` challenge rejected;
minimum (43-char) and maximum (128-char) length cases accepted; all unreserved
char types accepted; tampered challenge rejected.
### Documentation
- **`API_REFERENCE.md`** â Authorization endpoint parameter table updated with
`code_challenge` (Conditional) and `code_challenge_method` rows; token
endpoint authorization-code grant table updated with `code_verifier`
(Conditional) row and `client_secret` changed from Required to Conditional.
New "PKCE-Protected Authorization Code Flow" example section added.
- **`IMPLEMENTATION_GUIDE.md`** â Authorization Code Flow steps updated with
PKCE parameters; State Store module docs updated with accurate signatures and
atomic-operation note; login action example updated with safe `back`
validation; new PKCE subsection added under Security Considerations.
- **`QUICKSTART.md`** â Login action example updated with validated `back`
redirect pattern.
---
## [0.04] - 2026-04-29 (Security Fix: Open Redirect in Logout Endpoint)
### Security
- **CRIT-1 fixed â Open Redirect in logout endpoint** (`Controller::Root`,
`Utils::JWT`). The `post_logout_redirect_uri` parameter was previously
forwarded without any validation, allowing an attacker to redirect victims to
an arbitrary external URL after logout (phishing / credential harvesting).
The logout flow now enforces the following rules, in line with OpenID Connect
RP-Initiated Logout 1.0:
1. `post_logout_redirect_uri` is rejected with `invalid_request` unless
`id_token_hint` is also supplied.
2. The hint token's RSA signature is verified to confirm it was genuinely
issued by this server. Expiry is intentionally **not** checked â hint
tokens are frequently expired at logout time by design.
3. The `aud` claim of the verified hint identifies the requesting client.
The `post_logout_redirect_uri` is then compared by **exact string match**
against that client's registered `post_logout_redirect_uris` list.
Prefix matching and host-only matching are not permitted.
4. Any mismatch returns an `invalid_request` OAuth error; no redirect is
issued.
5. When a redirect is permitted, the optional `state` parameter is appended
verbatim to the redirect URI as required by the specification.
### Added
- **`JWT::decode_id_token_hint($token)`** â new method on
`Catalyst::Plugin::OpenIDConnect::Utils::JWT`. Verifies the token signature
against the configured public key and returns the decoded claims hashref, or
`undef` if the token is malformed or the signature is invalid. Distinct from
`verify_token` in that it does not reject expired tokens.
- **`Controller::Root::_allowed_post_logout_uris($client)`** â private helper
that normalises the `post_logout_redirect_uris` client config field from
either an arrayref (YAML/JSON config) or a whitespace-delimited string
(Config::General-style config) into a flat list of URIs.
- **`post_logout_redirect_uris` client config key** â each client may now
declare a list of permitted post-logout redirect URIs. This key is required
for clients that use `post_logout_redirect_uri` at the logout endpoint.
### Tests
- **`t/05_logout.t`** (new, 19 tests) â covers `decode_id_token_hint` for valid
tokens, expired tokens, tampered tokens, wrong-key tokens, and structurally
invalid JWTs; and `_allowed_post_logout_uris` for arrayref config, string
config, missing config, and exact-match security semantics (prefix-of-registered
and extended-path attacks).
### Documentation
- **`API_REFERENCE.md`** â Logout endpoint section rewritten with updated
parameter table (marking `id_token_hint` as conditionally required), security
note on exact-match validation, split request/response examples, full error
response examples, and a client registration code snippet.
- **`README.md`** â Client configuration reference updated with the new
`post_logout_redirect_uris` field.
- **`IMPLEMENTATION_GUIDE.md`** â Client configuration example and field list
updated with `post_logout_redirect_uris`.
- **`DEPLOYMENT.md`** â Production `catalyst.conf` example updated with
`post_logout_redirect_uris`.
- **`QUICKSTART.md`** â Quick-start Perl config example updated with
`post_logout_redirect_uris`.
- **`example/app.pl`** â Both example clients now include
`post_logout_redirect_uris`.
---
## [0.03] - 2026-04-24 (FastCGI / Multi-Process Store Support)
### Added
- **Catalyst::Plugin::OpenIDConnect::Role::Store** - New Moose role defining the
pluggable store interface. Any store backend must `with` this role and implement
three methods: `create_authorization_code`, `get_authorization_code`,
`consume_authorization_code`. This decouples the plugin from a specific
backend implementation.
- **Catalyst::Plugin::OpenIDConnect::Utils::Store::Redis** - Redis-backed store
implementation for multi-process deployments (FastCGI, pre-forking servers).
- Stores authorization codes in Redis with native TTL expiry via `SETEX`
- Lazy Redis connection (opened after `fork()` so each worker has its own socket)
- Supports `Redis::Fast` (preferred) or `Redis` client, auto-detected at runtime
- Configurable key prefix for namespace isolation on shared Redis instances
- Configurable code TTL (default 600 s)
- Optional Redis `AUTH` password support
- Blessed user objects serialised via `convert_blessed` JSON encoding
- **Configurable store class in plugin setup** - `Plugin::OpenIDConnect` config
( run in 1.012 second using v1.01-cache-2.11-cpan-995e09ba956 )