# The 28-Hour Bargain: How Continuous Access Evaluation Made Long-Lived Tokens Safe

> How Microsoft Entra Continuous Access Evaluation lets access tokens safely live up to 28 hours by pairing them with a near-real-time revocation channel.

*Published: 2026-05-30*
*Canonical: https://paragmali.com/blog/the-28-hour-bargain-how-continuous-access-evaluation-made-lo*
*License: CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/*

---
<TLDR>
**Microsoft Entra Continuous Access Evaluation (CAE) lets access tokens safely live up to 28 hours.** It works by maintaining a push-subscription channel between Entra and Microsoft 365 resource providers, so that when a user is disabled, has their password reset, or has MFA enabled, the resource provider rejects the next request with a `401` and a claims challenge -- typically within 15 minutes for critical events, instantly for IP-location changes [@ms-cae-concept]. The same pattern was standardized by the OpenID Foundation on September 2, 2025 as SSF 1.0, CAEP 1.0, and RISC 1.0 Final Specifications [@openid-three-final-specs], opening the door to vendor-neutral cross-SaaS revocation. CAE does **not** solve token theft (use DPoP for that) and does **not** cover Microsoft Defender for Endpoint or Intune as resource providers (they are signal sources into Conditional Access, not CAE consumers).
</TLDR>

## 1. Your Fired Employee Is Still Reading Email

09:00 Tuesday. The administrator disables the account at 09:01. At 09:23, the ex-employee's open Outlook for the Web tab refreshes -- and pulls down new mail. This is not a bug. This is RFC 6749 working exactly as designed. Until Microsoft Entra shipped a fix that took ten years and three standards bodies -- the IETF, the OpenID Foundation, and NIST -- to develop, the access token that user held at 09:00 stayed cryptographically valid until 10:00 at the latest, and there was nothing [Conditional Access](/blog/who-decided-this-token-is-good-a-field-guide-to-conditional-/) could do about it [@rfc-6749].

The window has a name now. It did not, for most of cloud identity's history. Microsoft's own documentation calls it "the lag between when conditions change for a user, and when policy changes are enforced" [@ms-cae-concept]. Between sign-in (Conditional Access territory) and the next token refresh (refresh-token territory) sits a stretch of time in which Conditional Access decisions have no enforcement surface. That stretch ranged from 60 minutes to 24 hours, depending on tenant configuration. For every OAuth 2.0 deployment from 2012 onward, this was the security debt the industry carried.

> **Note:** "Microsoft Entra ID" is the rebranded name for what most engineers learned as "Azure Active Directory" or "Azure AD." Microsoft announced the rename in July 2023 [@ms-entra-rename-2023]; the underlying service, tenants, app registrations, and APIs are unchanged. Throughout this article, "Entra" and the older "Azure AD" refer to the same identity platform.

This article explains the engineering pattern that lets a Microsoft 365 tenant do two things that look contradictory at the same time: extend access-token lifetime from 1 hour to up to 28 hours, *and* revoke a disabled user's session in under 15 minutes [@ms-cae-concept]. The reconciling idea is a near-real-time push channel between the identity provider (Entra) and a small set of cooperating resource providers. When you can revoke a token in minutes rather than waiting for it to expire, expiry stops doing the security work, and the token can live as long as the user actually needs it.

<Definition term="Continuous Access Evaluation (CAE)">
Microsoft Entra's push-subscription channel between the identity provider and cooperating resource providers (Exchange Online, SharePoint Online, Teams, and Microsoft Graph). CAE lets a resource provider revoke an already-issued access token in near-real-time -- up to 15 minutes for critical events, instantly for IP-location changes -- without waiting for the token to expire [@ms-cae-concept].
</Definition>

The trade has a price. The 15-minute critical-event service-level objective is the price the channel pays for fanning out events across hyperscale Microsoft 365 infrastructure. Sub-second revocation is possible -- other vendors demonstrate it at smaller scales -- but at Exchange-Online volume, 15 minutes is the engineering economics. We will earn that number by Section 8.

For now: the OAuth 2.0 designers knew about this gap when they wrote RFC 6749 in 2012. They chose it on purpose. To see why, and to see why the obvious patches all failed, we have to walk back to the moment the trade was made.

## 2. The Static-Expiry Compromise

In October 2012, Dick Hardt of Microsoft published RFC 6749 -- *The OAuth 2.0 Authorization Framework* -- as the editor of record for an IETF working group that had spent five years arguing about it [@rfc-6749]. Section 1.4 carries one of the most consequential adjectives in cloud-identity history. Access tokens, it says, are credentials "usually with a short lifetime" used by the client to access a protected resource. The word *usually* is doing heavy lifting. Nothing in the protocol enforces it. Nothing in the protocol provides revocation. Nothing in the protocol stops a server from issuing 24-hour bearer tokens that, once minted, stay cryptographically valid until they expire on their own.

This was a deliberate trade. To see why it was rational, remember what came before.

### Web Access Management: the model OAuth replaced

<Definition term="Web Access Management (WAM)">
The pre-2012 enterprise-identity pattern in which every protected HTTP request synchronously queried a central policy decision point. Strength: instant revocation, because every request consulted authoritative state. Weakness: a chatty bottleneck that did not scale to cloud volumes and could not federate trust across organizations.
</Definition>

Web Access Management dominated enterprise identity from the late 1990s into the early 2010s. Every protected HTTP request to a WAM-fronted application made a synchronous round-trip to a Policy Decision Point. The PDP held authoritative session and policy state. Revoke a user? The next request failed, immediately, because the PDP said no. No token-lifetime window. No gap between policy change and enforcement.

WAM was correct. WAM was also unworkable for the web that was coming. It did not scale: every request was a network hop. It did not federate: cross-organization SaaS meant the PDP could not live inside any one company's network. And it required every protected resource to participate in a single trust domain. By the time enterprises were running cross-organization SaaS at scale, the WAM model had run out of road.

The OAuth 2.0 authors made the opposite trade. Replace the chatty PDP round-trip with a self-contained signed bearer token -- a JWT the resource server validates locally. Validation becomes O(1) cryptographic verification with no round-trip. Throughput scales horizontally. Federation works, because the JWT carries its own attestation of the issuer. Revocation becomes...approximated. By expiry. The token is valid until it isn't, and you trust that the lifetime is short enough.

For a 2012 web of forum logins and consumer mashups, "short enough" was a defensible answer. For a 2020 enterprise running compliance-bound SaaS across thousands of employees, it was not.

### The Zero Trust pressure

Two intellectual pressures forced the question. The first came from Google. In December 2014, Rory Ward and Betsy Beyer published *BeyondCorp: A New Approach to Enterprise Security* in USENIX `;login:` [@ward-beyer-2014-beyondcorp].<MarginNote>Beyer would later co-author *Site Reliability Engineering* (O'Reilly, 2016); BeyondCorp came out of the same Google culture of evidence-driven infrastructure engineering.</MarginNote> The argument was philosophical: a session is not a one-shot decision at sign-in. It is a time-varying authorization. Trust signals -- device posture, network location, behavioral risk -- change continuously, and the access decision should change with them. BeyondCorp was not a CAE implementation; it predates the term. But it planted the seed that login-time enforcement was not enough.

The second pressure was bureaucratic. In August 2020, NIST published Special Publication 800-207, *Zero Trust Architecture*, by Scott Rose, Oliver Borchert, Stu Mitchell, and Sean Connelly [@nist-sp-800-207]. SP 800-207 codified the BeyondCorp philosophy as U.S. federal guidance. One sentence made the engineering investment commercially rational: *"Authentication and authorization (both subject and device) are discrete functions performed before a session to an enterprise resource is established."* A federal mandate for continuous re-evaluation pushed every cloud vendor with U.S. government contracts to find an implementation. The gap RFC 6749 had left was now a procurement problem.

### A name for the problem

The third moment named the gap. On February 21, 2019, Atul Tulshibagwale, then an engineer at Google, published *Re-thinking federated identity with the Continuous Access Evaluation Protocol* on the Google Cloud blog [@tulshibagwale-2019-google-blog]. The post introduced a term -- CAEP -- and a framing: publish-and-subscribe between identity providers and resource providers, as a third option between WAM's per-request chattiness and OAuth's fire-and-forget expiry. We return to Tulshibagwale's actual proposal in Section 5. For now what matters: 2019 was the year the industry got a vocabulary for a problem it had been carrying for seven years.

<Sidenote>The OpenID Foundation working group that grew out of Tulshibagwale's proposal was originally chartered as the *Shared Signals & Events* (SSE) working group. It was renamed *Shared Signals* in subsequent years, but older industry write-ups from 2020-2022 still use the SSE abbreviation [@idsalliance-2022-11-cae].</Sidenote>

<Mermaid caption="The 13-year arc from RFC 6749 to the OpenID Shared Signals Final Specifications.">
gantt
    title CAE and Shared Signals timeline (2012-2025)
    dateFormat YYYY-MM
    axisFormat %Y
    section IETF standards
    RFC 6749 OAuth 2.0           :done, a1, 2012-10, 30d
    RFC 7009 Token Revocation    :done, a2, 2013-08, 30d
    RFC 7662 Token Introspection :done, a3, 2015-10, 30d
    RFC 8417 SET                 :done, a4, 2018-07, 30d
    RFC 8935 SET Push            :done, a5, 2020-11, 30d
    RFC 8936 SET Poll            :done, a6, 2020-11, 30d
    section Zero Trust thinking
    BeyondCorp paper             :done, b1, 2014-12, 30d
    NIST SP 800-207 Final        :done, b2, 2020-08, 30d
    section CAEP origin and OIDF
    Tulshibagwale CAEP post      :done, c1, 2019-02, 30d
    OIDF Shared Signals WG       :done, c2, 2019-09, 30d
    SSF 1.0 CAEP 1.0 RISC 1.0    :done, c3, 2025-09, 30d
    section Microsoft Entra CAE
    Limited preview Weinert      :done, d1, 2020-04, 30d
    Expanded preview Simons      :done, d2, 2020-10, 30d
    General Availability         :done, d3, 2022-01, 30d
</Mermaid>

The OAuth 2.0 designers traded revocation latency for throughput on purpose [@rfc-6749]. Once that gap proved unacceptable, three obvious patches were tried. None of them worked. To see *why* none of them worked is to understand the negative space CAE was designed to fill.

## 3. Three Patches, Three Failures

Between 2013 and the late 2010s, the OAuth community published three patches for RFC 6749's revocation gap. Each was rationally adopted; each was rationally abandoned at hyperscale. This section is the genealogy of those failures, because what each one got wrong defines the shape of the design that finally worked.

### Patch 1: RFC 7009 -- the `/revoke` endpoint (August 2013)

In August 2013, Torsten Lodderstedt of Deutsche Telekom, Stefanie Dronia, and Marius Scurtescu of Google published RFC 7009, *OAuth 2.0 Token Revocation* [@rfc-7009]. The contribution was a standardized HTTP endpoint, `/revoke`, that a client could POST a token to in order to invalidate it. The mental model is the logout button: when a user signs out, the client tells the authorization server "I'm done with this token, please retire it."

The failure mode is in the threat model. RFC 7009 is *client-initiated*. The token holder asks for revocation. But the scenario that motivates CAE is precisely the one where the token holder is uncooperative. A fired employee will not POST their access token to `/revoke` on the way out the door. An attacker who has stolen a token will certainly not. The administrator on the other side cannot use the endpoint either, because they do not possess the bearer token.

Worse, RFC 7009's Implementation Note (Section 3) is candid about self-contained tokens: the only standardized recourse is "some (currently non-standardized) backend interaction between the authorization server and the resource server" when immediate revocation is desired [@rfc-7009]. Read that carefully. The spec admits there is no spec. The JWT in flight at the resource server is *cryptographically valid until it expires*. The authorization server can mark it revoked in a local database, but the resource server never asks. It validates the signature locally. The revocation event never crosses the wire.

RFC 7009 works for opaque tokens with a token-introspection back-channel. It does not, by itself, solve revocation for self-contained JWT bearers -- which by the mid-2010s were the dominant pattern in the cloud.

### Patch 2: RFC 7662 -- the `/introspect` endpoint (October 2015)

Two years later, in October 2015, Justin Richer published RFC 7662, *OAuth 2.0 Token Introspection* [@rfc-7662]. The mechanism: on every request, the resource server calls a `/introspect` endpoint on the authorization server with the bearer token. The AS replies with the token's current state. If the token has been revoked, `/introspect` returns `active: false`, and the resource server denies the request.

This is correct. It also reintroduces the WAM bottleneck that OAuth was designed to escape.

For an AS serving billions of requests per day -- Microsoft Graph as one example, Google's IdP as another -- making `/introspect` the per-request critical path turns the authorization server into a synchronous dependency on every API call against every resource server in the estate. Latency adds up. Availability becomes shared. If the AS has a bad five minutes, every resource server has a bad five minutes simultaneously. The architecture OAuth bought with self-contained tokens -- resource server scales independently of AS -- gets traded back for exactly the WAM property that motivated OAuth's existence.

<Aside label="A parallel-path note on RFC 7662">
RFC 7662 introspection is alive and well. It remains the right choice for opaque-token systems and on-premises IdPs where the resource server count is small, the per-request latency budget is generous, and the AS is well within capacity. The criticism here is structural and only applies at hyperscale public-cloud volumes. RFC 7662 was not killed by RFC 7009 or by CAE; it is a parallel path that continues to serve a substantial fraction of the deployed OAuth surface.
</Aside>

### Patch 3: Make the token life so short revocation does not matter

The third patch was the obvious one. If you cannot revoke a token mid-life, make its life short. Issue access tokens with a minutes-long lifetime, the way early Microsoft experiments did. The revocation window collapses. Problem solved.

Microsoft tried it. The retrospective is unusually candid. On April 21, 2020, Alex Weinert, then Director of Identity Security at Microsoft, published *Moving towards real time policy and security enforcement* on the Azure Active Directory Identity Blog [@weinert-2020-04-real-time]. (The original lives at post ID 1276933 on Microsoft's tech community; the full body is preserved in Microsoft's Japanese translation on the jpazureid GitHub mirror [@jpazureid-blog-1-japanese].) The post names the failure mode in one sentence:

<PullQuote>
"We have experimented with the "blunt object" approach of reduced token lifetimes but found they can degrade user experiences and reliability without eliminating risks." -- Alex Weinert, Microsoft, April 21, 2020 [@weinert-2020-04-real-time]
</PullQuote>

Two things break. First, *user experience and reliability*. Every short-lifetime boundary forces every active client to round-trip the IdP for a fresh token. For Outlook, Teams, Word Online, OneDrive, and every other client an enterprise user has open at once, that is a wave of token requests per user per cycle. Multiplied by Microsoft 365 active users, the load profile creates real outages. Network blips that would otherwise be invisible surface as failed refreshes, with user-visible re-authentication prompts. Second, *it does not eliminate the risk*. A minutes-long window is still a window. A fired employee can read or exfiltrate a great deal of email in that window. You have paid the full user-experience cost and still left a non-trivial breach surface.

This was the third failure. The negative space across the three patches defines the shape any real solution has to take: it must be *server-initiated* (not RFC 7009), it must be *push-based* rather than per-request poll (not RFC 7662), and it must *separate revocation from expiry* so the IdP does not pay for every revocation with a refresh-load spike (not the short-lifetime patch). The three failures exhaust the surface of the obvious fix.

> **Note:** Each of the three patches fails for a different reason; together they rule out everything except server-initiated push subscription that decouples revocation from expiry.

If the patches all fail, the next move has to be architectural. The first published statement of that architecture was Atul Tulshibagwale's February 2019 Google blog post -- and the move he proposed is the one Microsoft would ship three years later.

## 4. Four Generations of Session Enforcement

Walk forward through the genealogy of session enforcement and the breakthrough in Section 5 stops looking like a stroke of genius and starts looking like the only move the design space had left. Four generations, each killed by a documented limit of the previous one.

### Generation 0: WAM (pre-2012)

Per-request synchronous round-trip to a Policy Decision Point. Instant revocation; chatty bottleneck; no federation. Killed by cloud-scale request rates and the rise of cross-organization SaaS, where the protected resource and the policy authority no longer lived in the same trust domain. WAM remains valuable in single-tenant enterprise contexts, but for the public-cloud API mesh it cannot scale.

### Generation 1: Static-expiry JWT (2012-2020)

Self-contained signed bearer tokens validated locally at the resource server. Revocation approximated by expiry per RFC 6749 [@rfc-6749]. Throughput scales; federation works; revocation is acceptable when the lifetime is short and the threat model is benign. Killed by (a) the fired-employee window, (b) the three failed Section 3 patches, and (c) the philosophical pressure from [Zero Trust](/blog/the-thirteen-months-that-made-zero-trust-unavoidable-windows/) to treat sessions as continuously re-evaluated.

### Generation 2: Microsoft CAE (limited preview April 2020, GA January 10, 2022)

The first production solution. Limited preview launched in April 2020 with Alex Weinert's *Moving towards real time policy and security enforcement* announcement [@weinert-2020-04-real-time]. Expanded public preview October 2020 [@simons-2020-10-expanded-preview; @vansurksum-2020-10-10]. General Availability January 10, 2022, announced by Alex Simons, Corporate VP for Program Management in the Microsoft Identity Division [@simons-2022-01-ga-rss].

The architecture is a private push-subscription channel between Entra and a small set of Microsoft 365 resource providers, with a wire-level handshake (the `claims` challenge) for telling the client to re-acquire a token reflecting new state. Access-token lifetime extends from the default 1 hour to up to 28 hours specifically for CAE-aware sessions [@ms-cae-concept]. We will unpack the mechanism in Section 5.

The Gen-2 limitation that motivated Gen 3: the wire format is *Microsoft-internal*. A SaaS vendor that wants the same revocation properties for its own resource provider cannot use Microsoft's CAE channel. The protocol does not federate.

### Generation 3: OpenID SSF 1.0 + CAEP 1.0 + RISC 1.0 (Final Specifications, September 2, 2025)

The OpenID Foundation generalized the Microsoft pattern into a vendor-neutral specification. On September 2, 2025, three Final Specifications were approved: the Shared Signals Framework 1.0 (SSF), the Continuous Access Evaluation Profile 1.0 (CAEP), and the Risk and Incident Sharing and Coordination 1.0 (RISC) [@openid-three-final-specs; @openid-sharedsignals-wg].

The wire envelope is IETF RFC 8417's Security Event Token (SET), published in July 2018 by Phil Hunt (Oracle), Michael Jones (Microsoft), William Denniss (Google), and Morteza Ansari (Cisco) [@rfc-8417]. A SET is a signed JWT carrying a single security event. The transport layer is RFC 8935 push (POST over TLS from transmitter to receiver) and RFC 8936 poll (recipient-initiated retrieval), both published November 2020 by Annabelle Backman and collaborators [@rfc-8935; @rfc-8936]. SSF defines the subscription model -- streams, subjects, transmitter and receiver metadata endpoints. CAEP and RISC define the *vocabulary* of events that can ride that envelope.

<Definition term="Security Event Token (SET)">
IETF RFC 8417's standardized signed-JWT envelope for transmitting security-relevant events between systems. Each SET carries exactly one event with a well-defined event-type URI; the envelope is signature-protected and timestamp-bearing. SET is the wire format underlying CAEP, SSF, and RISC, as well as Microsoft's internal CAE protocol [@rfc-8417].
</Definition>

<Sidenote>RFC 8417 was a cross-vendor IETF effort that pre-dated the OpenID Shared Signals working group by a year. Phil Hunt was at Oracle; Michael Jones at Microsoft; William Denniss at Google; Morteza Ansari at Cisco. The envelope-only design -- leaving event vocabularies to higher-layer profiles -- is what allowed both Microsoft's internal protocol and the OpenID profiles to converge on the same wire format without coordination [@rfc-8417].</Sidenote>

<Mermaid caption="The OpenID Shared Signals layer stack. RFC 8417 is the envelope; RFC 8935 and 8936 are transport; SSF is subscription; CAEP and RISC are event vocabularies.">
flowchart TD
    L4["Layer 4: Event vocabularies<br/>CAEP 1.0 (session) and RISC 1.0 (account)"]
    L3["Layer 3: Subscription and stream model<br/>OpenID SSF 1.0"]
    L2["Layer 2: HTTP transport<br/>RFC 8935 push, RFC 8936 poll"]
    L1["Layer 1: Signed event envelope<br/>RFC 8417 Security Event Token (SET)"]
    L4 --> L3
    L3 --> L2
    L2 --> L1
</Mermaid>

The generation chain has a documented engineering reason for each transition. The comparison matrix below pulls the essentials together.

| Approach | Year | Revocation latency | Strengths | Weaknesses |
|---|---|---|---|---|
| WAM (Gen 0) | pre-2012 | Instant | Authoritative state, instant enforcement | No federation, per-request bottleneck |
| Static-expiry JWT (Gen 1) | 2012-2020 | Up to token lifetime (1h-24h) | O(1) RP validation, federation works | No revocation; fired-employee window |
| Short-lifetime patch | mid-2010s | Minutes | Conceptually simple | Load amplification, window remains, UX degradation |
| RFC 7662 introspection | 2015 onward | Instant | Standardized, works for opaque tokens | AS becomes per-request critical path |
| Microsoft CAE (Gen 2) | 2020-2022 | Up to 15 min critical; instant IP | Push, decoupled from request rate, long tokens safe | Microsoft-internal protocol; tiny RP set |
| OpenID SSF/CAEP (Gen 3) | 2025 onward | Vendor-dependent | Vendor-neutral standard, cross-SaaS | Receiver adoption still early |

<Mermaid caption="The generation chain with the engineering reason each generation was superseded.">
flowchart LR
    G0["Gen 0: WAM<br/>per-request PDP"]
    G1["Gen 1: Static-expiry JWT<br/>RFC 6749 (2012)"]
    G2["Gen 2: Microsoft CAE<br/>GA January 2022"]
    G3["Gen 3: OpenID SSF and CAEP<br/>Final September 2025"]
    G0 -- "cloud scale and federation" --> G1
    G1 -- "fired-employee window, patches fail" --> G2
    G2 -- "Microsoft-only, no cross-SaaS" --> G3
</Mermaid>

Knowing the lineage is not knowing the trick. What is the actual mechanism CAE deploys -- the thing that turns this standards-history arc into a feature that ships and makes 28-hour tokens defensible? It has three parts, and once you see them together, you understand why long tokens are safe.

## 5. Subscription, Claims Challenge, Extended Lifetime

Three innovations, none new in isolation, all unprecedented in combination. This is the section where you see the trick.

Atul Tulshibagwale's 2019 framing names the move: "Our vision for continuous access evaluation is based on a publish-and-subscribe ('pub-sub') approach... It's complementary to federated or cert-based authentication... It's not as chatty as WAM... It doesn't impact latency for user access" [@tulshibagwale-2019-google-blog]. Pub-sub is the third option between WAM's per-request chattiness and RFC 6749's fire-and-forget. Subscription is the channel; claims challenge is the wire-level handshake; extended lifetime is the user-experience prize.

### Part 1: Subscription

Microsoft's CAE concept page describes the architecture in one sentence that rewards close reading:

<PullQuote>
"Timely response to policy violations or security issues really requires a 'conversation' between the token issuer Microsoft Entra, and the relying party (enlightened app)." -- Microsoft Learn, *Continuous access evaluation in Microsoft Entra* [@ms-cae-concept]
</PullQuote>

The word *conversation* is the architecture. The relying party (a CAE-aware Microsoft 365 workload such as Exchange Online) subscribes to a finite, documented set of *critical events* for the subjects it cares about. Entra pushes events to the RP as state changes. State is cached at the RP. On the hot path -- the per-request data plane -- the RP does an O(1) JWT signature verification plus an O(1) hash-table lookup of cached revocation state. No back-channel round-trip on the hot path. The 28-hour token costs no more to validate than the 1-hour token it replaced [@ms-cae-concept].

This is the move that defeats RFC 7662. The state lives at the RP, not at the AS. The control-plane cost scales with the rate of *events*, not the rate of *requests*. Push, not poll.

### Part 2: The claims challenge

When state at the RP changes -- because a push event has arrived saying "this user's password has been reset" -- the RP cannot reach into a request that has already been accepted and is being served. CAE is in-band with the *next* request, not the current one. The next time the client presents the stale token, the RP rejects it with `HTTP 401` and a specific header:

```
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="insufficient_claims",
                  claims="eyJhY2Nlc3NfdG9rZW4iOnsiYWNyc..."
```

The `claims` parameter is a base64url-encoded JSON object that tells the client what to re-acquire from the IdP. The Microsoft Authentication Library (MSAL) on the client decodes the challenge transparently and requests a new access token from Entra with the indicated claims. Entra either issues a fresh CAE-aware token (if authorization still holds) or rejects, forcing interactive re-authentication. The client retries the original API call with the new token [@ms-cae-app-resilience].

<Definition term="Claims Challenge">
The HTTP-level mechanism by which a CAE-aware resource provider signals to a client that the presented token must be re-acquired with fresh state. The challenge is conveyed as a `WWW-Authenticate: Bearer error="insufficient_claims"` header with a base64url-encoded `claims` parameter; current Microsoft Authentication Library (MSAL) releases decode and handle it automatically when the client app registration declares the `xms_cc` capability `["cp1"]` [@ms-cae-app-resilience].
</Definition>

This is the move that defeats RFC 7009. Revocation is initiated by the *resource provider's view of the IdP's state*, not by the token holder. A fired employee's client cannot opt out of the claims challenge; the RP will not serve any further request until a fresh token arrives that reflects the post-revocation state.

<RunnableCode lang="js" title="Decoding a CAE claims challenge">{`
// A real-shape WWW-Authenticate header from a CAE-aware resource provider.
// The 'claims' parameter is base64url-encoded JSON.
const header = 'Bearer error="insufficient_claims", claims="eyJhY2Nlc3NfdG9rZW4iOnsibmJmIjp7ImVzc2VudGlhbCI6dHJ1ZSwgInZhbHVlIjoiMTcyMDQ4MDA0MyJ9fX0="';

// Extract the claims parameter
const match = header.match(/claims="([^"]+)"/);
const b64 = match ? match[1] : null;

// base64url decode (Node 'Buffer' would work; here we use the browser-safe approach)
function b64urlDecode(s) {
  s = s.replace(/-/g, '+').replace(/_/g, '/');
  while (s.length % 4) s += '=';
  return atob(s);
}

const claimsJson = b64urlDecode(b64);
console.log(JSON.parse(claimsJson));
// {
//   "access_token": {
//     "nbf": {
//       "essential": true,
//       "value": "1720480043"
//     }
//   }
// }
// MSAL reads this and requests a new token whose 'nbf' (not-before) is at least
// the supplied timestamp -- i.e., a token issued after the state change.
`}</RunnableCode>

The `nbf` (not-before) claim challenge is the most common shape: the RP is telling the client "give me a token issued after this moment." The client requests one. Entra checks current state -- did the user get disabled? did the password get reset? did the risk score elevate? -- and either issues or denies. The wire format is simple enough to inspect in a browser tab, which is part of why the architecture has been able to standardize: there is no magic to reverse-engineer.

### Part 3: Extended lifetime, the prize

The first two parts buy you the third. Once revocation is push-based and the claims challenge gives the RP a way to evict stale tokens within seconds of seeing a control-plane event, the expiry timer stops carrying the security weight. Tokens can live longer because the expiry is no longer the only revocation mechanism.

Microsoft documents the upper bound as "up to 28 hours" for CAE-aware sessions [@ms-cae-concept; @ms-cae-app-resilience]. The default for non-CAE-capable clients remains 1 hour. This is the move that defeats the short-lifetime patch: the IdP load profile collapses because tokens refresh once a day, not on a per-minute cycle, and the revocation window is dramatically smaller -- not because expiry shrank, but because the channel now does the revocation work expiry used to do.

> **Key idea:** Long-lived access tokens are safe only when paired with a near-real-time revocation channel. CAE is the channel. Subscription provides the push, the claims challenge is the in-band handshake the push enables, and the 28-hour lifetime is what the channel buys -- not what the channel costs.

### The full round trip

The three parts interlock. The complete flow, from a state change at Entra to a re-validated request, runs end-to-end through every layer the article has named.

<Mermaid caption="The end-to-end CAE claims-challenge round trip. State change at Entra propagates via push to the resource provider; the RP rejects the next stale-token request with a claims challenge; MSAL acquires a fresh token; the request retries.">
sequenceDiagram
    participant Admin
    participant Entra as Microsoft Entra
    participant Client as Client (MSAL)
    participant RP as Resource Provider (e.g. Exchange Online)
    Admin->>Entra: Disable user account
    Entra->>RP: Push critical-event SET (account disabled)
    Note over RP: Updates cached revocation state for (sub, tenant)
    Client->>RP: GET /me/messages (Authorization Bearer old token)
    Note over RP: Validates JWT signature O(1), checks cached state
    RP-->>Client: 401 plus WWW-Authenticate insufficient_claims
    Note over Client: MSAL parses claims challenge from header
    Client->>Entra: Token request with claims
    Note over Entra: Checks current user state, account is disabled
    Entra-->>Client: 400 invalid_grant or interactive re-auth required
    Note over Client: User cannot recover, session terminates
</Mermaid>

Three moves, one design. Remove any one and the system collapses. Subscription without a claims challenge gives you push events the RP cannot act on at the wire. Claims challenge without subscription gives you a 401 mechanism with no information to decide when to fire it. Extended lifetime without either gives you Generation 1's fired-employee window. The 28-hour token is not the *cost* of CAE; it is what CAE *purchases*.

This is the design. What does it actually do in production today, and where does it stop?

## 6. CAE as Deployed in Microsoft Entra (2026)

Concrete answers to concrete questions. Which events trigger CAE? Who participates? What is the actual SLA? How long do tokens actually live? No marketing language; only what Microsoft Learn currently documents.

### Critical event evaluation events

Microsoft Learn lists exactly five events that drive *critical event evaluation* at the IdP-to-RP boundary [@ms-cae-concept]:

1. A user account is deleted or disabled.
2. A password for a user is changed or reset.
3. Multi-factor authentication is enabled for the user.
4. An administrator explicitly revokes all refresh tokens for a user.
5. High user risk is detected by Microsoft Entra ID Protection.

These five events propagate from Entra to the participating CAE-aware resource providers via the push channel. Microsoft's published service-level objective is "up to 15 minutes" for critical-event propagation [@ms-cae-concept]. That is not the same as "instant." The phrase to avoid is "CAE delivers instant revocation"; the accurate phrase is "CAE delivers near-real-time revocation, typically within 15 minutes for critical events."

A separate scenario -- *Conditional Access policy evaluation* -- covers network and IP-location changes. Here the SLA is different: IP-location enforcement is **instant** per Microsoft's published documentation [@ms-cae-concept]. The difference is mechanical. IP location is a property the RP sees directly on every request (the source IP of the incoming HTTP connection); the RP can compare it against the location constraints attached to the session and reject locally with no propagation delay. Critical events have to travel from Entra to the RP through the event channel, and that travel has a 15-minute budget at Microsoft 365 scale.

| Event | Source | Propagation | Notes |
|---|---|---|---|
| Account deleted or disabled | Entra ID directory | Up to 15 min | Honored by Exchange Online, SharePoint Online, Teams, Graph (CA) |
| Password changed or reset | Entra ID directory | Up to 15 min | Same RP set |
| MFA enabled for user | Entra ID directory | Up to 15 min | Same RP set |
| All refresh tokens revoked (admin) | Entra ID admin action | Up to 15 min | Same RP set |
| High user risk detected | Entra ID Protection | Up to 15 min | **SharePoint Online does not honor user-risk events** [@ms-cae-concept] |
| IP location changed (CA policy) | Resource-provider observation | Instant | Conditional Access policy evaluation path; strict location enforcement [@ms-strict-location-enforcement] |

> **Note:** Microsoft Defender for Endpoint and Microsoft Intune (MDM) are *signal sources* into Conditional Access. They contribute to the risk score and device-compliance state that drive CA policy decisions, but they are **not** CAE-consuming resource providers. They do not subscribe to Entra critical-event notifications and they do not enforce the claims-challenge handshake on token-bearing requests. The CAE-aware RP set is exactly: Exchange Online, SharePoint Online, Microsoft Teams, and Microsoft Graph (the last only for Conditional Access policy evaluation) [@ms-cae-concept]. If you read older deck slides or vendor blog posts that list MDE or Intune as CAE participants, they are conflating the signal-source role with the resource-provider role.

<Sidenote>The SharePoint Online user-risk caveat is a concrete example of why "CAE-aware" is not a binary property at the workload level. SharePoint Online is fully CAE-aware for the first four critical events on the list; it just does not subscribe to user-risk events specifically. The lesson is that you must read the per-workload documentation carefully when designing controls that depend on a specific event's enforcement [@ms-cae-concept].</Sidenote>

### Workloads that participate

The CAE-aware resource-provider set, per Microsoft Learn [@ms-cae-concept]:

- **Exchange Online** -- full CAE consumer (initial implementation, October 2020).
- **SharePoint Online** -- full CAE consumer, with the user-risk caveat noted above.
- **Microsoft Teams** -- full CAE consumer (initial implementation), per Alex Simons's January 2022 GA announcement [@simons-2022-01-ga-rss].
- **Microsoft Graph** -- consumes Conditional Access policy evaluation events (the IP-location instant path); narrower scope than the M365 productivity workloads.

Client-side support is also explicit. Microsoft's compatibility tables in the CAE concept page enumerate which client and server combinations are *Supported*, *Partially supported*, or *Not Supported* on every major operating system and form factor [@ms-cae-concept]. Office web apps against SharePoint Online and Exchange Online are documented as *Not Supported* on several combinations; every Teams client surface shows as *Partially supported*. The point is not that CAE is broken on these surfaces -- it is that Microsoft documents the rough edges in primary source, and tenant administrators who care about specific scenarios must read the table.

### Tokens and clients

The default access-token lifetime for CAE-aware sessions is up to 28 hours; the default for non-CAE-capable clients remains 1 hour [@ms-cae-concept; @ms-cae-app-resilience]. Client support requires a current Microsoft Authentication Library (MSAL) release on the target platform: the 4.x line for .NET and JavaScript; the appropriate current line for Python, Java, Android, iOS, or macOS, per each SDK's own release stream. Microsoft Learn's *Use Continuous Access Evaluation enabled APIs* page enumerates per-SDK guidance [@ms-cae-app-resilience]. The app registration must also declare the `xms_cc` client capability with value `["cp1"]` to advertise CAE-handling support to the IdP [@ms-cae-app-resilience].

<Definition term="xms_cc (Client Capabilities)">
An app-registration claim by which a client advertises support for CAE-aware token issuance. The canonical wire-level value in the issued JWT is lowercase `"cp1"` (Microsoft's developer docs show both `"cp1"` and `"CP1"`; negotiation is case-insensitive but the token claim is lowercase). It signals that the client's MSAL implementation can decode and act on a `WWW-Authenticate: Bearer error="insufficient_claims"` response by parsing the `claims` parameter and re-acquiring a token. Without it, Entra issues the default 1-hour token and the resource provider falls back to standard expiry [@ms-cae-app-resilience].
</Definition>

<Definition term="Resource Provider (RP) in the CAE sense">
A Microsoft 365 workload (Exchange Online, SharePoint Online, Teams, or Microsoft Graph for Conditional Access policy) that consumes Entra's critical-event notifications and enforces them on subsequent token-bearing requests via the claims-challenge handshake. This is a narrower meaning than the generic OAuth 2.0 sense of "resource server"; in CAE, "resource provider" specifically means a workload that has implemented the CAE participation contract with Entra [@ms-cae-concept].
</Definition>

<Aside label="What 'up to 28 hours' actually means">
Microsoft documents an *upper bound* on token lifetime. The actual lifetime issued for any given session is variable and can be shorter. CAE-aware sessions can also be refreshed silently as long as the channel signals nothing has changed. Practically, this means most users with CAE-aware clients on M365 productivity workloads almost never see an interactive re-authentication prompt during normal working hours [@ms-cae-concept].
</Aside>

### A migration note for older tenants

Tenant administrators with Conditional Access policies that pre-date GA may carry legacy "strict location enforcement" preview settings. Microsoft has since migrated the feature into GA, and the current Microsoft Learn page *Strictly enforce location policies using continuous access evaluation* documents the post-migration configuration model [@ms-strict-location-enforcement]. Administrators should verify their policies after each major Conditional Access feature wave to ensure preview-to-GA migrations have been picked up.

CAE is one approach among several. Where does it sit relative to introspection-per-request, identity-aware proxies, DPoP, and the cross-vendor OpenID standard? The design space is small enough to map cleanly.

## 7. Competing Approaches and Their Relation to CAE

Five named methods occupy adjacent positions in the design space. Some compete; some compose. The map matters because deployments that confuse the two get wrong answers.

### CAE versus OpenID SSF and CAEP 1.0

Same architecture, different implementations. Microsoft CAE solves the Microsoft estate via a Microsoft-internal protocol; OpenID SSF and CAEP solve the cross-vendor SaaS long tail via a public standard atop RFC 8417 [@openid-three-final-specs; @openid-ssf-1_0-final; @openid-caep-1_0]. The two are convergent rather than rivalrous: Microsoft is moving toward also acting as an SSF transmitter and receiver alongside its first-party CAE protocol, and other vendors are building SSF receivers that can consume signals from any transmitter, including Microsoft.

The Authenticate 2025 interop event in October 2025 was the first whose tested text was the Final-Specification version of SSF [@openid-authenticate-2025-interop]. Multi-vendor SSF and CAEP interoperability has been demonstrated at successive Gartner IAM Summit interop events as well. At the March 2024 London summit, SGNL's CAEP Hub interoperated as both transmitter and receiver with Cisco Duo, Okta, SailPoint, and Helisoft on the `session-revoked` CAEP event [@sgnl-2024-04-interop]. Okta's own blog characterizes the March 2025 London summit as "a significant industry shift toward interconnected, real-time security" with "interoperable implementations from pioneers like Okta, Google, IBM, Omnissa, SailPoint, and Thales" [@okta-shared-signals].

<Sidenote>Tim Cappalli, who joined Okta after his time at Microsoft, co-chairs the OpenID Shared Signals Working Group alongside Atul Tulshibagwale (SGNL, formerly Google) [@tulshibagwale-sgnl-2023-08-qanda; @openid-sharedsignals-wg]. The cross-vendor co-chair arrangement is part of why the Final Specifications passed without significant vendor pushback: the people doing the standardization had visibility into both Microsoft's and Google's prior implementations.</Sidenote>

### CAE versus RFC 7662 introspection

Parallel paths, not competitors. RFC 7662 introspection [@rfc-7662] continues to be the right answer for opaque-token systems and on-premises IdPs where the AS-to-RP per-request round-trip is acceptable. CAE wins at hyperscale public-cloud volumes specifically because it inverts the per-request dependency: state pushes to the RP once and lives in cache; the data plane does not consult the AS on every request. If you are building a B2B integration with a small RP count and a few hundred requests per second, RFC 7662 is fine. If you are building Exchange Online, it is not.

### CAE versus DPoP and mTLS-bound tokens

Complementary, not competitive. The threat model for CAE is *stale authorization*: the authorization decision at sign-in is no longer accurate, because the user has been disabled, their password has been reset, their risk score has changed, or their network location has shifted. The threat model for proof-of-possession is *stolen tokens*: an attacker holding a bearer token that was legitimately issued to a different party.

RFC 9449, *OAuth 2.0 Demonstrating Proof of Possession (DPoP)*, published September 2023 by Daniel Fett and collaborators [@rfc-9449-dpop], binds an access token to a client-held key pair: a DPoP-bound token can only be replayed by an attacker who also stole the private key. RFC 8705, *OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens*, published February 2020 by Brian Campbell and collaborators [@rfc-8705-mtls], does the same thing using mTLS certificates. Both are sender-constrained-token mechanisms; both close the bearer-token-replay attack surface.

CAE does not address token theft. A stolen CAE-aware token is still usable by the attacker until the IdP or RP becomes aware of the compromise. A DPoP-bound CAE-aware token closes both gaps: the attacker cannot replay it, and even if they could, the channel can revoke it within minutes. The correct deployment pattern is to combine CAE with DPoP or mTLS-binding where the application threat model warrants both.

### CAE versus BeyondCorp-style identity-aware proxies

Different architectural layer. Identity-aware proxies (Google IAP, Cloudflare Access, AWS Verified Access) sit *in front of* the resource server and enforce policy at the proxy. They have full visibility into per-request state and can do instant revocation by terminating the connection at the proxy when policy changes. This is correct for proxy-fronted workloads but does not scale to the long tail of API surfaces that cannot or will not sit behind a proxy. CAE pushes the enforcement into the resource server itself, which is what lets it work for native cloud APIs and federated SaaS where the proxy model would not.

### A note on PRT theft

CAE does not address attacks at the [Primary Refresh Token (PRT)](/blog/inside-the-primary-refresh-token-the-cryptographic-seam-betw/) layer. The PRT is a long-lived refresh credential Windows uses to mint access tokens silently from a logged-in session. A stolen PRT can mint CAE-aware access tokens that are, from Entra's perspective, legitimately issued -- the attacker holds a credential the IdP still recognizes. CAE will only catch this if the user is revoked, the password is reset, or one of the other critical events fires *after* the PRT theft. The Pass-the-PRT attack class therefore bypasses CAE entirely; defenses for that layer are out of scope here and are a separate engineering problem.

### Mapping the design space

The table is the cleanest way to see who competes with whom and who composes with whom.

| Approach | Solves | Composes with CAE | Competes with CAE |
|---|---|---|---|
| OpenID SSF/CAEP 1.0 | Cross-vendor revocation | Yes (CAE is a Microsoft implementation of the same pattern) | No |
| RFC 7662 introspection | Opaque-token revocation at modest scale | Parallel path | At hyperscale only |
| DPoP (RFC 9449) | Sender-constrained tokens | Yes (compose for full coverage) | No |
| mTLS-bound tokens (RFC 8705) | Sender-constrained tokens | Yes (compose for full coverage) | No |
| Identity-aware proxy | Per-request policy at the proxy edge | Composes for proxy-fronted workloads | Different layer |
| Short access-token lifetime | Reduces revocation window mechanically | Falls back when CAE not available | Yes, and loses on the trade |

The reader who came to this article expecting a binary contest -- "which one wins?" -- has the wrong frame. The actual answer is that CAE is one move in a layered defense, and most production deployments will end up composing it with DPoP or mTLS for token binding, falling back to short lifetimes for non-CAE clients, and continuing to use introspection for opaque-token internal APIs.

That handles deployment. But every architecture has limits. The reader has spent six sections climbing; the next section is the *humility* beat where the descent begins.

## 8. Theoretical Limits: What CAE Cannot Do

Every architecture has a floor. The reader has spent six sections climbing; this is where the limits show up -- not as vendor laziness, but as physics, scale, and trust topology.

### Limit 1: cannot revoke a token already in flight

Once a request has been accepted and is being served by the resource provider, CAE cannot reach into the RP's execution thread and abort it. The revocation applies to the *next* request. A long-running operation -- a bulk Outlook export, a large SharePoint upload -- that began at 10:23:00 may complete normally even if the user is disabled at 10:23:01. The revocation takes effect the next time the client presents the token [@ms-cae-concept]. For most use cases the in-flight window is sub-second and the consequence is negligible; for long-running data egress, it matters.

### Limit 2: cannot beat the 15-minute critical-event SLA for most events

Microsoft's published SLA is "up to 15 minutes" for critical-event propagation [@ms-cae-concept]. Only IP-location enforcement is instant. The 15-minute number is not a fundamental limit; it is engineering economics at hyperscale. Fanning out an event to every CAE-aware RP for every potentially affected subject across Microsoft 365's global infrastructure is what produces the budget. Smaller-scale deployments demonstrate much better numbers: TigerIdentity's commercial deployment self-reports sub-second end-to-end revocation in a tuned CAEP receiver configuration [@tigeridentity-caep-explained]. The architecture allows sub-second; Microsoft's particular deployment chooses 15 minutes because the alternative at its fan-out scale is prohibitively expensive.

The strict physical floor sits below even the tuned implementations. An RP cannot enforce a revocation it has not yet learned about. The one-way network latency $L$ between IdP and RP sets the absolute minimum: with a transcontinental $L \approx 70\,\text{ms}$, no push protocol can revoke faster than that, and pull protocols are necessarily worse. In practice, queuing, scheduling, and event-fanout dominate $L$ at scale -- but the floor remains.

> **Key idea:** The 15-minute SLA is not a fundamental limit; it is engineering economics at hyperscale. Sub-second is feasible at smaller fan-outs, and is the direction of travel as receiver implementations improve and as Microsoft's own event-distribution infrastructure ages well. But the strict physical floor is the network latency between IdP and RP; no cooperative protocol can do better than that.

### Limit 3: cannot cover non-CAE-aware clients or resource providers

CAE is a cooperative protocol. Both the client (via the `xms_cc=cp1` capability declaration) and the resource provider (via implementing the participation contract) must be CAE-aware [@ms-cae-app-resilience]. A non-CAE client receives a default 1-hour token and never sees a claims challenge; it relies on standard expiry. A non-CAE RP silently falls back to standard token expiry as well; the IdP's events have no consumer. The CAE-aware portion of the estate enjoys the new contract; the rest carries the old security debt unchanged.

This is why audit posture matters. A tenant administrator who wants to argue that revocation latency for their workforce is "under 15 minutes" must be able to demonstrate that the client and RP combinations the workforce actually uses are CAE-aware. Microsoft's compatibility tables [@ms-cae-concept] document several Office-web-app and OneDrive-Win32-versus-SharePoint combinations as *Not Supported* or *Partially supported*; those gaps are part of the tenant's effective revocation profile, not someone else's problem.

### Limit 4: cannot help if the resource provider itself is compromised

Revocation state lives at the RP. A compromised RP can simply ignore revocation events: keep serving requests against tokens Entra has signaled are invalid; misreport its own subscription state; drop events on the floor. CAE is a *cooperative* protocol between trustworthy parties. It is not a defense against an RP that has been pwned. The OpenID SSF specification addresses this implicitly by defining receiver requirements (verification events, stream-control endpoints, signature verification on SETs), but no receiver requirement can compel a compromised receiver to obey the protocol.

The threat model implication: an attacker who has compromised an RP does not need to bypass CAE. They simply do not implement it from the inside, and the protocol's design has no remedy. RP integrity is a prerequisite, not a guarantee.

### Limit 5: cannot revoke a stolen PRT before it mints a new access token

As noted in Section 7, the Primary Refresh Token sits outside CAE's scope. A stolen PRT mints new CAE-aware access tokens that Entra treats as legitimately issued, because from Entra's perspective they *are* legitimately issued -- the attacker is presenting a credential the IdP recognizes. CAE catches PRT theft only when one of the five critical events fires after the theft. If the attacker exfiltrates a PRT, refreshes a token, and immediately uses it, the access token is valid and the revocation channel has nothing to revoke.

<Sidenote>The SharePoint Online user-risk-event caveat is a useful concrete example of the per-feature limit pattern. Even within the four CAE-consuming RPs, feature support is not uniform; you cannot reason about CAE as a single boolean property at the workload level. Every event you care about must be checked against the specific RP that will enforce it [@ms-cae-concept].</Sidenote>

### The bounded design space

Put together, the five limits draw the perimeter of what CAE can do. It cannot stop in-flight requests. It cannot beat network latency at the strict floor or 15 minutes at Microsoft's chosen operating point. It cannot help non-participating clients or RPs. It cannot fix a compromised RP. It cannot revoke PRT-layer credentials before they mint new tokens. The honest summary is that the design space is *bounded* -- the reader who internalizes the five limits has a calibrated sense of what is fundamentally possible, and can stop expecting CAE to be a single fix for revocation in all situations.

The limits also map the open frontier. If those are the structural constraints, what are the OpenID Foundation and the SaaS long tail working on in 2026?

## 9. Open Problems (2026)

Final Specifications are necessary but not sufficient. CAEP 1.0, SSF 1.0, and RISC 1.0 were approved on September 2, 2025 [@openid-three-final-specs]. The question for 2026 is what *adoption* and *extension* look like. Five live problems.

### 1. Third-party SaaS receiver-adoption depth

The Final Specifications give every SaaS vendor a clean target to build against. The question is whether they will. Google Workspace shipped its SSF receiver in Closed Beta, supporting only the `session-revoked` CAEP event at launch [@google-workspace-ssf-api]. That is one event out of CAEP 1.0's eight. The SaaS long tail -- Workday, ServiceNow, GitHub Enterprise, Atlassian, Salesforce -- has not, as of the Final Specification's first anniversary, shipped public receivers.

For the "fired employee with N SaaS apps" scenario to be fully solved, every SaaS app in the user's bundle has to be a CAEP receiver subscribed to events from the enterprise IdP. The architecture is in place; the integration work is per-vendor and per-customer. This is the largest single determinant of CAE's real-world value over the next several years.

> **Note:** The Microsoft 365 estate enjoys near-complete CAE coverage because Microsoft built both the IdP and the resource providers. The cross-vendor story is fundamentally a coordination problem: every receiver has to be built, deployed, and configured to subscribe to events from every transmitter the enterprise uses. SSF 1.0 makes the integration tractable; it does not make the work disappear. Watch receiver coverage in 2026-2028 as the leading indicator of CAE's industry-wide impact.

### 2. CAE for non-human and agent identities

CAEP subject identifiers assume user-shaped or device-shaped subjects [@openid-caep-1_0]. Workload identities, service principals, and emerging [AI-agent identities](/blog/agentic-identity-on-windows-when-the-process-acting-on-your-/) sit outside the model as currently profiled. An agent acting on behalf of a user, with its own identity and its own session, is not yet covered by a Final-Specification profile. The Microsoft Entra *Conditional Access for Agent Identities* workstream is a documented Microsoft Learn surface as of 2026 [@ms-conditional-access-agent-id] and is one of the workstreams that will eventually produce a CAEP profile for non-human subjects, but as of mid-2026 the cross-vendor standardization gap is open.

### 3. Cross-IdP federation of SSF streams

When tenant A federates to tenant B, the event-flow path crosses a trust boundary the current Final Specifications do not explicitly profile. If a user is disabled in tenant A's IdP, how does the revocation event reach the resource providers downstream in tenant B? The pieces -- transmitter, receiver, SET envelope, signed events -- are all in place; what is missing is the canonical profile for cross-IdP federation of SSF streams. This is a 2026-2027 OpenID Foundation workstream rather than a Final-Specification gap.

### 4. Bidirectional signal sharing

Today's CAE and CAEP deployments are largely IdP-as-transmitter, RP-as-receiver. The full vision is bidirectional: an RP that detects anomalous behavior (unusual access patterns, suspected automation, post-authentication risk signals) should be able to transmit those signals back to the IdP, which can then incorporate them into the next authorization decision. SGNL and similar vendors are building toward this model. The Final Specifications support bidirectional flow at the protocol level; the policy and operational pieces -- who trusts whom, what events flow which way, how an IdP weighs signals from an RP -- are still being worked out.

### 5. Reason-code convergence between CAEP and RISC

CAEP 1.0 and RISC 1.0 cover overlapping ground around credential mutation. CAEP defines a `credential-change` event; RISC defines `account-credential-change-required` [@openid-caep-1_0; @openid-sharedsignals-wg]. Implementers must choose, and vendor extensions proliferate where the spec leaves room. Reason-code convergence between the two profiles is incomplete; some receivers will subscribe to both streams to be safe, others will pick one and hope upstream transmitters agree. Over time the WG will likely consolidate; for 2026, the practical guidance is to support both event vocabularies in receiver code.

<Aside label="The Authenticate 2025 interop event">
The first interoperability event whose tested text was the Final-Specification version of SSF took place at Authenticate 2025 in San Diego, October 13-15, 2025, hosted by the FIDO Alliance and coordinated by the OpenID Foundation Shared Signals Working Group [@openid-authenticate-2025-interop]. The event required that all participants with an SSF Transmitter pass the OpenID Foundation's free, open-source conformance tests. This was the fourth in a series of Gartner-IAM and Authenticate interops since March 2024, and the first conducted after SSF 1.0 was approved Final on September 2, 2025. The list of vendor participants has grown at each event; cross-vendor receiver coverage is the metric to watch.
</Aside>

Given all this -- the architecture, the limits, the open frontier -- what should you actually do this week in your tenant and your code?

## 10. Turning CAE On in Your Tenant and Your Code

Three audiences, three checklists. Each section is what an engineer in that role needs to confirm or change to make CAE work in their environment.

### For the tenant administrator

CAE has been auto-enabled by default for new Microsoft Entra tenants since the January 2022 GA [@simons-2022-01-ga-rss]. Tenants created before then may need to verify enablement in **Conditional Access -> Session controls -> Customize continuous access evaluation**. The relevant signals to check:

1. **CAE enablement state.** Confirm that the tenant-wide CAE policy is set to *Enabled* rather than *Disabled* or *Strict location*.
2. **Per-policy disable flags.** Some legacy CA policies carry per-policy CAE overrides. Audit any that explicitly disable CAE; the right default is to honor it.
3. **Strict location enforcement migration.** Tenants with pre-GA "strict location enforcement" preview settings should verify that the policy has migrated to the current GA configuration model documented in Microsoft Learn [@ms-strict-location-enforcement].
4. **Audit log baselines.** Sign-in logs surface `signInEventTypes` with CAE-related entries; refresh-token issuance events and revocation events appear in the Entra ID audit log. Build a baseline before changing policies so you can detect drift.

### For the MSAL client developer

The client side has three things to confirm and one thing to test:

1. **MSAL version.** Use a current MSAL release on your client platform: 4.x for MSAL.NET and MSAL.js; the appropriate current line for MSAL Python, MSAL Java, MSAL Android, and MSAL for iOS/macOS, per each SDK's own release stream. Microsoft Learn's *Use Continuous Access Evaluation enabled APIs* page enumerates the per-SDK guidance [@ms-cae-app-resilience]. Earlier major-version lines do not handle the claims challenge transparently.
2. **Capability declaration.** The app registration must declare `xms_cc` with value `["cp1"]` (lowercase is the canonical token-claim form; uppercase `"CP1"` also works because negotiation is case-insensitive). This is the wire-level signal to Entra that the client can handle a CAE-aware token and the claims challenge that comes with it.
3. **Claims-challenge handling.** MSAL helpers do this transparently in current SDK versions, but custom HTTP pipelines that bypass MSAL must implement the `WWW-Authenticate: Bearer error="insufficient_claims"` response handler manually. Decode the `claims` parameter (base64url), pass it to `AcquireTokenInteractive` or the equivalent, retry the original request with the new token.
4. **End-to-end test.** Trigger an admin password reset against a test user in a non-production tenant and verify that the next API call from a signed-in MSAL session surfaces the claims challenge and recovers cleanly. This is the single most useful confidence test; it exercises every layer of the protocol in one round trip.

<RunnableCode lang="js" title="Detecting a CAE-aware session at the client">{`
// Illustrative: inspect an MSAL JS token-cache entry for the xms_cc capability
// marker. In real apps, MSAL handles capability negotiation; this is for
// educational inspection only.

// A real-shape AccessTokenEntity from MSAL JS cache
const tokenEntity = {
  homeAccountId: 'abc.def-tenant',
  environment: 'login.microsoftonline.com',
  credentialType: 'AccessToken',
  clientId: '11111111-2222-3333-4444-555555555555',
  tenantId: 'tenant-id',
  target: 'User.Read Mail.Read',
  // expiresOn is up to ~28 hours after cachedAt for CAE-aware sessions
  cachedAt: '1748534400',
  expiresOn: '1748635200',  // 28h later
  extendedExpiresOn: '1748635200',
  // Capability declaration the app advertised at acquisition time
  requestedClaims: { xms_cc: ['cp1'] }
};

const ttlSeconds = parseInt(tokenEntity.expiresOn) - parseInt(tokenEntity.cachedAt);
const ttlHours = ttlSeconds / 3600;
const isCaeAware = tokenEntity.requestedClaims &&
                   tokenEntity.requestedClaims.xms_cc &&
                   tokenEntity.requestedClaims.xms_cc
                     .some(c => c.toLowerCase() === 'cp1');

console.log('TTL hours:', ttlHours.toFixed(1));
console.log('CAE-aware:', isCaeAware);
// TTL hours: 28.0
// CAE-aware: true
// A TTL above ~1 hour with xms_cc cp1 is a strong indicator the session is
// CAE-aware and Entra issued an extended-lifetime token.
`}</RunnableCode>

### For the custom-API author

This is the hardest path. To make a custom protected API a CAE-aware resource provider today, the first-party Microsoft pathway is not publicly available -- the CAE participation contract for the M365 productivity workloads is internal to Microsoft. The community-canonical implementation pattern is Damien Bowden's `damienbod/AspNetCoreMeIDCAE` reference repository on GitHub [@damienbod-aspnetcoremeidcae], with an accompanying blog post walkthrough [@damienbod-blog-2022-04]. The repository (initial version April 3, 2022; updated through .NET 10 in late 2025) demonstrates:

- The `xms_cc=cp1` capability declaration on both the client and the API app registrations.
- The Microsoft.Identity.Web claims-challenge handling on the API side.
- The Razor Page client flow that catches a `401` with the challenge header and re-acquires the token.

For a fully standards-track pathway, the same custom API can be built as an OpenID SSF receiver consuming CAEP events from any SSF-compliant transmitter, using the RFC 8417 SET envelope over the RFC 8935 push transport [@rfc-8417; @rfc-8935]. Production-grade SSF receiver code is now available in commercial CAEP Hub products (SGNL, TigerIdentity) and a growing set of open-source libraries.

> **Note:** CAE itself does not require add-on licensing for the basic critical-event evaluation across Microsoft 365 -- it is part of the Entra ID baseline for new tenants. The Microsoft Entra ID Protection feed that drives *high user risk detected* events, however, requires Microsoft Entra ID P2 (or an equivalent SKU that includes Identity Protection). Confirm current licensing terms in the Microsoft licensing documentation before making procurement decisions; the lower SKUs cover four of the five critical events but not the risk-based one [@ms-cae-concept].

### Observability

Sign-in logs and audit logs are where CAE behavior shows up. Look for:

- **Sign-in logs**: filter by `signInEventTypes` containing CAE-related entries. CAE-aware sign-ins have a different telemetry shape than non-CAE sign-ins.
- **Token-issuance events**: refresh-token issuance against CAE-aware app registrations should show the extended lifetime.
- **Audit log revocation entries**: administrator revocation actions and Identity-Protection-driven revocations appear here; cross-correlate with the resource-provider-side telemetry to validate end-to-end propagation.

<Spoiler kind="solution" label="How to confirm a tenant is CAE-active end to end">
Use Microsoft Graph PowerShell to enumerate the tenant's CAE configuration and then trigger a synthetic test: 1) read `Get-MgIdentityConditionalAccessPolicy` to verify the relevant CA policies have CAE enabled in their `SessionControls.ContinuousAccessEvaluation` block; 2) create a test user, sign them in via Outlook on the Web; 3) reset their password via `Update-MgUser`; 4) observe in the audit log that the password reset propagates to a CAE event, and verify in Outlook on the Web that the next refresh surfaces a re-authentication prompt within the 15-minute SLA. This is the simplest end-to-end confidence test that does not require modifying any production resource.
</Spoiler>

### Defaults are good

The most common engineering recommendation here is to leave the defaults alone. CAE on, default tenant settings, current MSAL clients, `xms_cc=cp1` on every new app registration. The configuration surface area is small precisely because the design is right: there are not many knobs to turn. The work is in confirming that the client and RP combinations your users actually exercise are CAE-aware, and in monitoring the audit logs to catch drift.

That is what to do. The last section is what to remember -- the misconceptions every team carries into a CAE conversation, and the answers that close them.

## 11. FAQ and Coda

<FAQ title="Frequently asked questions">

<FAQItem question="Is CAE the same as instant revocation?">
No. The published SLA is up to 15 minutes for the five critical events; only IP-location enforcement is instant. See Section 6 for the mechanical reason for the asymmetry and Section 8 Limit 2 for why 15 minutes is engineering economics rather than a fundamental limit [@ms-cae-concept].
</FAQItem>

<FAQItem question="Does CAE protect against token theft?">
No. CAE addresses *stale authorization* (the original authorization decision is no longer correct), not *stolen tokens* (an attacker is presenting a token that was legitimately issued to someone else). For token theft, use a sender-constrained-token construction: DPoP per RFC 9449 [@rfc-9449-dpop] or mTLS-bound tokens per RFC 8705 [@rfc-8705-mtls]. Both compose cleanly with CAE; a DPoP-bound CAE-aware token is the strongest commonly-deployed combination today, closing both the replay attack surface and the stale-authorization gap.
</FAQItem>

<FAQItem question="Is CAEP still a draft?">
No. SSF 1.0, CAEP 1.0, and RISC 1.0 were approved as OpenID Foundation Final Specifications on September 2, 2025 -- see Section 4 for the standards-stack treatment [@openid-three-final-specs].
</FAQItem>

<FAQItem question="Do Microsoft Defender for Endpoint or Microsoft Intune speak CAE?">
No. MDE and Intune are signal sources into Conditional Access, not CAE-consuming resource providers; see the Section 6 Common-misconception callout for the full distinction and the CAE-aware RP set [@ms-cae-concept].
</FAQItem>

<FAQItem question="Are long-lived (28-hour) access tokens a security regression?">
*Not when the resource provider is CAE-aware.* The token lifetime stops carrying the revocation weight; the channel does. A CAE-aware RP can revoke a 28-hour token within 15 minutes of a critical event, which is a strictly better revocation profile than a 1-hour token with no channel (revocable only at the 1-hour expiry boundary in the worst case) [@ms-cae-concept]. *Yes*, however, when the RP is *not* CAE-aware: the token then carries its full lifetime as the revocation window, and longer is worse. The architectural rule: only issue extended-lifetime tokens to clients whose RPs are CAE-aware -- which is exactly what the `xms_cc=cp1` capability negotiation enforces [@ms-cae-app-resilience].
</FAQItem>

<FAQItem question="Does CAE work with SAML?">
No. CAE is specific to OAuth 2.0 and OpenID Connect access tokens. SAML assertions have their own lifetime and replay-protection model and are not in scope for the CAE participation contract or for the OpenID SSF/CAEP profiles [@ms-cae-concept; @openid-caep-1_0]. If you are still operating SAML-fronted workloads, the analogous design problem (revocation between sign-in and assertion expiry) is solved differently and is largely a per-product implementation question rather than a standards story.
</FAQItem>

</FAQ>

### Coda: the bargain

The OAuth 2.0 designers in 2012 took a deliberate trade: short-lived self-contained tokens were the price they paid to escape the WAM bottleneck. The trade was correct for the web they were designing for. It became wrong the moment enterprises ran compliance-bound SaaS at scale on top of those tokens. Three obvious patches were tried -- the `/revoke` endpoint, the `/introspect` endpoint, the short-lifetime experiment -- and each failed for a distinct reason: the wrong party initiates revocation; the AS becomes a per-request critical path; expiry as a blunt instrument creates load and reliability problems while still leaving a window.

What replaced them was an architecture that took two facts seriously. First, revocation has to be push from the IdP to the RP -- not pull from RP to AS, not client-initiated POST to `/revoke`. Second, expiry and revocation can be separated: once the channel handles revocation, expiry can be measured in days rather than minutes. The 15-minute critical-event SLA and the up-to-28-hour token lifetime are two halves of the same bargain. Microsoft Entra ships them together because they only work together; the OpenID Foundation has standardized the same pattern across vendors because the long tail of SaaS faces the same problem.

The architecture is settled; the adoption is in progress. The CAEP, SSF, and RISC Final Specifications give every SaaS vendor a tractable target. The Microsoft 365 estate is already covered. Cross-vendor receiver coverage is the metric that will decide how much of the 2026 enterprise identity surface actually inherits the bargain -- and that, more than any further protocol work, is the story to watch over the next several years.

<StudyGuide slug="continuous-access-evaluation" keyTerms={[
  { term: "Continuous Access Evaluation (CAE)", definition: "Microsoft Entra's push-subscription channel that lets a resource provider revoke an already-issued access token in near-real-time without waiting for expiry." },
  { term: "Web Access Management (WAM)", definition: "Pre-2012 enterprise identity pattern with synchronous per-request PDP round-trips; instant revocation but no scale or federation." },
  { term: "Security Event Token (SET)", definition: "IETF RFC 8417 signed-JWT envelope for transmitting security events; the wire format under CAEP, SSF, and RISC." },
  { term: "Claims Challenge", definition: "HTTP 401 with WWW-Authenticate insufficient_claims header and a base64url-encoded claims parameter; the wire-level mechanism by which a CAE-aware RP tells a client to re-acquire a token." },
  { term: "xms_cc capability", definition: "App-registration claim with canonical value cp1 (case-insensitive) by which a client advertises CAE-handling support to Entra." },
  { term: "Resource Provider (RP) in CAE", definition: "Exchange Online, SharePoint Online, Teams, or Microsoft Graph; a workload that consumes Entra's critical-event notifications." },
  { term: "OpenID Shared Signals Framework (SSF)", definition: "Vendor-neutral OpenID Foundation Final Specification (September 2, 2025) for stream-based SET delivery between transmitters and receivers." },
  { term: "Continuous Access Evaluation Profile (CAEP)", definition: "OpenID Foundation Final Specification (September 2, 2025) defining session-level event types atop SSF." }
]} questions={[
  { q: "Why does the standard OAuth 2.0 /revoke endpoint not solve the fired-employee problem?", a: "Because it is client-initiated: an uncooperative token holder will not POST their token to /revoke, and the administrator on the other side does not possess the bearer token to POST." },
  { q: "Why is RFC 7662 introspection unworkable as the next generation of revocation at hyperscale?", a: "Because it reintroduces a synchronous per-request dependency on the authorization server, returning the architecture to the WAM bottleneck that OAuth was designed to escape." },
  { q: "What three innovations interlock to make CAE work, and why are they only meaningful in combination?", a: "Subscription (push channel from IdP to RP), claims challenge (the 401 plus WWW-Authenticate insufficient_claims handshake), and extended lifetime (up to 28 hours). Subscription without the claims challenge gives push events with no in-band way to act on them; claims challenge without subscription has no information to decide when to fire; extended lifetime without either reverts to Generation 1's fired-employee window." },
  { q: "Why is the 15-minute critical-event SLA not a fundamental limit?", a: "Because it is engineering economics at Microsoft 365's event-fanout scale, not architecture. Smaller-scale CAEP receivers (TigerIdentity, SGNL) demonstrate sub-second propagation. The strict physical floor is the one-way network latency between IdP and RP." },
  { q: "Which Microsoft workloads are CAE-aware resource providers, and which are signal sources rather than RPs?", a: "RPs: Exchange Online, SharePoint Online, Teams, and Microsoft Graph (for Conditional Access policy evaluation). Signal sources, not RPs: Microsoft Defender for Endpoint and Microsoft Intune." }
]} />
