Plugin
Identity expiry guard
RegulusIdentityExpiryGuard Short-lived-token enforcement. Rejects tool calls whose Principal's credentials have expired and emits a structured rejection event with the cause. Crucial when agents run hours-long jobs.
What it does #
The identity-expiry guard ensures the Principal’s credentials are
still valid at the moment of every tool dispatch. For a short
interactive agent invocation this is rarely a problem. For a
long-running agent — overnight batch, a multi-hour async workflow,
an agent running inside a sub-agent loop — the original token can
expire mid-flight.
Why it matters #
Regulated buyers run OIDC tokens with TTLs of 15 minutes to an hour.
A 4-hour agent invocation that started at 02:00 will hit token expiry
around 02:15–03:00. Without enforcement, the agent keeps calling
tools using the original sub claim long after the IdP has rotated
the user out of the role. Compliance evidence becomes a fiction.
How it works #
The plugin reads the expires_at claim from the active Principal
and compares against the current wall-clock at every tool dispatch.
If expiry has passed, the call is denied with IDENTITY_EXPIRED. The
audit chain captures the rejection with the expired Principal and
the wall-clock difference.
Refresh strategy #
The plugin does not refresh tokens itself — that’s the IdentityAdapter’s
job. Best practice: pair this plugin with an IdentityAdapter
implementation that refreshes ahead of expiry (e.g.
SpringSecurityOAuth2IdentityAdapter’s built-in refresh). For agents
that run beyond the longest available refresh window, configure a
RolloverPrincipal that delegates to a service-account credential
with a documented hand-off in the audit chain.
Configuration #
regulus:
identity-expiry-guard:
enabled: true
grace-seconds: 30 # allow N seconds of clock skew
refusal-decision: DENY # alternative: REQUIRE_HITL
Status today #
The plugin is shipped in v0.2.0 but must be registered explicitly
in RegulusAdkAutoConfiguration — it’s not yet auto-wired alongside
the other plugins. The fix is a one-line registration:
@Bean
public RegulusIdentityExpiryGuard regulusIdentityExpiryGuard() {
return new RegulusIdentityExpiryGuard();
}
Auto-wiring lands in v0.3.