Not just at login. Every request.
A validated JWT only proves a token was legitimate at issuance. Continuous authorization re-checks the agent's current state on every single proxied request, so a revocation, an admin kill switch, or a stale session takes effect immediately — not whenever the token happens to expire. This is what turns ModGate from an auth layer into a security layer.
1. Live agent-state checks (automatic)
This runs on every request through the MCP proxy — nothing to configure. Before a tool call is forwarded to your server, ModGate checks:
| Check | Rejected if |
|---|---|
| Agent exists | The agent identity referenced by the token has been deleted |
| Agent is active | The agent has been revoked |
| Agent unexpired | The agent identity's own expiresAt has passed |
| Not force-reauthed | An admin triggered the kill switch after this token was issued |
| Within reverify window | The session has outlived its configured reverification interval |
These same checks also apply to /oauth/introspect and /oauth/delegate, so third-party resource servers and orchestrator agents get identical, live-checked behavior — not a weaker version of it.
2. What a failed check looks like
HTTP 401 or 403
{
"error": "reauthorization_required",
"error_description": "Session exceeded the 900s continuous-authorization window. Obtain a new token.",
"reason": "reverification_interval_exceeded"
}| reason | Status | Fix |
|---|---|---|
| agent_not_found | 403 | Agent identity was deleted — this is unrecoverable |
| agent_revoked | 403 | Agent was revoked — create a new agent identity |
| agent_expired | 403 | Agent identity's expiresAt has passed — extend or recreate it |
| reauth_forced | 401 | Complete a new authorization_code exchange, not just a refresh |
| reverification_interval_exceeded | 401 | Refresh the token — a normal, expected occurrence, not an error state |
Every rejection also fires a session.reauth_required webhook and an audit log entry — see Webhooks.
3. Tune the policy per agent
Defaults are a 900-second (15 minute) reverify window and a 120-calls-per-minute rate ceiling. Override either per agent:
PATCH https://api.modgate.io/agents/{tenantId}/{agentId}/continuous-auth
X-ModGate-API-Key: YOUR_API_KEY
Content-Type: application/json
{
"reverifyIntervalSeconds": 120,
"maxCallsPerMinute": 30
}
# Response — merges with any existing policy:
{
"id": "agent_xyz789",
"continuousAuth": {
"reverifyIntervalSeconds": 120,
"maxCallsPerMinute": 30
},
...
}reverifyIntervalSeconds below your access token's own TTL for your highest-privilege agents (admin-scoped, delegation-capable orchestrators) — it forces a fresh token more often than the token would naturally expire on its own.4. Admin kill switch — force-reauth
For incident response: invalidate every outstanding token for an agent right now, without waiting for its next scheduled check or its token to expire.
POST https://api.modgate.io/agents/{tenantId}/{agentId}/force-reauth
X-ModGate-API-Key: YOUR_API_KEY
# Response:
{
"agentId": "agent_xyz789",
"tenantId": "org_...",
"forceReauthAfter": 1752624000000,
"message": "All outstanding tokens for this agent are now considered stale and will be rejected on next use."
}Unlike revocation, force-reauth doesn't deactivate the agent — it just invalidates every token issued before this moment, including outstanding refresh tokens. The agent can resume working immediately once it completes a fresh authorization_code exchange. Use this when you're not sure an agent is compromised but want it to prove itself again; use revocation when you're sure.
5. See every agent's posture at a glance
GET https://api.modgate.io/sessions/{tenantId}
X-ModGate-API-Key: YOUR_API_KEY
# Response:
{
"tenantId": "org_...",
"sessions": [
{
"agentId": "agent_xyz789",
"name": "billing-bot",
"active": true,
"reverifyIntervalSeconds": 900,
"maxCallsPerMinute": 120,
"reauthForced": false,
"forceReauthAfter": null
}
],
"total": 1
}Useful for a dashboard panel, or a quick sanity check before an incident call: which agents currently have a forced reauth in effect, and what policy each is running under.
6. Rate-anomaly detection
Independent of the checks above, every proxied call also counts against a rolling 60-second per-agent window. Exceed maxCallsPerMinute and the call is rejected with 429 rate_limited, and an anomaly.rate_exceeded webhook fires — a compromised or malfunctioning agent burning through calls gets caught immediately, not whenever someone happens to check the audit log.
Questions? We answer personally.
[email protected] →