<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Parag Mali - tag: conditional-access</title><description>Posts tagged conditional-access.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sun, 07 Jun 2026 04:13:14 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/conditional-access/rss.xml" rel="self" type="application/rss+xml"/><item><title>The 28-Hour Bargain: How Continuous Access Evaluation Made Long-Lived Tokens Safe</title><link>https://paragmali.com/blog/the-28-hour-bargain-how-continuous-access-evaluation-made-lo/</link><guid isPermaLink="true">https://paragmali.com/blog/the-28-hour-bargain-how-continuous-access-evaluation-made-lo/</guid><description>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.</description><pubDate>Sat, 30 May 2026 00:00:00 GMT</pubDate><content:encoded>
**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).
&lt;h2&gt;1. Your Fired Employee Is Still Reading Email&lt;/h2&gt;
&lt;p&gt;09:00 Tuesday. The administrator disables the account at 09:01. At 09:23, the ex-employee&apos;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 &lt;a href=&quot;https://paragmali.com/blog/who-decided-this-token-is-good-a-field-guide-to-conditional-/&quot; rel=&quot;noopener&quot;&gt;Conditional Access&lt;/a&gt; could do about it [@rfc-6749].&lt;/p&gt;
&lt;p&gt;The window has a name now. It did not, for most of cloud identity&apos;s history. Microsoft&apos;s own documentation calls it &quot;the lag between when conditions change for a user, and when policy changes are enforced&quot; [@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.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &quot;Microsoft Entra ID&quot; is the rebranded name for what most engineers learned as &quot;Azure Active Directory&quot; or &quot;Azure AD.&quot; Microsoft announced the rename in July 2023 [@ms-entra-rename-2023]; the underlying service, tenants, app registrations, and APIs are unchanged. Throughout this article, &quot;Entra&quot; and the older &quot;Azure AD&quot; refer to the same identity platform.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;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, &lt;em&gt;and&lt;/em&gt; revoke a disabled user&apos;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.&lt;/p&gt;

Microsoft Entra&apos;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].
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2&gt;2. The Static-Expiry Compromise&lt;/h2&gt;
&lt;p&gt;In October 2012, Dick Hardt of Microsoft published RFC 6749 -- &lt;em&gt;The OAuth 2.0 Authorization Framework&lt;/em&gt; -- 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 &quot;usually with a short lifetime&quot; used by the client to access a protected resource. The word &lt;em&gt;usually&lt;/em&gt; 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.&lt;/p&gt;
&lt;p&gt;This was a deliberate trade. To see why it was rational, remember what came before.&lt;/p&gt;
&lt;h3&gt;Web Access Management: the model OAuth replaced&lt;/h3&gt;

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.
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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&apos;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.&lt;/p&gt;
&lt;p&gt;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&apos;t, and you trust that the lifetime is short enough.&lt;/p&gt;
&lt;p&gt;For a 2012 web of forum logins and consumer mashups, &quot;short enough&quot; was a defensible answer. For a 2020 enterprise running compliance-bound SaaS across thousands of employees, it was not.&lt;/p&gt;
&lt;h3&gt;The Zero Trust pressure&lt;/h3&gt;
&lt;p&gt;Two intellectual pressures forced the question. The first came from Google. In December 2014, Rory Ward and Betsy Beyer published &lt;em&gt;BeyondCorp: A New Approach to Enterprise Security&lt;/em&gt; in USENIX &lt;code&gt;;login:&lt;/code&gt; [@ward-beyer-2014-beyondcorp].Beyer would later co-author &lt;em&gt;Site Reliability Engineering&lt;/em&gt; (O&apos;Reilly, 2016); BeyondCorp came out of the same Google culture of evidence-driven infrastructure engineering. 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.&lt;/p&gt;
&lt;p&gt;The second pressure was bureaucratic. In August 2020, NIST published Special Publication 800-207, &lt;em&gt;Zero Trust Architecture&lt;/em&gt;, 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: &lt;em&gt;&quot;Authentication and authorization (both subject and device) are discrete functions performed before a session to an enterprise resource is established.&quot;&lt;/em&gt; 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.&lt;/p&gt;
&lt;h3&gt;A name for the problem&lt;/h3&gt;
&lt;p&gt;The third moment named the gap. On February 21, 2019, Atul Tulshibagwale, then an engineer at Google, published &lt;em&gt;Re-thinking federated identity with the Continuous Access Evaluation Protocol&lt;/em&gt; 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&apos;s per-request chattiness and OAuth&apos;s fire-and-forget expiry. We return to Tulshibagwale&apos;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.&lt;/p&gt;
&lt;p&gt;The OpenID Foundation working group that grew out of Tulshibagwale&apos;s proposal was originally chartered as the &lt;em&gt;Shared Signals &amp;amp; Events&lt;/em&gt; (SSE) working group. It was renamed &lt;em&gt;Shared Signals&lt;/em&gt; in subsequent years, but older industry write-ups from 2020-2022 still use the SSE abbreviation [@idsalliance-2022-11-cae].&lt;/p&gt;

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
&lt;p&gt;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 &lt;em&gt;why&lt;/em&gt; none of them worked is to understand the negative space CAE was designed to fill.&lt;/p&gt;
&lt;h2&gt;3. Three Patches, Three Failures&lt;/h2&gt;
&lt;p&gt;Between 2013 and the late 2010s, the OAuth community published three patches for RFC 6749&apos;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.&lt;/p&gt;
&lt;h3&gt;Patch 1: RFC 7009 -- the &lt;code&gt;/revoke&lt;/code&gt; endpoint (August 2013)&lt;/h3&gt;
&lt;p&gt;In August 2013, Torsten Lodderstedt of Deutsche Telekom, Stefanie Dronia, and Marius Scurtescu of Google published RFC 7009, &lt;em&gt;OAuth 2.0 Token Revocation&lt;/em&gt; [@rfc-7009]. The contribution was a standardized HTTP endpoint, &lt;code&gt;/revoke&lt;/code&gt;, 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 &quot;I&apos;m done with this token, please retire it.&quot;&lt;/p&gt;
&lt;p&gt;The failure mode is in the threat model. RFC 7009 is &lt;em&gt;client-initiated&lt;/em&gt;. 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 &lt;code&gt;/revoke&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;Worse, RFC 7009&apos;s Implementation Note (Section 3) is candid about self-contained tokens: the only standardized recourse is &quot;some (currently non-standardized) backend interaction between the authorization server and the resource server&quot; 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 &lt;em&gt;cryptographically valid until it expires&lt;/em&gt;. 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;Patch 2: RFC 7662 -- the &lt;code&gt;/introspect&lt;/code&gt; endpoint (October 2015)&lt;/h3&gt;
&lt;p&gt;Two years later, in October 2015, Justin Richer published RFC 7662, &lt;em&gt;OAuth 2.0 Token Introspection&lt;/em&gt; [@rfc-7662]. The mechanism: on every request, the resource server calls a &lt;code&gt;/introspect&lt;/code&gt; endpoint on the authorization server with the bearer token. The AS replies with the token&apos;s current state. If the token has been revoked, &lt;code&gt;/introspect&lt;/code&gt; returns &lt;code&gt;active: false&lt;/code&gt;, and the resource server denies the request.&lt;/p&gt;
&lt;p&gt;This is correct. It also reintroduces the WAM bottleneck that OAuth was designed to escape.&lt;/p&gt;
&lt;p&gt;For an AS serving billions of requests per day -- Microsoft Graph as one example, Google&apos;s IdP as another -- making &lt;code&gt;/introspect&lt;/code&gt; 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&apos;s existence.&lt;/p&gt;

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.
&lt;h3&gt;Patch 3: Make the token life so short revocation does not matter&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Microsoft tried it. The retrospective is unusually candid. On April 21, 2020, Alex Weinert, then Director of Identity Security at Microsoft, published &lt;em&gt;Moving towards real time policy and security enforcement&lt;/em&gt; on the Azure Active Directory Identity Blog [@weinert-2020-04-real-time]. (The original lives at post ID 1276933 on Microsoft&apos;s tech community; the full body is preserved in Microsoft&apos;s Japanese translation on the jpazureid GitHub mirror [@jpazureid-blog-1-japanese].) The post names the failure mode in one sentence:&lt;/p&gt;

&quot;We have experimented with the &quot;blunt object&quot; approach of reduced token lifetimes but found they can degrade user experiences and reliability without eliminating risks.&quot; -- Alex Weinert, Microsoft, April 21, 2020 [@weinert-2020-04-real-time]
&lt;p&gt;Two things break. First, &lt;em&gt;user experience and reliability&lt;/em&gt;. 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, &lt;em&gt;it does not eliminate the risk&lt;/em&gt;. 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.&lt;/p&gt;
&lt;p&gt;This was the third failure. The negative space across the three patches defines the shape any real solution has to take: it must be &lt;em&gt;server-initiated&lt;/em&gt; (not RFC 7009), it must be &lt;em&gt;push-based&lt;/em&gt; rather than per-request poll (not RFC 7662), and it must &lt;em&gt;separate revocation from expiry&lt;/em&gt; 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.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the patches all fail, the next move has to be architectural. The first published statement of that architecture was Atul Tulshibagwale&apos;s February 2019 Google blog post -- and the move he proposed is the one Microsoft would ship three years later.&lt;/p&gt;
&lt;h2&gt;4. Four Generations of Session Enforcement&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;Generation 0: WAM (pre-2012)&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;Generation 1: Static-expiry JWT (2012-2020)&lt;/h3&gt;
&lt;p&gt;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 &lt;a href=&quot;https://paragmali.com/blog/the-thirteen-months-that-made-zero-trust-unavoidable-the-win/&quot; rel=&quot;noopener&quot;&gt;Zero Trust&lt;/a&gt; to treat sessions as continuously re-evaluated.&lt;/p&gt;
&lt;h3&gt;Generation 2: Microsoft CAE (limited preview April 2020, GA January 10, 2022)&lt;/h3&gt;
&lt;p&gt;The first production solution. Limited preview launched in April 2020 with Alex Weinert&apos;s &lt;em&gt;Moving towards real time policy and security enforcement&lt;/em&gt; 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].&lt;/p&gt;
&lt;p&gt;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 &lt;code&gt;claims&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;The Gen-2 limitation that motivated Gen 3: the wire format is &lt;em&gt;Microsoft-internal&lt;/em&gt;. A SaaS vendor that wants the same revocation properties for its own resource provider cannot use Microsoft&apos;s CAE channel. The protocol does not federate.&lt;/p&gt;
&lt;h3&gt;Generation 3: OpenID SSF 1.0 + CAEP 1.0 + RISC 1.0 (Final Specifications, September 2, 2025)&lt;/h3&gt;
&lt;p&gt;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].&lt;/p&gt;
&lt;p&gt;The wire envelope is IETF RFC 8417&apos;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 &lt;em&gt;vocabulary&lt;/em&gt; of events that can ride that envelope.&lt;/p&gt;

IETF RFC 8417&apos;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&apos;s internal CAE protocol [@rfc-8417].
&lt;p&gt;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&apos;s internal protocol and the OpenID profiles to converge on the same wire format without coordination [@rfc-8417].&lt;/p&gt;

flowchart TD
    L4[&quot;Layer 4: Event vocabularies&lt;br /&gt;CAEP 1.0 (session) and RISC 1.0 (account)&quot;]
    L3[&quot;Layer 3: Subscription and stream model&lt;br /&gt;OpenID SSF 1.0&quot;]
    L2[&quot;Layer 2: HTTP transport&lt;br /&gt;RFC 8935 push, RFC 8936 poll&quot;]
    L1[&quot;Layer 1: Signed event envelope&lt;br /&gt;RFC 8417 Security Event Token (SET)&quot;]
    L4 --&amp;gt; L3
    L3 --&amp;gt; L2
    L2 --&amp;gt; L1
&lt;p&gt;The generation chain has a documented engineering reason for each transition. The comparison matrix below pulls the essentials together.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Revocation latency&lt;/th&gt;
&lt;th&gt;Strengths&lt;/th&gt;
&lt;th&gt;Weaknesses&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;WAM (Gen 0)&lt;/td&gt;
&lt;td&gt;pre-2012&lt;/td&gt;
&lt;td&gt;Instant&lt;/td&gt;
&lt;td&gt;Authoritative state, instant enforcement&lt;/td&gt;
&lt;td&gt;No federation, per-request bottleneck&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static-expiry JWT (Gen 1)&lt;/td&gt;
&lt;td&gt;2012-2020&lt;/td&gt;
&lt;td&gt;Up to token lifetime (1h-24h)&lt;/td&gt;
&lt;td&gt;O(1) RP validation, federation works&lt;/td&gt;
&lt;td&gt;No revocation; fired-employee window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short-lifetime patch&lt;/td&gt;
&lt;td&gt;mid-2010s&lt;/td&gt;
&lt;td&gt;Minutes&lt;/td&gt;
&lt;td&gt;Conceptually simple&lt;/td&gt;
&lt;td&gt;Load amplification, window remains, UX degradation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RFC 7662 introspection&lt;/td&gt;
&lt;td&gt;2015 onward&lt;/td&gt;
&lt;td&gt;Instant&lt;/td&gt;
&lt;td&gt;Standardized, works for opaque tokens&lt;/td&gt;
&lt;td&gt;AS becomes per-request critical path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft CAE (Gen 2)&lt;/td&gt;
&lt;td&gt;2020-2022&lt;/td&gt;
&lt;td&gt;Up to 15 min critical; instant IP&lt;/td&gt;
&lt;td&gt;Push, decoupled from request rate, long tokens safe&lt;/td&gt;
&lt;td&gt;Microsoft-internal protocol; tiny RP set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenID SSF/CAEP (Gen 3)&lt;/td&gt;
&lt;td&gt;2025 onward&lt;/td&gt;
&lt;td&gt;Vendor-dependent&lt;/td&gt;
&lt;td&gt;Vendor-neutral standard, cross-SaaS&lt;/td&gt;
&lt;td&gt;Receiver adoption still early&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

flowchart LR
    G0[&quot;Gen 0: WAM&lt;br /&gt;per-request PDP&quot;]
    G1[&quot;Gen 1: Static-expiry JWT&lt;br /&gt;RFC 6749 (2012)&quot;]
    G2[&quot;Gen 2: Microsoft CAE&lt;br /&gt;GA January 2022&quot;]
    G3[&quot;Gen 3: OpenID SSF and CAEP&lt;br /&gt;Final September 2025&quot;]
    G0 -- &quot;cloud scale and federation&quot; --&amp;gt; G1
    G1 -- &quot;fired-employee window, patches fail&quot; --&amp;gt; G2
    G2 -- &quot;Microsoft-only, no cross-SaaS&quot; --&amp;gt; G3
&lt;p&gt;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.&lt;/p&gt;
&lt;h2&gt;5. Subscription, Claims Challenge, Extended Lifetime&lt;/h2&gt;
&lt;p&gt;Three innovations, none new in isolation, all unprecedented in combination. This is the section where you see the trick.&lt;/p&gt;
&lt;p&gt;Atul Tulshibagwale&apos;s 2019 framing names the move: &quot;Our vision for continuous access evaluation is based on a publish-and-subscribe (&apos;pub-sub&apos;) approach... It&apos;s complementary to federated or cert-based authentication... It&apos;s not as chatty as WAM... It doesn&apos;t impact latency for user access&quot; [@tulshibagwale-2019-google-blog]. Pub-sub is the third option between WAM&apos;s per-request chattiness and RFC 6749&apos;s fire-and-forget. Subscription is the channel; claims challenge is the wire-level handshake; extended lifetime is the user-experience prize.&lt;/p&gt;
&lt;h3&gt;Part 1: Subscription&lt;/h3&gt;
&lt;p&gt;Microsoft&apos;s CAE concept page describes the architecture in one sentence that rewards close reading:&lt;/p&gt;

Timely response to policy violations or security issues really requires a &apos;conversation&apos; between the token issuer Microsoft Entra, and the relying party (enlightened app). -- Microsoft Learn, *Continuous access evaluation in Microsoft Entra* [@ms-cae-concept]
&lt;p&gt;The word &lt;em&gt;conversation&lt;/em&gt; is the architecture. The relying party (a CAE-aware Microsoft 365 workload such as Exchange Online) subscribes to a finite, documented set of &lt;em&gt;critical events&lt;/em&gt; 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].&lt;/p&gt;
&lt;p&gt;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 &lt;em&gt;events&lt;/em&gt;, not the rate of &lt;em&gt;requests&lt;/em&gt;. Push, not poll.&lt;/p&gt;
&lt;h3&gt;Part 2: The claims challenge&lt;/h3&gt;
&lt;p&gt;When state at the RP changes -- because a push event has arrived saying &quot;this user&apos;s password has been reset&quot; -- the RP cannot reach into a request that has already been accepted and is being served. CAE is in-band with the &lt;em&gt;next&lt;/em&gt; request, not the current one. The next time the client presents the stale token, the RP rejects it with &lt;code&gt;HTTP 401&lt;/code&gt; and a specific header:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error=&quot;insufficient_claims&quot;,
                  claims=&quot;eyJhY2Nlc3NfdG9rZW4iOnsiYWNyc...&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;claims&lt;/code&gt; 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].&lt;/p&gt;

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=&quot;insufficient_claims&quot;` 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 `[&quot;cp1&quot;]` [@ms-cae-app-resilience].
&lt;p&gt;This is the move that defeats RFC 7009. Revocation is initiated by the &lt;em&gt;resource provider&apos;s view of the IdP&apos;s state&lt;/em&gt;, not by the token holder. A fired employee&apos;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.&lt;/p&gt;
&lt;p&gt;{`
// A real-shape WWW-Authenticate header from a CAE-aware resource provider.
// The &apos;claims&apos; parameter is base64url-encoded JSON.
const header = &apos;Bearer error=&quot;insufficient_claims&quot;, claims=&quot;eyJhY2Nlc3NfdG9rZW4iOnsibmJmIjp7ImVzc2VudGlhbCI6dHJ1ZSwgInZhbHVlIjoiMTcyMDQ4MDA0MyJ9fX0=&quot;&apos;;&lt;/p&gt;
&lt;p&gt;// Extract the claims parameter
const match = header.match(/claims=&quot;([^&quot;]+)&quot;/);
const b64 = match ? match[1] : null;&lt;/p&gt;
&lt;p&gt;// base64url decode (Node &apos;Buffer&apos; would work; here we use the browser-safe approach)
function b64urlDecode(s) {
  s = s.replace(/-/g, &apos;+&apos;).replace(/_/g, &apos;/&apos;);
  while (s.length % 4) s += &apos;=&apos;;
  return atob(s);
}&lt;/p&gt;
&lt;p&gt;const claimsJson = b64urlDecode(b64);
console.log(JSON.parse(claimsJson));
// {
//   &quot;access_token&quot;: {
//     &quot;nbf&quot;: {
//       &quot;essential&quot;: true,
//       &quot;value&quot;: &quot;1720480043&quot;
//     }
//   }
// }
// MSAL reads this and requests a new token whose &apos;nbf&apos; (not-before) is at least
// the supplied timestamp -- i.e., a token issued after the state change.
`}&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;nbf&lt;/code&gt; (not-before) claim challenge is the most common shape: the RP is telling the client &quot;give me a token issued after this moment.&quot; 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.&lt;/p&gt;
&lt;h3&gt;Part 3: Extended lifetime, the prize&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Microsoft documents the upper bound as &quot;up to 28 hours&quot; 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.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;The full round trip&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;

sequenceDiagram
    participant Admin
    participant Entra as Microsoft Entra
    participant Client as Client (MSAL)
    participant RP as Resource Provider (e.g. Exchange Online)
    Admin-&amp;gt;&amp;gt;Entra: Disable user account
    Entra-&amp;gt;&amp;gt;RP: Push critical-event SET (account disabled)
    Note over RP: Updates cached revocation state for (sub, tenant)
    Client-&amp;gt;&amp;gt;RP: GET /me/messages (Authorization Bearer old token)
    Note over RP: Validates JWT signature O(1), checks cached state
    RP--&amp;gt;&amp;gt;Client: 401 plus WWW-Authenticate insufficient_claims
    Note over Client: MSAL parses claims challenge from header
    Client-&amp;gt;&amp;gt;Entra: Token request with claims
    Note over Entra: Checks current user state, account is disabled
    Entra--&amp;gt;&amp;gt;Client: 400 invalid_grant or interactive re-auth required
    Note over Client: User cannot recover, session terminates
&lt;p&gt;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&apos;s fired-employee window. The 28-hour token is not the &lt;em&gt;cost&lt;/em&gt; of CAE; it is what CAE &lt;em&gt;purchases&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is the design. What does it actually do in production today, and where does it stop?&lt;/p&gt;
&lt;h2&gt;6. CAE as Deployed in Microsoft Entra (2026)&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;Critical event evaluation events&lt;/h3&gt;
&lt;p&gt;Microsoft Learn lists exactly five events that drive &lt;em&gt;critical event evaluation&lt;/em&gt; at the IdP-to-RP boundary [@ms-cae-concept]:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A user account is deleted or disabled.&lt;/li&gt;
&lt;li&gt;A password for a user is changed or reset.&lt;/li&gt;
&lt;li&gt;Multi-factor authentication is enabled for the user.&lt;/li&gt;
&lt;li&gt;An administrator explicitly revokes all refresh tokens for a user.&lt;/li&gt;
&lt;li&gt;High user risk is detected by Microsoft Entra ID Protection.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These five events propagate from Entra to the participating CAE-aware resource providers via the push channel. Microsoft&apos;s published service-level objective is &quot;up to 15 minutes&quot; for critical-event propagation [@ms-cae-concept]. That is not the same as &quot;instant.&quot; The phrase to avoid is &quot;CAE delivers instant revocation&quot;; the accurate phrase is &quot;CAE delivers near-real-time revocation, typically within 15 minutes for critical events.&quot;&lt;/p&gt;
&lt;p&gt;A separate scenario -- &lt;em&gt;Conditional Access policy evaluation&lt;/em&gt; -- covers network and IP-location changes. Here the SLA is different: IP-location enforcement is &lt;strong&gt;instant&lt;/strong&gt; per Microsoft&apos;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.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Propagation&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Account deleted or disabled&lt;/td&gt;
&lt;td&gt;Entra ID directory&lt;/td&gt;
&lt;td&gt;Up to 15 min&lt;/td&gt;
&lt;td&gt;Honored by Exchange Online, SharePoint Online, Teams, Graph (CA)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Password changed or reset&lt;/td&gt;
&lt;td&gt;Entra ID directory&lt;/td&gt;
&lt;td&gt;Up to 15 min&lt;/td&gt;
&lt;td&gt;Same RP set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MFA enabled for user&lt;/td&gt;
&lt;td&gt;Entra ID directory&lt;/td&gt;
&lt;td&gt;Up to 15 min&lt;/td&gt;
&lt;td&gt;Same RP set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All refresh tokens revoked (admin)&lt;/td&gt;
&lt;td&gt;Entra ID admin action&lt;/td&gt;
&lt;td&gt;Up to 15 min&lt;/td&gt;
&lt;td&gt;Same RP set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High user risk detected&lt;/td&gt;
&lt;td&gt;Entra ID Protection&lt;/td&gt;
&lt;td&gt;Up to 15 min&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;SharePoint Online does not honor user-risk events&lt;/strong&gt; [@ms-cae-concept]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IP location changed (CA policy)&lt;/td&gt;
&lt;td&gt;Resource-provider observation&lt;/td&gt;
&lt;td&gt;Instant&lt;/td&gt;
&lt;td&gt;Conditional Access policy evaluation path; strict location enforcement [@ms-strict-location-enforcement]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft Defender for Endpoint and Microsoft Intune (MDM) are &lt;em&gt;signal sources&lt;/em&gt; into Conditional Access. They contribute to the risk score and device-compliance state that drive CA policy decisions, but they are &lt;strong&gt;not&lt;/strong&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The SharePoint Online user-risk caveat is a concrete example of why &quot;CAE-aware&quot; 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&apos;s enforcement [@ms-cae-concept].&lt;/p&gt;
&lt;h3&gt;Workloads that participate&lt;/h3&gt;
&lt;p&gt;The CAE-aware resource-provider set, per Microsoft Learn [@ms-cae-concept]:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Exchange Online&lt;/strong&gt; -- full CAE consumer (initial implementation, October 2020).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SharePoint Online&lt;/strong&gt; -- full CAE consumer, with the user-risk caveat noted above.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Teams&lt;/strong&gt; -- full CAE consumer (initial implementation), per Alex Simons&apos;s January 2022 GA announcement [@simons-2022-01-ga-rss].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Graph&lt;/strong&gt; -- consumes Conditional Access policy evaluation events (the IP-location instant path); narrower scope than the M365 productivity workloads.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Client-side support is also explicit. Microsoft&apos;s compatibility tables in the CAE concept page enumerate which client and server combinations are &lt;em&gt;Supported&lt;/em&gt;, &lt;em&gt;Partially supported&lt;/em&gt;, or &lt;em&gt;Not Supported&lt;/em&gt; on every major operating system and form factor [@ms-cae-concept]. Office web apps against SharePoint Online and Exchange Online are documented as &lt;em&gt;Not Supported&lt;/em&gt; on several combinations; every Teams client surface shows as &lt;em&gt;Partially supported&lt;/em&gt;. 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.&lt;/p&gt;
&lt;h3&gt;Tokens and clients&lt;/h3&gt;
&lt;p&gt;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&apos;s own release stream. Microsoft Learn&apos;s &lt;em&gt;Use Continuous Access Evaluation enabled APIs&lt;/em&gt; page enumerates per-SDK guidance [@ms-cae-app-resilience]. The app registration must also declare the &lt;code&gt;xms_cc&lt;/code&gt; client capability with value &lt;code&gt;[&quot;cp1&quot;]&lt;/code&gt; to advertise CAE-handling support to the IdP [@ms-cae-app-resilience].&lt;/p&gt;

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 `&quot;cp1&quot;` (Microsoft&apos;s developer docs show both `&quot;cp1&quot;` and `&quot;CP1&quot;`; negotiation is case-insensitive but the token claim is lowercase). It signals that the client&apos;s MSAL implementation can decode and act on a `WWW-Authenticate: Bearer error=&quot;insufficient_claims&quot;` 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].

A Microsoft 365 workload (Exchange Online, SharePoint Online, Teams, or Microsoft Graph for Conditional Access policy) that consumes Entra&apos;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 &quot;resource server&quot;; in CAE, &quot;resource provider&quot; specifically means a workload that has implemented the CAE participation contract with Entra [@ms-cae-concept].

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].
&lt;h3&gt;A migration note for older tenants&lt;/h3&gt;
&lt;p&gt;Tenant administrators with Conditional Access policies that pre-date GA may carry legacy &quot;strict location enforcement&quot; preview settings. Microsoft has since migrated the feature into GA, and the current Microsoft Learn page &lt;em&gt;Strictly enforce location policies using continuous access evaluation&lt;/em&gt; 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2&gt;7. Competing Approaches and Their Relation to CAE&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;CAE versus OpenID SSF and CAEP 1.0&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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&apos;s CAEP Hub interoperated as both transmitter and receiver with Cisco Duo, Okta, SailPoint, and Helisoft on the &lt;code&gt;session-revoked&lt;/code&gt; CAEP event [@sgnl-2024-04-interop]. Okta&apos;s own blog characterizes the March 2025 London summit as &quot;a significant industry shift toward interconnected, real-time security&quot; with &quot;interoperable implementations from pioneers like Okta, Google, IBM, Omnissa, SailPoint, and Thales&quot; [@okta-shared-signals].&lt;/p&gt;
&lt;p&gt;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&apos;s and Google&apos;s prior implementations.&lt;/p&gt;
&lt;h3&gt;CAE versus RFC 7662 introspection&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;CAE versus DPoP and mTLS-bound tokens&lt;/h3&gt;
&lt;p&gt;Complementary, not competitive. The threat model for CAE is &lt;em&gt;stale authorization&lt;/em&gt;: 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 &lt;em&gt;stolen tokens&lt;/em&gt;: an attacker holding a bearer token that was legitimately issued to a different party.&lt;/p&gt;
&lt;p&gt;RFC 9449, &lt;em&gt;OAuth 2.0 Demonstrating Proof of Possession (DPoP)&lt;/em&gt;, 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, &lt;em&gt;OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens&lt;/em&gt;, 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;CAE versus BeyondCorp-style identity-aware proxies&lt;/h3&gt;
&lt;p&gt;Different architectural layer. Identity-aware proxies (Google IAP, Cloudflare Access, AWS Verified Access) sit &lt;em&gt;in front of&lt;/em&gt; 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.&lt;/p&gt;
&lt;h3&gt;A note on PRT theft&lt;/h3&gt;
&lt;p&gt;CAE does not address attacks at the &lt;a href=&quot;https://paragmali.com/blog/inside-the-primary-refresh-token-the-cryptographic-seam-betw/&quot; rel=&quot;noopener&quot;&gt;Primary Refresh Token (PRT)&lt;/a&gt; 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&apos;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 &lt;em&gt;after&lt;/em&gt; 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.&lt;/p&gt;
&lt;h3&gt;Mapping the design space&lt;/h3&gt;
&lt;p&gt;The table is the cleanest way to see who competes with whom and who composes with whom.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Solves&lt;/th&gt;
&lt;th&gt;Composes with CAE&lt;/th&gt;
&lt;th&gt;Competes with CAE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;OpenID SSF/CAEP 1.0&lt;/td&gt;
&lt;td&gt;Cross-vendor revocation&lt;/td&gt;
&lt;td&gt;Yes (CAE is a Microsoft implementation of the same pattern)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RFC 7662 introspection&lt;/td&gt;
&lt;td&gt;Opaque-token revocation at modest scale&lt;/td&gt;
&lt;td&gt;Parallel path&lt;/td&gt;
&lt;td&gt;At hyperscale only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DPoP (RFC 9449)&lt;/td&gt;
&lt;td&gt;Sender-constrained tokens&lt;/td&gt;
&lt;td&gt;Yes (compose for full coverage)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mTLS-bound tokens (RFC 8705)&lt;/td&gt;
&lt;td&gt;Sender-constrained tokens&lt;/td&gt;
&lt;td&gt;Yes (compose for full coverage)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Identity-aware proxy&lt;/td&gt;
&lt;td&gt;Per-request policy at the proxy edge&lt;/td&gt;
&lt;td&gt;Composes for proxy-fronted workloads&lt;/td&gt;
&lt;td&gt;Different layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short access-token lifetime&lt;/td&gt;
&lt;td&gt;Reduces revocation window mechanically&lt;/td&gt;
&lt;td&gt;Falls back when CAE not available&lt;/td&gt;
&lt;td&gt;Yes, and loses on the trade&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The reader who came to this article expecting a binary contest -- &quot;which one wins?&quot; -- 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.&lt;/p&gt;
&lt;p&gt;That handles deployment. But every architecture has limits. The reader has spent six sections climbing; the next section is the &lt;em&gt;humility&lt;/em&gt; beat where the descent begins.&lt;/p&gt;
&lt;h2&gt;8. Theoretical Limits: What CAE Cannot Do&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;Limit 1: cannot revoke a token already in flight&lt;/h3&gt;
&lt;p&gt;Once a request has been accepted and is being served by the resource provider, CAE cannot reach into the RP&apos;s execution thread and abort it. The revocation applies to the &lt;em&gt;next&lt;/em&gt; 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.&lt;/p&gt;
&lt;h3&gt;Limit 2: cannot beat the 15-minute critical-event SLA for most events&lt;/h3&gt;
&lt;p&gt;Microsoft&apos;s published SLA is &quot;up to 15 minutes&quot; 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&apos;s global infrastructure is what produces the budget. Smaller-scale deployments demonstrate much better numbers: TigerIdentity&apos;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&apos;s particular deployment chooses 15 minutes because the alternative at its fan-out scale is prohibitively expensive.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; 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&apos;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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Limit 3: cannot cover non-CAE-aware clients or resource providers&lt;/h3&gt;
&lt;p&gt;CAE is a cooperative protocol. Both the client (via the &lt;code&gt;xms_cc=cp1&lt;/code&gt; 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&apos;s events have no consumer. The CAE-aware portion of the estate enjoys the new contract; the rest carries the old security debt unchanged.&lt;/p&gt;
&lt;p&gt;This is why audit posture matters. A tenant administrator who wants to argue that revocation latency for their workforce is &quot;under 15 minutes&quot; must be able to demonstrate that the client and RP combinations the workforce actually uses are CAE-aware. Microsoft&apos;s compatibility tables [@ms-cae-concept] document several Office-web-app and OneDrive-Win32-versus-SharePoint combinations as &lt;em&gt;Not Supported&lt;/em&gt; or &lt;em&gt;Partially supported&lt;/em&gt;; those gaps are part of the tenant&apos;s effective revocation profile, not someone else&apos;s problem.&lt;/p&gt;
&lt;h3&gt;Limit 4: cannot help if the resource provider itself is compromised&lt;/h3&gt;
&lt;p&gt;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 &lt;em&gt;cooperative&lt;/em&gt; 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.&lt;/p&gt;
&lt;p&gt;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&apos;s design has no remedy. RP integrity is a prerequisite, not a guarantee.&lt;/p&gt;
&lt;h3&gt;Limit 5: cannot revoke a stolen PRT before it mints a new access token&lt;/h3&gt;
&lt;p&gt;As noted in Section 7, the Primary Refresh Token sits outside CAE&apos;s scope. A stolen PRT mints new CAE-aware access tokens that Entra treats as legitimately issued, because from Entra&apos;s perspective they &lt;em&gt;are&lt;/em&gt; 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.&lt;/p&gt;
&lt;p&gt;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].&lt;/p&gt;
&lt;h3&gt;The bounded design space&lt;/h3&gt;
&lt;p&gt;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&apos;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 &lt;em&gt;bounded&lt;/em&gt; -- 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.&lt;/p&gt;
&lt;p&gt;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?&lt;/p&gt;
&lt;h2&gt;9. Open Problems (2026)&lt;/h2&gt;
&lt;p&gt;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 &lt;em&gt;adoption&lt;/em&gt; and &lt;em&gt;extension&lt;/em&gt; look like. Five live problems.&lt;/p&gt;
&lt;h3&gt;1. Third-party SaaS receiver-adoption depth&lt;/h3&gt;
&lt;p&gt;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 &lt;code&gt;session-revoked&lt;/code&gt; CAEP event at launch [@google-workspace-ssf-api]. That is one event out of CAEP 1.0&apos;s eight. The SaaS long tail -- Workday, ServiceNow, GitHub Enterprise, Atlassian, Salesforce -- has not, as of the Final Specification&apos;s first anniversary, shipped public receivers.&lt;/p&gt;
&lt;p&gt;For the &quot;fired employee with N SaaS apps&quot; scenario to be fully solved, every SaaS app in the user&apos;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&apos;s real-world value over the next several years.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 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&apos;s industry-wide impact.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2. CAE for non-human and agent identities&lt;/h3&gt;
&lt;p&gt;CAEP subject identifiers assume user-shaped or device-shaped subjects [@openid-caep-1_0]. Workload identities, service principals, and emerging &lt;a href=&quot;https://paragmali.com/blog/agentic-identity-on-windows-when-the-process-acting-on-your-/&quot; rel=&quot;noopener&quot;&gt;AI-agent identities&lt;/a&gt; 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 &lt;em&gt;Conditional Access for Agent Identities&lt;/em&gt; 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.&lt;/p&gt;
&lt;h3&gt;3. Cross-IdP federation of SSF streams&lt;/h3&gt;
&lt;p&gt;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&apos;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.&lt;/p&gt;
&lt;h3&gt;4. Bidirectional signal sharing&lt;/h3&gt;
&lt;p&gt;Today&apos;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.&lt;/p&gt;
&lt;h3&gt;5. Reason-code convergence between CAEP and RISC&lt;/h3&gt;
&lt;p&gt;CAEP 1.0 and RISC 1.0 cover overlapping ground around credential mutation. CAEP defines a &lt;code&gt;credential-change&lt;/code&gt; event; RISC defines &lt;code&gt;account-credential-change-required&lt;/code&gt; [@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.&lt;/p&gt;

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&apos;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.
&lt;p&gt;Given all this -- the architecture, the limits, the open frontier -- what should you actually do this week in your tenant and your code?&lt;/p&gt;
&lt;h2&gt;10. Turning CAE On in Your Tenant and Your Code&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;For the tenant administrator&lt;/h3&gt;
&lt;p&gt;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 &lt;strong&gt;Conditional Access -&amp;gt; Session controls -&amp;gt; Customize continuous access evaluation&lt;/strong&gt;. The relevant signals to check:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CAE enablement state.&lt;/strong&gt; Confirm that the tenant-wide CAE policy is set to &lt;em&gt;Enabled&lt;/em&gt; rather than &lt;em&gt;Disabled&lt;/em&gt; or &lt;em&gt;Strict location&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per-policy disable flags.&lt;/strong&gt; Some legacy CA policies carry per-policy CAE overrides. Audit any that explicitly disable CAE; the right default is to honor it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strict location enforcement migration.&lt;/strong&gt; Tenants with pre-GA &quot;strict location enforcement&quot; preview settings should verify that the policy has migrated to the current GA configuration model documented in Microsoft Learn [@ms-strict-location-enforcement].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit log baselines.&lt;/strong&gt; Sign-in logs surface &lt;code&gt;signInEventTypes&lt;/code&gt; 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.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;For the MSAL client developer&lt;/h3&gt;
&lt;p&gt;The client side has three things to confirm and one thing to test:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;MSAL version.&lt;/strong&gt; 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&apos;s own release stream. Microsoft Learn&apos;s &lt;em&gt;Use Continuous Access Evaluation enabled APIs&lt;/em&gt; page enumerates the per-SDK guidance [@ms-cae-app-resilience]. Earlier major-version lines do not handle the claims challenge transparently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Capability declaration.&lt;/strong&gt; The app registration must declare &lt;code&gt;xms_cc&lt;/code&gt; with value &lt;code&gt;[&quot;cp1&quot;]&lt;/code&gt; (lowercase is the canonical token-claim form; uppercase &lt;code&gt;&quot;CP1&quot;&lt;/code&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Claims-challenge handling.&lt;/strong&gt; MSAL helpers do this transparently in current SDK versions, but custom HTTP pipelines that bypass MSAL must implement the &lt;code&gt;WWW-Authenticate: Bearer error=&quot;insufficient_claims&quot;&lt;/code&gt; response handler manually. Decode the &lt;code&gt;claims&lt;/code&gt; parameter (base64url), pass it to &lt;code&gt;AcquireTokenInteractive&lt;/code&gt; or the equivalent, retry the original request with the new token.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;End-to-end test.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;{`
// 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.&lt;/p&gt;
&lt;p&gt;// A real-shape AccessTokenEntity from MSAL JS cache
const tokenEntity = {
  homeAccountId: &apos;abc.def-tenant&apos;,
  environment: &apos;login.microsoftonline.com&apos;,
  credentialType: &apos;AccessToken&apos;,
  clientId: &apos;11111111-2222-3333-4444-555555555555&apos;,
  tenantId: &apos;tenant-id&apos;,
  target: &apos;User.Read Mail.Read&apos;,
  // expiresOn is up to ~28 hours after cachedAt for CAE-aware sessions
  cachedAt: &apos;1748534400&apos;,
  expiresOn: &apos;1748635200&apos;,  // 28h later
  extendedExpiresOn: &apos;1748635200&apos;,
  // Capability declaration the app advertised at acquisition time
  requestedClaims: { xms_cc: [&apos;cp1&apos;] }
};&lt;/p&gt;
&lt;p&gt;const ttlSeconds = parseInt(tokenEntity.expiresOn) - parseInt(tokenEntity.cachedAt);
const ttlHours = ttlSeconds / 3600;
const isCaeAware = tokenEntity.requestedClaims &amp;amp;&amp;amp;
                   tokenEntity.requestedClaims.xms_cc &amp;amp;&amp;amp;
                   tokenEntity.requestedClaims.xms_cc
                     .some(c =&amp;gt; c.toLowerCase() === &apos;cp1&apos;);&lt;/p&gt;
&lt;p&gt;console.log(&apos;TTL hours:&apos;, ttlHours.toFixed(1));
console.log(&apos;CAE-aware:&apos;, 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.
`}&lt;/p&gt;
&lt;h3&gt;For the custom-API author&lt;/h3&gt;
&lt;p&gt;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&apos;s &lt;code&gt;damienbod/AspNetCoreMeIDCAE&lt;/code&gt; 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:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;xms_cc=cp1&lt;/code&gt; capability declaration on both the client and the API app registrations.&lt;/li&gt;
&lt;li&gt;The Microsoft.Identity.Web claims-challenge handling on the API side.&lt;/li&gt;
&lt;li&gt;The Razor Page client flow that catches a &lt;code&gt;401&lt;/code&gt; with the challenge header and re-acquires the token.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 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 &lt;em&gt;high user risk detected&lt;/em&gt; 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].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Observability&lt;/h3&gt;
&lt;p&gt;Sign-in logs and audit logs are where CAE behavior shows up. Look for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sign-in logs&lt;/strong&gt;: filter by &lt;code&gt;signInEventTypes&lt;/code&gt; containing CAE-related entries. CAE-aware sign-ins have a different telemetry shape than non-CAE sign-ins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token-issuance events&lt;/strong&gt;: refresh-token issuance against CAE-aware app registrations should show the extended lifetime.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit log revocation entries&lt;/strong&gt;: administrator revocation actions and Identity-Protection-driven revocations appear here; cross-correlate with the resource-provider-side telemetry to validate end-to-end propagation.&lt;/li&gt;
&lt;/ul&gt;

Use Microsoft Graph PowerShell to enumerate the tenant&apos;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.
&lt;h3&gt;Defaults are good&lt;/h3&gt;
&lt;p&gt;The most common engineering recommendation here is to leave the defaults alone. CAE on, default tenant settings, current MSAL clients, &lt;code&gt;xms_cc=cp1&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2&gt;11. FAQ and Coda&lt;/h2&gt;

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].

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.

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].

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].

*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].

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.
&lt;h3&gt;Coda: the bargain&lt;/h3&gt;
&lt;p&gt;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 &lt;code&gt;/revoke&lt;/code&gt; endpoint, the &lt;code&gt;/introspect&lt;/code&gt; 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.&lt;/p&gt;
&lt;p&gt;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 &lt;code&gt;/revoke&lt;/code&gt;. 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;continuous-access-evaluation&quot; keyTerms={[
  { term: &quot;Continuous Access Evaluation (CAE)&quot;, definition: &quot;Microsoft Entra&apos;s push-subscription channel that lets a resource provider revoke an already-issued access token in near-real-time without waiting for expiry.&quot; },
  { term: &quot;Web Access Management (WAM)&quot;, definition: &quot;Pre-2012 enterprise identity pattern with synchronous per-request PDP round-trips; instant revocation but no scale or federation.&quot; },
  { term: &quot;Security Event Token (SET)&quot;, definition: &quot;IETF RFC 8417 signed-JWT envelope for transmitting security events; the wire format under CAEP, SSF, and RISC.&quot; },
  { term: &quot;Claims Challenge&quot;, definition: &quot;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.&quot; },
  { term: &quot;xms_cc capability&quot;, definition: &quot;App-registration claim with canonical value cp1 (case-insensitive) by which a client advertises CAE-handling support to Entra.&quot; },
  { term: &quot;Resource Provider (RP) in CAE&quot;, definition: &quot;Exchange Online, SharePoint Online, Teams, or Microsoft Graph; a workload that consumes Entra&apos;s critical-event notifications.&quot; },
  { term: &quot;OpenID Shared Signals Framework (SSF)&quot;, definition: &quot;Vendor-neutral OpenID Foundation Final Specification (September 2, 2025) for stream-based SET delivery between transmitters and receivers.&quot; },
  { term: &quot;Continuous Access Evaluation Profile (CAEP)&quot;, definition: &quot;OpenID Foundation Final Specification (September 2, 2025) defining session-level event types atop SSF.&quot; }
]} questions={[
  { q: &quot;Why does the standard OAuth 2.0 /revoke endpoint not solve the fired-employee problem?&quot;, a: &quot;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.&quot; },
  { q: &quot;Why is RFC 7662 introspection unworkable as the next generation of revocation at hyperscale?&quot;, a: &quot;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.&quot; },
  { q: &quot;What three innovations interlock to make CAE work, and why are they only meaningful in combination?&quot;, a: &quot;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&apos;s fired-employee window.&quot; },
  { q: &quot;Why is the 15-minute critical-event SLA not a fundamental limit?&quot;, a: &quot;Because it is engineering economics at Microsoft 365&apos;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.&quot; },
  { q: &quot;Which Microsoft workloads are CAE-aware resource providers, and which are signal sources rather than RPs?&quot;, a: &quot;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.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>continuous-access-evaluation</category><category>microsoft-entra</category><category>oauth2</category><category>zero-trust</category><category>openid-shared-signals</category><category>identity-security</category><category>conditional-access</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Who Decided This Token Is Good? A Field Guide to Conditional Access and Entra ID Protection</title><link>https://paragmali.com/blog/who-decided-this-token-is-good-a-field-guide-to-conditional-/</link><guid isPermaLink="true">https://paragmali.com/blog/who-decided-this-token-is-good-a-field-guide-to-conditional-/</guid><description>A wire-level tour of Microsoft Entra Conditional Access, Identity Protection, and Continuous Access Evaluation, plus the five things they cannot do.</description><pubDate>Tue, 26 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Conditional Access is Microsoft&apos;s Zero Trust policy engine, not a feature.** Every interactive sign-in to a licensed Microsoft 365 tenant flows through three planes: a signal plane (Entra ID Protection&apos;s machine-learning risk scoring), a policy plane (Conditional Access&apos;s JSON rule evaluator), and a session plane (Continuous Access Evaluation&apos;s event-driven revocation channel). This article assembles the wire format of all three -- the `riskDetection` resource on Microsoft Graph, the `conditionalAccessPolicy` schema, the `cp1` client capability that opts a client into 28-hour tokens, and the `401 + insufficient_claims` claims challenge -- into one end-to-end picture, then names the five things this architecture fundamentally cannot do.
&lt;h2&gt;1. Who decided this token is good?&lt;/h2&gt;
&lt;p&gt;It is 09:02 on a Tuesday in Lisbon. Alice opens Outlook on a managed laptop in a hotel and the reading pane populates with mail in under a second. She did not type a password. She did not approve a push. She did not touch a hardware key.&lt;/p&gt;
&lt;p&gt;Who decided that was fine?&lt;/p&gt;
&lt;p&gt;The question is harder than it looks. Alice&apos;s password lives in a token cache from yesterday&apos;s sign-in at the office. Outlook&apos;s client silently acquires a fresh access token from Entra. That request may match a Conditional Access policy. The policy may consult an Identity Protection risk score. The result is either an access token or a refusal. Exchange Online receives the token, validates it, and may yet revoke it mid-session because something changed in the last sixty seconds. Bytes return to Alice.&lt;/p&gt;

Microsoft Entra ID&apos;s policy engine for evaluating sign-in attempts. A Conditional Access policy is a JSON object that matches a set of users, cloud apps, and conditions (network location, device state, sign-in risk, user risk, client app, platform) against a set of grants (block, require MFA, require compliant device, require Authentication Strength, and so on). Policies are evaluated after first-factor authentication; a block grant in any matching policy overrides all allow grants [@ms-ca-overview].

The machine-learning signal plane that scores sign-ins and users for risk. ID Protection emits `riskDetection` events tagged with `riskEventType` (anonymized IP, leaked credentials, password spray, atypical travel, and roughly two dozen others), `riskLevel` (low, medium, high), `riskState`, and `detectionTimingType` (realtime, nearRealtime, or offline). Available only on Microsoft Entra ID P2 [@ms-id-protection-overview].

The session plane. CAE is an event-driven channel between Microsoft Entra and CAE-aware resource APIs (Exchange Online, SharePoint Online, Teams, Microsoft Graph). When a critical event fires -- account disabled, password reset, high user risk, network location change -- the resource API returns `HTTP 401` with a `WWW-Authenticate: Bearer error=&quot;insufficient_claims&quot;` challenge. The client replays the embedded claims to Entra and acquires a fresh token. In exchange for this channel, CAE tokens live up to 28 hours [@ms-cae-concept].
&lt;p&gt;Every component in this chain is individually documented on Microsoft Learn. The Conditional Access policy schema is on the Graph reference [@ms-graph-capolicy]. The &lt;code&gt;riskDetection&lt;/code&gt; resource is on the Graph reference too [@ms-graph-riskdetection]. The &lt;code&gt;cp1&lt;/code&gt; client capability is in the claims-challenge document [@ms-claims-challenge]. The &quot;up to 15 minutes&quot; propagation ceiling for CAE non-IP events is in the CAE concept document [@ms-cae-concept].&lt;/p&gt;
&lt;p&gt;But the chain is not assembled anywhere. That is what this article does.&lt;/p&gt;
&lt;p&gt;This article is for the architect or the detection engineer who already knows what a JWT is, what a service principal is, and what an MDM does. If you have ever stared at a Sign-in log entry that reads &quot;Conditional Access: Success&quot; and wondered what &lt;em&gt;exactly&lt;/em&gt; the policy engine concluded, this is for you.&lt;/p&gt;
&lt;p&gt;Three moments of insight are coming. First, why MFA without context fails not because MFA is weak but because the &lt;em&gt;unit&lt;/em&gt; is wrong (Section 3). Second, why the architectural breakthrough was a &lt;em&gt;separation&lt;/em&gt; and not a new algorithm (Section 5). Third, why the system has limits that no engineering will fix (Section 8).&lt;/p&gt;
&lt;p&gt;How did the industry end up with a token-issuance and claims-challenge model? The answer begins in 1975, with a paper that did not mention identity once.&lt;/p&gt;
&lt;h2&gt;2. From perimeter to identity boundary&lt;/h2&gt;
&lt;p&gt;In September 1975, Jerome Saltzer and Michael Schroeder published an eight-principle paper on operating-system protection that nobody at MIT thought of as a paper about cloud identity [@saltzer-schroeder-1975]. Half a century later, two of those eight -- &lt;em&gt;complete mediation&lt;/em&gt; and &lt;em&gt;least privilege&lt;/em&gt; -- are the implicit theorems every Conditional Access policy evaluates against. Where did the industry go in between?&lt;/p&gt;
&lt;h3&gt;Saltzer and Schroeder: the unstated theorems&lt;/h3&gt;
&lt;p&gt;Complete mediation says &quot;every access to every object must be checked for authority.&quot; Least privilege says &quot;every program and every user of the system should operate using the least set of privileges necessary to complete the job.&quot; These are stated as design &lt;em&gt;principles&lt;/em&gt;, not theorems. But they function as theorems for anyone building an access-control system: violate either of them and you have, by construction, a vulnerability. Conditional Access does not derive the principles. It re-states them as a JSON schema and a runtime evaluator.&lt;/p&gt;
&lt;h3&gt;Jericho Forum: the perimeter dissolves&lt;/h3&gt;
&lt;p&gt;In 2003, David Lacey of the Royal Mail and a loose affiliation of corporate CISOs began arguing, against the prevailing castle-and-moat consensus, that the corporate network perimeter could no longer be relied on as the trust boundary. The Jericho Forum formally launched under the Open Group umbrella in January 2004 [@wikipedia-jericho-forum]. They coined the term &quot;de-perimeterisation&quot; to describe what their member firms were already living: data and identity travelling outside the firewall faster than the firewall could be moved.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s own retrospective puts the quote precisely: the Jericho Forum &quot;promoted a new concept of security called de-perimeterisation that focused on how to protect enterprise data flowing in and out of your enterprise network boundary instead of striving to convince users and the business to keep it on the corporate network&quot; [@simos-2020-jericho]. The first sentence of Microsoft Learn&apos;s CA overview today is a direct descendant: &quot;modern security extends beyond an organization&apos;s network perimeter&quot; [@ms-ca-overview].&lt;/p&gt;
&lt;h3&gt;Kindervag: the name&lt;/h3&gt;
&lt;p&gt;John Kindervag, then a principal analyst at Forrester Research, gave the model its marketable name in a September 2010 report titled &quot;No More Chewy Centers: Introducing the Zero Trust Model of Information Security&quot; [@kindervag-2010-zero-trust]. Three tenets: all resources are accessed securely regardless of location; access control is on strict need-to-know and strictly enforced; all traffic is inspected and logged.&lt;/p&gt;
&lt;p&gt;The label stuck. Microsoft Learn now calls CA &quot;Microsoft&apos;s Zero Trust policy engine&quot; in its first sentence [@ms-ca-overview]. The lineage from Kindervag&apos;s 14-page Forrester report to that sentence is direct.&lt;/p&gt;
&lt;p&gt;The original Kindervag PDF is gated behind Forrester&apos;s paywall. The widely cited copy on &lt;code&gt;ndm.net&lt;/code&gt; redirects to an unrelated managed-IT-services company; the only reliably accessible mirror is the Wayback Machine snapshot. Treat the lineage as well documented and the URL as a curiosity of how academic ideas survive the open web.&lt;/p&gt;
&lt;h3&gt;BeyondCorp: the alternative&lt;/h3&gt;
&lt;p&gt;In December 2014, Rory Ward and Betsy Beyer published &quot;BeyondCorp: A New Approach to Enterprise Security&quot; in USENIX &lt;code&gt;;login:&lt;/code&gt; [@ward-beyer-2014-beyondcorp]. The paper described Google&apos;s internal Zero Trust deployment: every request authenticated and authorized by an access proxy, no implicit network trust, device inventory and user identity as the inputs to access decisions. A follow-up in 2016 documented the production rollout [@osborn-2016-beyondcorp].&lt;/p&gt;
&lt;p&gt;This is the architectural fork Section 7 returns to. BeyondCorp puts the policy engine in the data path, as a reverse proxy that sees every HTTP request. CA puts the policy engine at &lt;em&gt;token issuance&lt;/em&gt; and re-evaluates via &lt;em&gt;claims challenges&lt;/em&gt;. Both work. They are not interchangeable.&lt;/p&gt;
&lt;h3&gt;NIST SP 800-207: the vocabulary&lt;/h3&gt;
&lt;p&gt;In August 2020, NIST published Special Publication 800-207, &lt;em&gt;Zero Trust Architecture&lt;/em&gt; [@nist-sp-800-207-2020]. It codified the U.S. federal reference architecture: a Policy Engine that decides, a Policy Administrator that effects the decision, and a Policy Enforcement Point that intercepts the access.&lt;/p&gt;
&lt;p&gt;That trio is the vocabulary the Microsoft Learn CA documentation now uses. In the SP 800-207 mapping, Conditional Access is the Policy Engine and Policy Administrator; Exchange Online, SharePoint Online, Teams, and Microsoft Graph are the Policy Enforcement Points; Entra ID Protection is the trust algorithm that feeds the Policy Engine.&lt;/p&gt;

If you ever have to map Conditional Access to SP 800-207 for a compliance review, the cleanest correspondences are: PE = the CA evaluator inside Entra; PA = Entra&apos;s token issuer (because the decision is effected by issuing or refusing a token); PEP = the resource API (Exchange, SharePoint, Graph) that validates the token, plus, for CAE-aware resources, the same API enforcing claims-challenge revocation mid-session. ID Protection is the &quot;trust algorithm&quot; input to the PE.
&lt;p&gt;The doctrine was settled by 2020. But Microsoft had already been trying to build a perimeter on identity for six years, starting in 2014 with a much smaller idea.&lt;/p&gt;
&lt;h2&gt;3. Per-user MFA and the limits of binary controls&lt;/h2&gt;
&lt;p&gt;In 2014, Microsoft&apos;s only cloud-era access control was a per-user toggle that said &lt;em&gt;MFA: yes&lt;/em&gt; or &lt;em&gt;MFA: no&lt;/em&gt;. The toggle worked. It was a real improvement over passwords alone. It also produced the most exploited security failure of the next decade: MFA fatigue [@weinert-2023-managed-policies].&lt;/p&gt;
&lt;p&gt;How does a control improve security &lt;em&gt;and&lt;/em&gt; create a new attack class at the same time?&lt;/p&gt;
&lt;h3&gt;The per-user MFA state machine&lt;/h3&gt;
&lt;p&gt;Per-user MFA lives on the user object as a tri-state: &lt;code&gt;Disabled&lt;/code&gt;, &lt;code&gt;Enabled&lt;/code&gt;, or &lt;code&gt;Enforced&lt;/code&gt;. Microsoft Learn now says the quiet part out loud: &quot;The best way to protect users with Microsoft Entra MFA is to create a Conditional Access policy&quot; and &quot;Don&apos;t enable or enforce per-user Microsoft Entra multifactor authentication if you use Conditional Access policies&quot; [@ms-howto-mfa-userstates]. That guidance carries a generation of operational pain inside it. Mixing the two surfaces, in practice, produces unpredictable prompts: a CA policy says &quot;no MFA required for this location,&quot; the per-user state says &quot;always MFA,&quot; and the user gets prompted twice.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft&apos;s explicit guidance is to pick one surface. If you have Entra ID P1 or higher, use Conditional Access. The per-user state should remain &lt;code&gt;Disabled&lt;/code&gt; for those accounts. Mixed configurations produce both false-positive prompts and, occasionally, false-negative skips [@ms-howto-mfa-userstates].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Trusted IP rules: one-dimensional context&lt;/h3&gt;
&lt;p&gt;Office 365 added a second knob in the same era: &quot;trusted IPs.&quot; Sign-ins from a configured public IP range would skip the MFA challenge [@ms-ca-network]. The idea was that &quot;on the corporate network&quot; meant &quot;more trustworthy.&quot; This was reasonable in 2014. By 2017, it was already eroded by full-tunnel VPNs (every employee egresses through the corporate /16 from home), split-tunnel VPNs (some traffic does, some does not), and the realisation that &quot;corporate network&quot; had stopped being a useful synonym for &quot;trusted.&quot; Trusted IP is one-dimensional context, and one dimension was not enough.&lt;/p&gt;
&lt;h3&gt;Security Defaults: the Free-SKU descendant&lt;/h3&gt;
&lt;p&gt;Since 22 October 2019, every new Entra ID tenant has Security Defaults turned on by default at creation [@ms-security-defaults]. Security Defaults is a tenant-wide on/off switch that requires MFA for all admin roles, MFA for users when they show risk, blocks legacy authentication, and forces MFA registration. Microsoft&apos;s number on the impact is striking: &quot;more than 99.9% of those common identity-related attacks are stopped by using multifactor authentication and blocking legacy authentication&quot; [@ms-security-defaults].&lt;/p&gt;
&lt;p&gt;For Entra ID Free tenants in 2026, Security Defaults is still the only available baseline. There is no per-app policy, no per-risk gating, no Conditional Access. This is the licensing reality Section 10 returns to.&lt;/p&gt;
&lt;p&gt;Active Directory Federation Services -- AD FS -- is the on-prem federation product that ran the access-control story before any of this. It is still operational in many tenants. It is no longer Microsoft&apos;s strategic identity provider; the Microsoft Learn AD FS overview now opens with the explicit guidance &quot;Instead of upgrading to the latest version of AD FS, Microsoft highly recommends migrating to Microsoft Entra ID&quot; [@ms-ad-fs-overview]. AD FS claim rules functioned as a kind of policy engine, but they evaluated only at federation time and they had no concept of risk.&lt;/p&gt;
&lt;h3&gt;The four failure modes of the binary toggle&lt;/h3&gt;
&lt;p&gt;The first-generation controls -- per-user MFA, trusted IPs, Security Defaults -- share four documented limits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;No expression of context.&lt;/strong&gt; The toggle is either on or off. It cannot say &quot;MFA from a new country but not from the office.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trusted IP is thin context.&lt;/strong&gt; A public IP range is one bit of information; modern attacks include matching network egress.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No per-app policy.&lt;/strong&gt; The toggle applies to all apps the user accesses. You cannot say &quot;MFA for the admin portal, not for Outlook.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No exclusion semantics for break-glass accounts.&lt;/strong&gt; Emergency-access accounts need to be reachable when everything else has failed. The binary toggle either includes them or excludes them; it does not let you say &quot;exclude these accounts but log every sign-in as a high-priority alert.&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;MFA fatigue: when a control becomes a credential&lt;/h3&gt;
&lt;p&gt;The canonical failure of the binary toggle is push-bombing. The attacker has the password. The system requires MFA. The user gets four &quot;approve sign-in?&quot; notifications during a morning meeting. One gets a thumbs-up by reflex. The system did exactly what it was configured to do.&lt;/p&gt;
&lt;p&gt;The attack works because the control has no concept of &lt;em&gt;whether this is a normal sign-in&lt;/em&gt;. The same flow runs whether the request originates from the user&apos;s office WiFi or an anonymizing proxy in another country. The MFA challenge carries no risk-weighted information; the user has no signal that this prompt is different from yesterday&apos;s prompt. Fatigue is the consequence. Microsoft&apos;s own Entra blog catalogued the attack pattern and the operational mitigations in the wake of the 2022 incident cluster [@ms-techcom-mfa-fatigue].&lt;/p&gt;

Focusing on password rules, rather than things that can really help -- like multi-factor authentication (MFA), or great threat detection -- is just a distraction. -- Alex Weinert, Microsoft Identity, July 2019 [@weinert-2019-password]
&lt;p&gt;Weinert&apos;s 2019 piece is now infamous in the identity community for its title alone -- &quot;Your Pa$$word doesn&apos;t matter.&quot; The argument was that a password&apos;s composition rules carry no information that helps the system tell a real user from an attacker; what does carry information is &lt;em&gt;context&lt;/em&gt;. The system needed a place to put that context.&lt;/p&gt;
&lt;p&gt;If &lt;em&gt;MFA yes/no&lt;/em&gt; cannot express context, the next step is obvious: make context the input. But to make context the input, the system needs a place to &lt;em&gt;put&lt;/em&gt; it. The history of CA from 2015 forward is the history of giving context a home.&lt;/p&gt;
&lt;h2&gt;4. Generation by generation&lt;/h2&gt;
&lt;p&gt;The next eight years produced six generations of access control, each one closing a specific failure of the previous one. They look like product launches in a marketing chronology. They are something more interesting: a sequence of negative results, each followed by a positive engineering response.&lt;/p&gt;

timeline
    title Conditional Access timeline
    2014 : Gen 1 per-user MFA and trusted IPs
    2015 : CA enters public preview
    2016 : Gen 2 Conditional Access general availability
    2016 : ID Protection enters preview
    2018 : Gen 3 risk-based CA conditions broadly available
    2020 : CAE enters preview
    2022 : Gen 4 Continuous Access Evaluation general availability
    2023 : Gen 5 CA for workload identities
    2023 : Gen 6 Microsoft-managed policies and Authentication Strengths
    2026 : CA for AI agent identities
&lt;p&gt;The 2026 milestone -- Conditional Access for AI agent identities -- is itself still emerging; Microsoft&apos;s current framing in the Conditional Access Optimization Agent announcement names it explicitly as a frontier rather than a finished generation [@ms-techcom-ca-optimization-agent]. Section 9.1 returns to the open problems.&lt;/p&gt;
&lt;h3&gt;Gen 1 (2014 to 2016): per-user MFA&lt;/h3&gt;
&lt;p&gt;Documented in Section 3. The control has no concept of context. The failure motivates Gen 2.&lt;/p&gt;
&lt;h3&gt;Gen 2 (September 2016 GA): Conditional Access with static rules&lt;/h3&gt;
&lt;p&gt;The September 27, 2016 CloudBlogs post announcing CA general availability framed it as &quot;Protect your data at the front door&quot; -- the &quot;front door&quot; framing that Microsoft documentation still uses [@ms-techcom-ca-frontdoor-2016]. The policy schema (users + cloud apps + conditions to grants) was introduced in the 2015 preview [@ms-techcom-ca-preview-2015] and survived essentially unchanged into 2016 GA.&lt;/p&gt;
&lt;p&gt;Gen 2 closed Gen 1&apos;s failure mode: context now had a home. A policy could match on network location, on the app being accessed, on the user&apos;s group membership, on the device platform. It could express &quot;block country X&quot; or &quot;require MFA when not on the corporate network.&quot;&lt;/p&gt;
&lt;p&gt;The remaining documented limit: no risk feed. The engine could express &lt;em&gt;what to check for&lt;/em&gt; but not &lt;em&gt;whether this specific sign-in looks suspicious&lt;/em&gt;. A policy could block credential-stuffing attempts only if you happened to know in advance which IPs to deny. Motivated Gen 3.&lt;/p&gt;
&lt;h3&gt;Gen 3 (2017 to 2018): risk-based fusion&lt;/h3&gt;
&lt;p&gt;Identity Protection had been generating risk signals since its March 2016 preview. Through 2017 and 2018, two new condition keys appeared in the CA policy schema: &lt;code&gt;signInRiskLevels&lt;/code&gt; and &lt;code&gt;userRiskLevels&lt;/code&gt;. Both take values from the set &lt;code&gt;low&lt;/code&gt;, &lt;code&gt;medium&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;. The risk feed plugged into the policy plane through exactly two keys. The legacy ID-Protection-side risk policies (which were a parallel policy surface inside ID Protection itself) are now retiring on 1 October 2026; the canonical surface is CA [@ms-id-protection-policies].&lt;/p&gt;
&lt;p&gt;The remaining limit: pre-issuance only. The CA evaluator runs at sign-in time. Once a token is issued, the policy plane has no way to undo the decision until the token expires. Microsoft&apos;s own retrospective is honest about what they tried first: &quot;Microsoft experimented with the &apos;blunt object&apos; approach of reduced token lifetimes but found they degrade user experiences and reliability without eliminating risks&quot; [@ms-cae-concept]. A one-hour token cuts the worst-case revocation latency to an hour, but it also means a user with intermittent connectivity gets prompted every hour, and a mobile app with retry storms can hammer the IdP. The trade-off was unacceptable. Motivated Gen 4.&lt;/p&gt;
&lt;h3&gt;Gen 4 (January 2022 GA): Continuous Access Evaluation&lt;/h3&gt;
&lt;p&gt;CAE inverted the trade-off. Instead of shortening the token, lengthen it -- up to 28 hours [@ms-cae-concept]. Then add a side channel: when a critical event fires (account disabled, password reset, high user risk, IP location change), the resource API issues an &lt;code&gt;HTTP 401&lt;/code&gt; with a &lt;code&gt;WWW-Authenticate&lt;/code&gt; claims challenge, and the client replays to Entra for a fresh token. Latency on the side channel is bounded: &quot;up to 15 minutes&quot; for non-IP events, &quot;instant&quot; for IP locations [@ms-cae-concept]. CAE was tied to an emerging open standard from day one, the OpenID Continuous Access Evaluation Profile [@ms-cae-concept]. The general-availability announcement landed on 10 January 2022 [@ms-techcom-cae-ga-2022].&lt;/p&gt;
&lt;p&gt;Remaining limit: applies to humans only. Service principals do not consume CAE-aware client libraries; they cannot perform a claims challenge. Motivated Gen 5.&lt;/p&gt;
&lt;h3&gt;Gen 5 (2023 GA): Conditional Access for workload identities&lt;/h3&gt;
&lt;p&gt;Same engine, constrained grant set. The Microsoft Learn page is blunt on the boundaries: &quot;Workload Identities Premium licenses are required&quot; and the constraint set is unusual -- &quot;Policy can be applied to single tenant service principals that are registered in your tenant. Microsoft and third-party SaaS applications, including multitenant apps, are not covered by these policies. Managed identities aren&apos;t covered by policy&quot; and &quot;Under Grant, Block access is the only available option&quot; [@ms-workload-identity-ca]. The public preview of CA filters for workload identities opened on 26 October 2022 [@vansurksum-2022-workload-ca]; the Microsoft Entra Workload Identities standalone product followed in late November 2022, and the Conditional Access feature for workload identities itself reached general availability later in 2023.&lt;/p&gt;
&lt;p&gt;The single-tenant restriction is a structural choice. Multi-tenant SaaS apps appear in many tenants&apos; service principal directories at once; policy scoping on them would require a cross-tenant resolution protocol the engine does not have. Managed identities are excluded because they belong to Azure subscriptions, not to user identity, and Microsoft has chosen not to extend the surface there. Group assignments do not work either: &quot;Conditional Access policies assigned to a group that contains a service principal are not enforced for that service principal&quot; [@ms-workload-identity-ca].&lt;/p&gt;
&lt;p&gt;Remaining limit: under-configured in most tenants because the grant taxonomy is so narrow that admins do not see immediate value. Motivated Gen 6.&lt;/p&gt;
&lt;h3&gt;Gen 6 (November 2023 onwards): Microsoft-managed policies and Authentication Strengths&lt;/h3&gt;
&lt;p&gt;In November 2023, Alex Weinert announced Microsoft-managed Conditional Access policies: a set of baselines that Microsoft would auto-deploy into tenants in Report-only mode and then auto-enable after a waiting period [@weinert-2023-managed-policies]. The launch announcement specified a 90-day window [@helpnet-2023-microsoft-entra-policies]. The current Microsoft Learn documentation specifies &quot;Microsoft enables these policies no less than 45 days after they&apos;re introduced in your tenant if they&apos;re left in the Report-only state&quot; with a 28-day pre-enablement notification [@ms-managed-policies].&lt;/p&gt;
&lt;p&gt;The window shrank deliberately. The 90-day window in the 2023 launch announcement was a calibration window; the 45-day window in current documentation is the post-calibration setting. Both numbers are correct in their respective time frames. The article uses the current number throughout.&lt;/p&gt;
&lt;p&gt;Parallel to the managed policies, Microsoft shipped &lt;em&gt;Authentication Strengths&lt;/em&gt; -- a named bundle of acceptable authentication methods that can be required as a grant. The three built-in strengths are &lt;em&gt;MFA strength&lt;/em&gt;, &lt;em&gt;Passwordless MFA strength&lt;/em&gt;, and &lt;em&gt;Phishing-resistant MFA strength&lt;/em&gt; (FIDO2 security key, &lt;a href=&quot;https://paragmali.com/blog/your-face-is-not-your-password-inside-windows-hellos-hardwar/&quot; rel=&quot;noopener&quot;&gt;Windows Hello for Business&lt;/a&gt;, multifactor certificate-based authentication) [@ms-auth-strengths]. The phishing-resistant strength is the modern way to express &quot;no adversary-in-the-middle phishing kit should be able to defeat this grant.&quot;&lt;/p&gt;
&lt;h3&gt;The pattern: extension, not replacement&lt;/h3&gt;
&lt;p&gt;From Gen 3 onward, each generation &lt;em&gt;extends&lt;/em&gt; the prior schema rather than replacing it. The &lt;code&gt;conditionalAccessPolicy&lt;/code&gt; JSON shape that shipped in 2016 still drives the engine in 2026 -- with new condition keys added, new grant types added, new session controls added. By the standards of cloud control surfaces, that is a long run without a rewrite.&lt;/p&gt;
&lt;p&gt;The reason is the architectural decision the next section is about.&lt;/p&gt;
&lt;h2&gt;5. The two-plane separation&lt;/h2&gt;
&lt;p&gt;The breakthrough is not a model, not a token format, not a wire protocol. It is a &lt;em&gt;separation&lt;/em&gt;: the &lt;strong&gt;signal plane&lt;/strong&gt; that produces risk detections from the &lt;strong&gt;policy plane&lt;/strong&gt; that consumes them.&lt;/p&gt;
&lt;p&gt;Stated like that, it sounds banal. Read it the other direction -- a policy engine whose risk model can change without changing the policy semantics, and whose policy can change without retraining the model -- and it is the design that makes the system maintainable at trillions of daily signals across hundreds of thousands of tenants.&lt;/p&gt;
&lt;h3&gt;The two planes, precisely&lt;/h3&gt;
&lt;p&gt;The signal plane is Microsoft Entra ID Protection. It runs detection logic on every interactive sign-in (and, for offline detections, on historical sign-ins) and emits a &lt;code&gt;riskDetection&lt;/code&gt; resource into a per-tenant log on Microsoft Graph at &lt;code&gt;/identityProtection/riskDetections&lt;/code&gt;. Each detection carries five fields you care about: &lt;code&gt;riskEventType&lt;/code&gt; (one of about two dozen named detection types like &lt;code&gt;anonymizedIPAddress&lt;/code&gt;, &lt;code&gt;leakedCredentials&lt;/code&gt;, &lt;code&gt;unlikelyTravel&lt;/code&gt;), &lt;code&gt;riskLevel&lt;/code&gt; (&lt;code&gt;low&lt;/code&gt;, &lt;code&gt;medium&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;, plus the bookkeeping values &lt;code&gt;hidden&lt;/code&gt; and &lt;code&gt;none&lt;/code&gt;), &lt;code&gt;riskState&lt;/code&gt; (&lt;code&gt;atRisk&lt;/code&gt;, &lt;code&gt;confirmedCompromised&lt;/code&gt;, &lt;code&gt;dismissed&lt;/code&gt;, &lt;code&gt;remediated&lt;/code&gt;), &lt;code&gt;detectionTimingType&lt;/code&gt; (&lt;code&gt;realtime&lt;/code&gt;, &lt;code&gt;nearRealtime&lt;/code&gt;, &lt;code&gt;offline&lt;/code&gt;), and &lt;code&gt;additionalInfo&lt;/code&gt; (a JSON blob with user-agent, IP, alert URL, reason codes) [@ms-graph-riskdetection][@ms-id-protection-risks].&lt;/p&gt;
&lt;p&gt;The policy plane is Conditional Access. It is a JSON object at &lt;code&gt;/identity/conditionalAccess/policies/{id}&lt;/code&gt; on the Graph API [@ms-graph-capolicy]. Each policy has &lt;code&gt;displayName&lt;/code&gt;, &lt;code&gt;state&lt;/code&gt; (&lt;code&gt;enabled&lt;/code&gt;, &lt;code&gt;disabled&lt;/code&gt;, &lt;code&gt;enabledForReportingButNotEnforced&lt;/code&gt;), &lt;code&gt;conditions&lt;/code&gt;, &lt;code&gt;grantControls&lt;/code&gt;, and &lt;code&gt;sessionControls&lt;/code&gt;. The conditions block contains the per-policy targeting: which users, which apps, which platforms, which network locations -- and two condition keys named &lt;code&gt;signInRiskLevels&lt;/code&gt; and &lt;code&gt;userRiskLevels&lt;/code&gt;.&lt;/p&gt;

**Sign-in risk** is a per-sign-in probability that the credential being used is being used by someone other than the legitimate owner *at this moment*. **User risk** is a per-user probability that the account itself has been compromised over its recent history. A user with leaked credentials in a breach corpus carries persistent user risk until the password is reset; a user signing in from an anonymizing proxy carries sign-in risk for that session. CA policies can match on either, both, or neither. Risk-based conditions require Entra ID P2 [@ms-id-protection-policies].
&lt;p&gt;Those two condition keys -- &lt;code&gt;signInRiskLevels&lt;/code&gt; and &lt;code&gt;userRiskLevels&lt;/code&gt; -- are the entire API surface between the signal plane and the policy plane. Everything else about ID Protection is hidden behind them. The policy plane does not know whether &lt;code&gt;high&lt;/code&gt; came from a transformer or a logistic regression or a hardcoded rule. The signal plane does not know which policies will read its output. The contract is two strings.&lt;/p&gt;

flowchart LR
    subgraph SP[Signal plane Entra ID Protection]
        DET[Detection pipeline]
        RD[(riskDetection log)]
        RL[Risk level low medium high]
    end
    subgraph PP[Policy plane Conditional Access]
        EV[Policy evaluator]
        POL[(conditionalAccessPolicy JSON)]
        TOK[Token issuer]
    end
    subgraph SES[Session plane CAE]
        CH[Critical event channel]
        RP[Resource API]
    end
    DET --&amp;gt; RD
    DET --&amp;gt; RL
    RL -. signInRiskLevels userRiskLevels .-&amp;gt; EV
    POL --&amp;gt; EV
    EV --&amp;gt; TOK
    TOK -- access token --&amp;gt; RP
    DET -. user risk events .-&amp;gt; CH
    CH -. 401 insufficient claims .-&amp;gt; RP
&lt;h3&gt;Why the separation matters&lt;/h3&gt;
&lt;p&gt;Three concrete consequences fall out of the design:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The risk model is re-trainable without policy rewrites.&lt;/strong&gt; Microsoft&apos;s ID Protection team can change the underlying detection algorithm tomorrow. Add a new &lt;code&gt;riskEventType&lt;/code&gt;. Replace the classifier for &lt;code&gt;unlikelyTravel&lt;/code&gt;. Re-tune the threshold that maps a score to &lt;code&gt;low&lt;/code&gt;/&lt;code&gt;medium&lt;/code&gt;/&lt;code&gt;high&lt;/code&gt;. None of these require tenants to rewrite their CA policies, because policies match on the &lt;em&gt;level&lt;/em&gt;, not the &lt;em&gt;signal&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tenants without the licence simply do not use the risk conditions.&lt;/strong&gt; An Entra ID P1 tenant can deploy CA policies that match on users, apps, locations, devices, client apps, and platforms. P2 unlocks the risk conditions. The schema accommodates both: P1 policies just leave the risk arrays empty. There is no parallel policy surface for the non-risk-aware tenants; they use the same engine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CAE is a third plane layered onto the same skeleton.&lt;/strong&gt; Continuous Access Evaluation did not require redesign of the policy plane. The CAE channel is a new &lt;em&gt;event delivery&lt;/em&gt; mechanism; the events it propagates are things the signal plane already knew about (high user risk, password reset, account disabled) plus new ones the policy plane introduced (network-location-policy changed). The architecture absorbed CAE because the design was already a separation of concerns.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The signal plane and the policy plane are separable; the contract between them is &lt;em&gt;two condition keys&lt;/em&gt; (&lt;code&gt;signInRiskLevels&lt;/code&gt; and &lt;code&gt;userRiskLevels&lt;/code&gt;). That is what makes the system maintainable across a decade of evolution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;The &quot;pit of success&quot; framing&lt;/h3&gt;
&lt;p&gt;Alex Weinert calls this the &quot;pit of success.&quot; His November 2023 piece on Microsoft-managed policies put the metric on it: a decade ago Microsoft turned on a &quot;radical&quot; tenant-wide policy requiring MFA for every consumer Microsoft account, and &quot;today, 100 percent of consumer Microsoft accounts older than 60 days have multifactor authentication&quot; [@weinert-2023-managed-policies].&lt;/p&gt;
&lt;p&gt;The 100 percent number is achievable because the policy plane and the signal plane can each evolve independently. Microsoft can ship a managed policy that says &quot;require MFA for high-risk sign-ins&quot; without committing to a fixed definition of &quot;high risk.&quot; The definition lives on the signal plane and changes weekly. The policy lives on the policy plane and is stable for years.&lt;/p&gt;
&lt;p&gt;With the separation as the spine, the next section walks the end-to-end pipeline in one continuous trace, from signal to grant to token to session, on a real sign-in -- the trace no public Microsoft document assembles in one place.&lt;/p&gt;
&lt;h2&gt;6. The end-to-end pipeline&lt;/h2&gt;
&lt;p&gt;Take Alice&apos;s Tuesday morning from Section 1 and walk it forward. This section has six subsections. By the end of them, the question &quot;who decided?&quot; has six independently sourced answers and one combined picture.&lt;/p&gt;
&lt;h3&gt;6.1 What the signal plane sees&lt;/h3&gt;
&lt;p&gt;Identity Protection&apos;s detection taxonomy splits into five rough groups, based on what kind of information triggered the detection. The canonical taxonomy is the Microsoft Learn page on risk types [@ms-id-protection-risks]; the wire-format enum on the Graph schema is at [@ms-graph-riskdetection].&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Network signals.&lt;/em&gt; &lt;code&gt;anonymizedIPAddress&lt;/code&gt;, &lt;code&gt;maliciousIPAddress&lt;/code&gt;, &lt;code&gt;nationStateIP&lt;/code&gt;, &lt;code&gt;riskyIPAddress&lt;/code&gt;. The signal is the source IP and reputation databases that ID Protection ingests.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Behavioural signals.&lt;/em&gt; &lt;code&gt;unlikelyTravel&lt;/code&gt;, &lt;code&gt;mcasImpossibleTravel&lt;/code&gt;, &lt;code&gt;newCountry&lt;/code&gt;, &lt;code&gt;unfamiliarFeatures&lt;/code&gt;, &lt;code&gt;anomalousUserActivity&lt;/code&gt;. The signal is a deviation from the tenant&apos;s or the user&apos;s historical baseline.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Credential signals.&lt;/em&gt; &lt;code&gt;leakedCredentials&lt;/code&gt;, &lt;code&gt;passwordSpray&lt;/code&gt;. The signal is a match against a corpus of breached credentials or a velocity-based pattern across tenants.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Token and session signals.&lt;/em&gt; &lt;code&gt;anomalousToken&lt;/code&gt;, &lt;code&gt;tokenIssuerAnomaly&lt;/code&gt;, &lt;code&gt;attemptedPrtAccess&lt;/code&gt;, &lt;code&gt;attackerinTheMiddle&lt;/code&gt;, &lt;code&gt;authenticatorPhishing&lt;/code&gt;. The signal is on the token itself or on the way the authenticator flow ran.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Inbox behaviour.&lt;/em&gt; &lt;code&gt;suspiciousInboxForwarding&lt;/code&gt;, &lt;code&gt;mcasSuspiciousInboxManipulationRules&lt;/code&gt;. The signal is on what happened &lt;em&gt;after&lt;/em&gt; the sign-in -- a post-compromise indicator that retroactively flags the sign-in that enabled it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each detection is also tagged with a timing: real-time, near-real-time, or offline. Microsoft Learn is precise about the latencies: &quot;Detections triggered in real-time take 5-10 minutes to surface details in the reports. Offline detections take up to 48 hours&quot; [@ms-risk-detection-types].&lt;/p&gt;
&lt;p&gt;The detection is mapped to a risk &lt;em&gt;level&lt;/em&gt;, not a probability. Microsoft Learn calls the level &quot;calculated by our machine learning algorithms&quot; and explicitly notes the meaning: low/medium/high &quot;represent how confident Microsoft is that one or more of the user&apos;s credentials are known by an unauthorized entity&quot; [@ms-risk-detection-types].&quot;Confidence&quot; here is meant in the everyday sense, not the strict statistical sense of a confidence interval. Microsoft has not published a calibration study that would let you map a &quot;high&quot; risk level to a frequentist probability of compromise.&lt;/p&gt;
&lt;p&gt;The figure you sometimes see in Microsoft marketing materials -- &quot;more than 100 trillion signals processed per day&quot; [@ms-managed-policies], or, in older sources, &quot;78 trillion&quot; [@ms-id-protection-overview] -- is the &lt;em&gt;aggregate signal volume across all tenants and product surfaces&lt;/em&gt;, not per-sign-in features per user. The article keeps the two carefully separate.&lt;/p&gt;
&lt;p&gt;Microsoft has not publicly disclosed the production model architecture, the feature vector size, or per-detection precision and recall. The 2021 Microsoft Security Blog interview with Maria Puertas Calvo describes the existence of the ML team and the operational scale (&quot;hundreds of terabytes every day&quot;) but stops well short of architecture details [@ms-puertas-calvo-interview]. The model class is publicly unspecified; the taxonomy and the operating output are both public.&lt;/p&gt;
&lt;h3&gt;6.2 How risk surfaces&lt;/h3&gt;
&lt;p&gt;Two parallel logs matter for risk. The Sign-in log is the universe: every interactive and non-interactive sign-in produces an entry. The &lt;code&gt;riskDetections&lt;/code&gt; log is the &lt;em&gt;sparse overlay&lt;/em&gt;: a &lt;code&gt;riskDetection&lt;/code&gt; is emitted only when a detection fires for the sign-in. Most sign-ins produce a Sign-in log entry with no corresponding &lt;code&gt;riskDetection&lt;/code&gt;. Only flagged sign-ins do [@ms-graph-riskdetection].&lt;/p&gt;
&lt;p&gt;This is a common source of confusion. It is tempting to assume &quot;ID Protection scored every sign-in,&quot; and in a sense it did -- the detectors ran -- but the &lt;em&gt;durable artefact&lt;/em&gt; exists only when at least one detector fired. To compute a per-sign-in distribution of risk you need to &lt;em&gt;join&lt;/em&gt; the Sign-in log with the riskDetections log and treat the unjoined rows as &quot;no risk flagged at the moment of issuance.&quot;&lt;/p&gt;
&lt;p&gt;There is one more wrinkle. The detection taxonomy on the Microsoft Learn concept page and the &lt;code&gt;riskEventType&lt;/code&gt; enum on the Graph schema are not perfectly aligned. The concept page lists &lt;code&gt;mcasImpossibleTravel&lt;/code&gt; and &lt;code&gt;authenticatorPhishing&lt;/code&gt; as named detection types; the Graph enum lists &lt;code&gt;impossibleTravel&lt;/code&gt; (without the &lt;code&gt;mcas&lt;/code&gt; prefix). The two surfaces sometimes use different value names for the same logical detection -- a UI display string versus a Graph enum value. Detection engineers writing KQL against the Sign-in logs should account for both.&lt;/p&gt;
&lt;h3&gt;6.3 How CA consumes risk&lt;/h3&gt;
&lt;p&gt;Conditional Access evaluation runs in a fixed order: assignments are checked first (does this sign-in match this policy at all?), then conditions (do all the condition predicates hold?), then grants (which controls are demanded?), then session controls (which token lifetime, sign-in frequency, persistent browser).&lt;/p&gt;
&lt;p&gt;The key semantic, repeated across the Microsoft Learn documentation: a &lt;em&gt;block&lt;/em&gt; grant in any policy matching the sign-in overrides any allow grant in any other policy. The policy plane is not just additive; it has an explicit precedence rule.&lt;/p&gt;

flowchart TD
    A[Sign-in request] --&amp;gt; B[First-factor auth]
    B --&amp;gt; C[Enumerate matching policies]
    C --&amp;gt; D{Any policy matches?}
    D -- No --&amp;gt; E[Default allow with token]
    D -- Yes --&amp;gt; F[Evaluate conditions per policy]
    F --&amp;gt; G{Block grant in any match?}
    G -- Yes --&amp;gt; H[Deny access return error]
    G -- No --&amp;gt; I[Aggregate required grants]
    I --&amp;gt; J{All grants satisfied?}
    J -- No --&amp;gt; K[Issue challenge MFA or device]
    J -- Yes --&amp;gt; L[Apply session controls]
    L --&amp;gt; M[Issue access token]
&lt;p&gt;The pseudocode below is a compressed restatement of that flow. It is not Microsoft source code; it is the algorithmic shape an admin should keep in their head when reading a policy or debugging a sign-in.&lt;/p&gt;
&lt;p&gt;{`
function evaluate(signin) {
  const matching = allPolicies.filter(p =&amp;gt;
    p.state !== &apos;disabled&apos; &amp;amp;&amp;amp;
    matchesAssignments(p.conditions, signin) &amp;amp;&amp;amp;
    matchesConditions(p.conditions, signin)
  );&lt;/p&gt;
&lt;p&gt;  // Block precedence: any block grant wins
  if (matching.some(p =&amp;gt; p.grantControls.builtInControls.includes(&apos;block&apos;))) {
    return { decision: &apos;DENY&apos;, reason: &apos;block grant matched&apos; };
  }&lt;/p&gt;
&lt;p&gt;  // Aggregate required grants across matching policies
  const requiredGrants = new Set();
  for (const p of matching) {
    for (const g of p.grantControls.builtInControls) requiredGrants.add(g);
    if (p.grantControls.authenticationStrength) {
      requiredGrants.add(&apos;authStrength:&apos; + p.grantControls.authenticationStrength.id);
    }
  }&lt;/p&gt;
&lt;p&gt;  const satisfied = [...requiredGrants].every(g =&amp;gt; signin.satisfies(g));
  if (!satisfied) {
    return { decision: &apos;CHALLENGE&apos;, missing: [...requiredGrants].filter(g =&amp;gt; !signin.satisfies(g)) };
  }&lt;/p&gt;
&lt;p&gt;  // Apply session controls (token lifetime, sign-in frequency, persistent browser)
  const session = mergeSessionControls(matching.map(p =&amp;gt; p.sessionControls));
  return { decision: &apos;ALLOW&apos;, session };
}&lt;/p&gt;
&lt;p&gt;const result = evaluate({
  user: &apos;&lt;a href=&quot;mailto:alice@contoso.com&quot; rel=&quot;noopener&quot;&gt;alice@contoso.com&lt;/a&gt;&apos;,
  app: &apos;Office365 Exchange Online&apos;,
  location: { ip: &apos;203.0.113.42&apos;, country: &apos;PT&apos; },
  device: { compliant: true, joinType: &apos;Entra&apos; },
  signInRisk: &apos;low&apos;,
  userRisk: &apos;none&apos;,
  satisfies(grant) {
    const mfa = [&apos;mfa&apos;, &apos;authStrength:phishingResistantMfa&apos;];
    return mfa.includes(grant) || grant === &apos;compliantDevice&apos;;
  },
});
console.log(JSON.stringify(result, null, 2));
`}&lt;/p&gt;
&lt;p&gt;Risk-based conditions require Entra ID P2 [@ms-id-protection-overview]. Without that licence, the &lt;code&gt;signInRiskLevels&lt;/code&gt; and &lt;code&gt;userRiskLevels&lt;/code&gt; arrays in a policy are ignored. The rest of the engine works the same.&lt;/p&gt;
&lt;h3&gt;6.4 The grants&lt;/h3&gt;
&lt;p&gt;Each policy declares a set of grants. The grants are &lt;em&gt;additive within a policy&lt;/em&gt; (all required to satisfy the policy) but the &lt;em&gt;block grant in any matching policy&lt;/em&gt; takes precedence over allow grants in any other policy. Here are the grants currently in the schema:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Grant&lt;/th&gt;
&lt;th&gt;What it requires&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deny access.&lt;/td&gt;
&lt;td&gt;Always wins against allow grants.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mfa&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any MFA method registered for the user.&lt;/td&gt;
&lt;td&gt;The legacy generic-MFA grant; replaced in modern deployments by Authentication Strength.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;requireAuthenticationStrength&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A named bundle of acceptable methods.&lt;/td&gt;
&lt;td&gt;The modern grant. Built-in strengths include phishing-resistant [@ms-auth-strengths].&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;compliantDevice&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The device record has &lt;code&gt;isCompliant: true&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;Set by Intune or a third-party compliance partner.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;domainJoinedDevice&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hybrid Azure AD joined device.&lt;/td&gt;
&lt;td&gt;Requires Entra Connect on-prem trust.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;approvedApplication&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use an approved client app.&lt;/td&gt;
&lt;td&gt;A small allow-list of Microsoft mobile apps.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;compliantApplication&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An app under an Intune App Protection Policy.&lt;/td&gt;
&lt;td&gt;Mobile app management.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;passwordChange&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;User must change their password.&lt;/td&gt;
&lt;td&gt;Used for password-leaked recovery.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;requireTermsOfUse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;User must accept a terms-of-use document.&lt;/td&gt;
&lt;td&gt;Used for compliance and guest scenarios.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

A named, ordered bundle of acceptable authentication methods that a CA grant can demand. The three built-in strengths are *MFA strength* (any registered second factor), *Passwordless MFA strength* (no password used), and *Phishing-resistant MFA strength* (FIDO2 security key, Windows Hello for Business or a platform credential, or multifactor certificate-based authentication) [@ms-auth-strengths]. The phishing-resistant strength is the canonical modern grant for high-value access.
&lt;p&gt;The Authentication Strength grant is where the phishing-resistance story lives in 2026. A policy that demands the phishing-resistant strength refuses to accept TOTP or SMS or push as the second factor. Only credentials with cryptographic binding to the device or hardware token will satisfy the grant. That class of credential, by construction, cannot be replayed by an adversary-in-the-middle phishing kit -- because the underlying &lt;a href=&quot;https://paragmali.com/blog/webauthn-and-passkeys-on-windows-from-ctap-to-the-credential/&quot; rel=&quot;noopener&quot;&gt;WebAuthn&lt;/a&gt; ceremony is bound to the origin of the relying party.&lt;/p&gt;
&lt;h3&gt;6.5 The Windows-side handoff&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://paragmali.com/blog/inside-the-primary-refresh-token-the-cryptographic-seam-betw/&quot; rel=&quot;noopener&quot;&gt;PRT&lt;/a&gt; issuance is an interactive sign-in. It goes through CA like any other.&lt;/p&gt;

A long-lived refresh token issued to a Windows session at user sign-in to Entra-joined or hybrid-Entra-joined devices. The PRT is bound to the device&apos;s TPM where one is available, and it grants the user single sign-on to all CA-targeted apps from that Windows session. Issuance is subject to CA evaluation; if a CA policy demands compliant device, the device must already be marked `isCompliant` before the PRT is issued.
&lt;p&gt;The compliance state lands on the device object as &lt;code&gt;isCompliant&lt;/code&gt;. Intune (or a third-party MDM through Intune&apos;s compliance-partner API) writes that field after evaluating the device against a compliance policy: disk encrypted, OS patched, antivirus running, jailbreak detection clean, and so on. CA reads it on subsequent policy evaluations. If a policy requires &lt;code&gt;compliantDevice&lt;/code&gt; and the device object says &lt;code&gt;isCompliant: false&lt;/code&gt;, the grant is not satisfied.&lt;/p&gt;
&lt;p&gt;The operational seam to on-prem Active Directory runs the other direction. &lt;a href=&quot;https://paragmali.com/blog/kerberos-in-windows-the-other-half-of-ntlmless/&quot; rel=&quot;noopener&quot;&gt;Kerberos&lt;/a&gt; and &lt;a href=&quot;https://paragmali.com/blog/ntlmless-the-death-of-ntlm-in-windows/&quot; rel=&quot;noopener&quot;&gt;NTLM&lt;/a&gt; against on-prem domain controllers never consult Entra. The Microsoft Learn CA overview is explicit: CA is a &lt;em&gt;cloud control plane&lt;/em&gt;; on-prem authentication is outside its scope [@ms-ca-overview]. This is the limit Section 8 will name precisely.&lt;/p&gt;
&lt;h3&gt;6.6 CAE in session&lt;/h3&gt;
&lt;p&gt;The third plane. Wire format lives in two Microsoft Learn pages: the claims-challenge page [@ms-claims-challenge] and the app-resilience CAE page [@ms-app-resilience-cae].&lt;/p&gt;
&lt;p&gt;A client opts in to CAE by advertising the &lt;code&gt;cp1&lt;/code&gt; capability via the &lt;code&gt;xms_cc&lt;/code&gt; claim in token requests. In MSAL, that opt-in looks like &lt;code&gt;WithClientCapabilities(new[] { &quot;cp1&quot; })&lt;/code&gt; [@ms-app-resilience-cae]. The Microsoft Learn claims-challenge page says it cleanly: &quot;The only currently known value is &lt;code&gt;cp1&lt;/code&gt;&quot; [@ms-claims-challenge].&lt;/p&gt;
&lt;p&gt;When the policy plane sees a critical event after the token was issued, the resource API responds to the next call with &lt;code&gt;HTTP 401 Unauthorized&lt;/code&gt; and a &lt;code&gt;WWW-Authenticate&lt;/code&gt; header of the shape:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer authorization_uri=&quot;&amp;lt;entra-authorize-endpoint&amp;gt;&quot;, error=&quot;insufficient_claims&quot;, claims=&quot;&amp;lt;base64-encoded JSON&amp;gt;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;claims&lt;/code&gt; value is a base64-encoded JSON object that the client passes verbatim to the token endpoint when acquiring a fresh token [@ms-claims-challenge][@ms-app-resilience-cae]. The IdP evaluates the embedded claims, runs CA again with the new context, and issues a new token (or refuses).&lt;/p&gt;

The HTTP wire format CAE uses to revoke a session mid-flight. A CAE-aware resource API returns `HTTP 401` with `WWW-Authenticate: Bearer error=&quot;insufficient_claims&quot;, claims=&quot;&quot;`. The client replays the base64 blob to Entra; Entra re-runs CA with the new context; the client receives a fresh token or a definitive refusal. The wire format is documented at [@ms-claims-challenge] and demonstrated at [@ms-app-resilience-cae].
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The CAE-aware capability is signalled by the &lt;em&gt;client&lt;/em&gt;, not by the &lt;em&gt;token&lt;/em&gt;. The client advertises &lt;code&gt;cp1&lt;/code&gt; via &lt;code&gt;xms_cc&lt;/code&gt;; the token&apos;s CAE-awareness shows up as its lifetime (up to 28 hours) and the resource API&apos;s willingness to issue a claims challenge. Folk knowledge that says &quot;look for a &lt;code&gt;cae&lt;/code&gt; claim in the JWT&quot; is incorrect.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Microsoft Learn CAE document enumerates five critical events: account disabled or deleted, password change or reset, MFA enabled by an administrator, administrator token revocation, and high user risk detected by ID Protection [@ms-cae-concept]. A parallel pathway, &lt;em&gt;Conditional Access policy evaluation&lt;/em&gt;, propagates network-location and policy changes to CAE-aware resource providers on the same channel. For IP-location changes the latency is &quot;instant&quot;; for everything else the ceiling is up to 15 minutes [@ms-cae-concept].&lt;/p&gt;

sequenceDiagram
    participant C as Client app
    participant R as Resource API CAE aware
    participant E as Entra token issuer
    participant P as ID Protection
    Note over C: Client holds long-lived CAE token
    C-&amp;gt;&amp;gt;R: GET messages with bearer token
    R-&amp;gt;&amp;gt;R: Token still cryptographically valid
    P-&amp;gt;&amp;gt;E: High user risk event for Alice
    E-&amp;gt;&amp;gt;R: Push critical event Alice high risk
    C-&amp;gt;&amp;gt;R: GET messages with bearer token again
    R-&amp;gt;&amp;gt;C: 401 WWW-Authenticate insufficient_claims claims base64
    C-&amp;gt;&amp;gt;E: Token request with claims blob and cp1 capability
    E-&amp;gt;&amp;gt;E: Re-run CA with new context
    E--&amp;gt;&amp;gt;C: New token or definitive refusal
    C-&amp;gt;&amp;gt;R: Retry with new token
&lt;p&gt;{`
// Simplified MSAL.js-shaped pseudocode for CAE opt-in and challenge handling
const ENTRA_AUTHORITY = &apos;&apos;;
const EXCHANGE_ENDPOINT = &apos;&apos;;
const MAIL_READ_SCOPE = &apos;&apos;;&lt;/p&gt;
&lt;p&gt;const msal = new PublicClientApplication({
  auth: { clientId: &apos;&apos;, authority: ENTRA_AUTHORITY },
});&lt;/p&gt;
&lt;p&gt;async function callExchange() {
  let token = await msal.acquireTokenSilent({
    scopes: [MAIL_READ_SCOPE],
    clientCapabilities: [&apos;cp1&apos;], // advertise CAE awareness
  });&lt;/p&gt;
&lt;p&gt;  let res = await fetch(EXCHANGE_ENDPOINT, {
    headers: { Authorization: &apos;Bearer &apos; + token.accessToken },
  });&lt;/p&gt;
&lt;p&gt;  if (res.status === 401) {
    const header = res.headers.get(&apos;WWW-Authenticate&apos;) || &apos;&apos;;
    const m = /claims=&quot;([^&quot;]+)&quot;/.exec(header);
    if (m) {
      // Replay the embedded claims to acquire a fresh token
      token = await msal.acquireTokenSilent({
        scopes: [MAIL_READ_SCOPE],
        claims: Buffer.from(m[1], &apos;base64&apos;).toString(&apos;utf8&apos;),
        clientCapabilities: [&apos;cp1&apos;],
      });
      res = await fetch(EXCHANGE_ENDPOINT, {
        headers: { Authorization: &apos;Bearer &apos; + token.accessToken },
      });
    }
  }&lt;/p&gt;
&lt;p&gt;  console.log(&apos;HTTP&apos;, res.status);
}&lt;/p&gt;
&lt;p&gt;callExchange();
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; CAE inverts the conventional trade-off: lengthen the token, shorten the revocation. The token can live 28 hours because revocation is an event, not a clock.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The chain is now visible. The signal plane scored Alice&apos;s Tuesday sign-in. The policy plane evaluated the policies. The token issuer issued an access token (CAE-aware because Outlook advertises &lt;code&gt;cp1&lt;/code&gt;). Exchange Online accepted the token and returned mail. If, twelve minutes from now, Alice&apos;s account is flagged high risk because a different sign-in attempt fires &lt;code&gt;leakedCredentials&lt;/code&gt;, the critical event will fire, Exchange will issue a claims challenge, and Outlook will either acquire a fresh token (passing the new CA evaluation) or surface the refusal to the user.&lt;/p&gt;
&lt;p&gt;Six independent components co-decided on one access event. Microsoft is one vendor. The same problem has been solved differently by Google, Okta, AWS, Cloudflare, and Zscaler. The Microsoft answer is not the only correct answer.&lt;/p&gt;
&lt;h2&gt;7. How others do it&lt;/h2&gt;
&lt;p&gt;Microsoft chose to enforce at &lt;em&gt;token issuance and claims challenge&lt;/em&gt;. Google chose to enforce at &lt;em&gt;every HTTP request via a reverse proxy&lt;/em&gt;. AWS chose a decidable policy DSL. These are not minor variations; they are different answers to &quot;where does the policy engine live in the data path?&quot;&lt;/p&gt;
&lt;p&gt;Both Microsoft&apos;s and Google&apos;s models scale. Neither is strictly better. The choice is a function of what the enterprise already runs.&lt;/p&gt;
&lt;h3&gt;Google BeyondCorp, IAP, Chrome Enterprise Premium&lt;/h3&gt;
&lt;p&gt;Google&apos;s Identity-Aware Proxy puts the policy engine in the data path. The documentation calls it bluntly: &quot;IAP lets you establish a central authorization layer for applications accessed by HTTPS, so you can use an application-level access control model instead of relying on network-level firewalls&quot; [@google-iap]. Every HTTP request to an IAP-protected app passes through the proxy. The proxy authenticates the user (via Google Account, Workforce Identity Federation, or Identity Platform), evaluates a Common Expression Language policy against the request context, and -- on allow -- forwards the request to the backend with signed identity headers.&lt;/p&gt;
&lt;p&gt;The BeyondCorp Enterprise product (recently rebranded as Chrome Enterprise Premium) layers context-aware access on top: device posture, geographic location, time of day [@google-bce-overview]. The architecture matches the 2014 USENIX paper [@ward-beyer-2014-beyondcorp] and the 2016 production follow-up [@osborn-2016-beyondcorp].&lt;/p&gt;
&lt;p&gt;The strength is per-request authorization: every HTTP call is its own decision point. The weakness, from the M365 perspective, is that IAP does not gate Microsoft 365 first-party API traffic. The Outlook client does not route through Google&apos;s IAP; it routes through Entra and Exchange Online. For Microsoft 365 workloads, IAP is complementary at best.&lt;/p&gt;
&lt;h3&gt;Okta Identity Engine and ThreatInsight&lt;/h3&gt;
&lt;p&gt;Okta&apos;s policy engine is closer to Microsoft&apos;s structurally: the identity provider is the policy engine, app sign-on policies live on the IdP, and the resource side relies on the IdP&apos;s token rather than a per-request proxy. The Okta Identity Engine documents the rule shape: &quot;App sign-in policies define how a user must authenticate to gain access to an app. They verify ... group membership, the IP zone they&apos;re signing in from, risk level, and others&quot; [@okta-sign-on-policies]. Every new app gets a default policy with a single catch-all rule that allows access with two factors.&lt;/p&gt;
&lt;p&gt;Okta ThreatInsight is the IP-reputation feed. The documentation describes it operationally: &quot;Okta ThreatInsight aggregates data about sign-in activity across the Okta customer base to analyze and detect potentially malicious IP addresses ... password spraying, credential stuffing, brute-force cryptographic attacks&quot; [@okta-threatinsight]. The signal coverage is narrower than ID Protection: ThreatInsight is IP-centric, where ID Protection runs a multi-detection ML pipeline on tokens, sessions, behaviour, and credentials.&lt;/p&gt;
&lt;h3&gt;AWS IAM Identity Center and Verified Access&lt;/h3&gt;
&lt;p&gt;AWS splits the problem. IAM Identity Center handles workforce SSO and trusted identity propagation to AWS services [@aws-iam-identity-center]. AWS Verified Access handles per-request authorization for HTTPS-fronted apps -- the ZTNA piece. The Verified Access docs put it plainly: &quot;Verified Access evaluates each application access request in real time&quot; and &quot;verifies the trustworthiness of users and devices against a set of security requirements&quot; [@aws-verified-access].&lt;/p&gt;
&lt;p&gt;The interesting bit is the policy language: Cedar. Cedar is a deliberately decidable language for authorization policy. &quot;Decidable&quot; here is a precise term: the safety question (will some policy edit, in some future edit chain, leak this right?) is answerable by a static analyser for any Cedar policy [@cedar-security].&lt;/p&gt;
&lt;p&gt;Cedar&apos;s intentional non-Turing-completeness is the language-design hedge against the Harrison-Ruzzo-Ullman undecidability result the next section will name. The trade-off is expressiveness: Cedar cannot express arbitrary computational predicates, which is the price of being analysable [@cedar-security].&lt;/p&gt;
&lt;h3&gt;Cloudflare Access and Zscaler Private Access&lt;/h3&gt;
&lt;p&gt;Cloudflare Access is an edge proxy. Policies are deny-by-default, with four building blocks: Actions (Allow, Block, Bypass, Service Auth), Rule types (Include, Require, Exclude), Selectors, and Values [@cloudflare-access-policies]. The deny-by-default semantics are explicit: &quot;Since Access is deny by default, users who do not match a Block policy will still be denied access unless they explicitly match an Allow policy&quot; [@cloudflare-access-policies]. Cloudflare also ships a policy tester that lets administrators dry-run a policy against the existing user population [@cloudflare-access-policy-mgmt].&lt;/p&gt;
&lt;p&gt;Zscaler Private Access is a broker-based ZTNA: the user connects to a Zscaler edge node, the broker establishes a connection to the private app, and &quot;users never access the corporate network, and apps are never exposed to the public internet&quot; [@zscaler-zpa]. Zscaler&apos;s own marketing surveys put the VPN-replacement framing in numbers: &quot;91% of organizations are concerned that VPNs compromise their security&quot; and &quot;56% of organizations suffered one or more VPN-related attacks in 2023-2024&quot; [@zscaler-zpa].&lt;/p&gt;
&lt;p&gt;Architecturally, Cloudflare Access and ZPA both sit closer to BeyondCorp than to Microsoft CA: the policy engine is in the data path; the protected resource is fronted by the proxy rather than gated at token issuance.&lt;/p&gt;
&lt;h3&gt;OpenID Shared Signals Framework and CAEP&lt;/h3&gt;
&lt;p&gt;Not a competitor: the &lt;em&gt;cross-vendor wire format&lt;/em&gt; for what Microsoft built into CAE. On 22 September 2025, the OpenID Foundation approved three Final Specifications: the Shared Signals Framework 1.0, the Continuous Access Evaluation Profile 1.0, and the Risk Incident Sharing and Coordination Profile 1.0 [@helpnet-2025-openid][@openid-caep-final]. CAEP defines five event types -- Session Revoked, Token Claims Change, Credential Change, Assurance Level Change, Device Compliance Change -- as the cross-vendor revocation vocabulary.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s CAE implementation is, in Microsoft&apos;s own words, &quot;an industry standard based on Open ID Continuous Access Evaluation Profile&quot; [@ms-cae-concept]. The Final Specifications from September 2025 are the canonical post-2025 reference; older drafts at OpenID&apos;s site are superseded.&lt;/p&gt;
&lt;h3&gt;Head-to-head comparison&lt;/h3&gt;
&lt;p&gt;The differences worth memorising:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Enforcement point&lt;/th&gt;
&lt;th&gt;Native risk feed&lt;/th&gt;
&lt;th&gt;Post-issuance revocation&lt;/th&gt;
&lt;th&gt;Gates M365 first-party?&lt;/th&gt;
&lt;th&gt;Best suited for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Microsoft Entra CA + ID Protection + CAE&lt;/td&gt;
&lt;td&gt;Token issuer + CAE-aware resource APIs&lt;/td&gt;
&lt;td&gt;ID Protection ML pipeline&lt;/td&gt;
&lt;td&gt;CAE up to 15 min, instant for IP&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;M365 tenants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google IAP / Chrome Enterprise Premium&lt;/td&gt;
&lt;td&gt;HTTPS reverse proxy&lt;/td&gt;
&lt;td&gt;Context-aware access signals&lt;/td&gt;
&lt;td&gt;Per-request (always re-decides)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Google Cloud workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Okta Identity Engine + ThreatInsight&lt;/td&gt;
&lt;td&gt;IdP token issuance&lt;/td&gt;
&lt;td&gt;ThreatInsight IP feed&lt;/td&gt;
&lt;td&gt;Limited, IdP-dependent&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Vendor-neutral front door&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS IAM Identity Center + Verified Access&lt;/td&gt;
&lt;td&gt;Verified Access proxy + IAM&lt;/td&gt;
&lt;td&gt;Trust providers (third-party)&lt;/td&gt;
&lt;td&gt;Per-request for Verified Access&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;AWS-hosted apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloudflare Access&lt;/td&gt;
&lt;td&gt;Edge proxy&lt;/td&gt;
&lt;td&gt;Risk score + identity factors&lt;/td&gt;
&lt;td&gt;Per-request&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Public web apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zscaler Private Access&lt;/td&gt;
&lt;td&gt;Broker / edge node&lt;/td&gt;
&lt;td&gt;Posture + identity&lt;/td&gt;
&lt;td&gt;Per-request&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Private app access&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Per-cell sourcing for the table: the Microsoft row&apos;s &quot;Yes&quot; cell on M365 first-party gating is the directly-stated claim from the Microsoft Learn CA overview [@ms-ca-overview]. The other rows&apos; &quot;No&quot; cells are &lt;em&gt;negative inferences&lt;/em&gt; drawn from each peer&apos;s own product documentation, none of which advertises Microsoft 365 first-party API gating: Google IAP gates HTTPS-fronted apps behind the proxy [@google-iap]; Cloudflare Access deny-by-default applies to the apps fronted by Cloudflare [@cloudflare-access-policies]; Verified Access &quot;evaluates each application access request&quot; for HTTPS apps behind AWS [@aws-verified-access]; Zscaler ZPA brokers private app access [@zscaler-zpa]; Okta sign-on policies gate apps wired into Okta&apos;s IdP [@okta-sign-on-policies]. The cell semantics are &quot;does the system gate Outlook/Teams/SharePoint/Graph first-party traffic&quot; and the answer is structurally No outside Microsoft.&lt;/p&gt;

flowchart LR
    subgraph TOK[Token issuance model Microsoft Okta]
        U1[User] --&amp;gt; AT[Acquire token]
        AT --&amp;gt; CA1[CA evaluator]
        CA1 --&amp;gt; IS[Issue token]
        IS --&amp;gt; R1[Resource API validates token]
        R1 -. CAE 401 .-&amp;gt; AT
    end
    subgraph PRX[Data path proxy model Google BeyondCorp AWS Verified Access Cloudflare Zscaler]
        U2[User] --&amp;gt; PXY[Proxy intercepts every request]
        PXY --&amp;gt; POL[Policy evaluator at the proxy]
        POL --&amp;gt; BCK[Backend application]
    end
&lt;p&gt;The honest observation worth sitting with: none of the proxy systems gates M365 first-party API traffic. Outlook, Teams, SharePoint, and Microsoft Graph route through Entra. For those workloads, Entra remains the only effective policy plane. The proxy systems gate &lt;em&gt;the apps that sit behind the proxy&lt;/em&gt; -- internal apps, partner-facing apps, custom workloads. That makes BeyondCorp, Okta, Cloudflare Access, and ZPA &lt;em&gt;complementary to&lt;/em&gt; Entra CA in an M365 environment, not substitutes for it.&lt;/p&gt;
&lt;p&gt;Six systems, six architectural choices. None of them wrong. But what do they &lt;em&gt;all&lt;/em&gt; leave on the table?&lt;/p&gt;
&lt;h2&gt;8. What Conditional Access fundamentally cannot do&lt;/h2&gt;
&lt;p&gt;Section 7 cannot be the ending. There are at least five things Conditional Access -- and every peer in Section 7 -- &lt;em&gt;cannot&lt;/em&gt; do. Some are engineering limits; some are theorems. Both classes are worth naming.&lt;/p&gt;
&lt;h3&gt;(a) On-prem authentication&lt;/h3&gt;
&lt;p&gt;CA is a cloud control plane. Kerberos and NTLM against on-prem domain controllers do not consult Entra. There is no policy hook for the legacy Windows protocols. If a domain user signs in to a domain-joined workstation, authenticates to a file server, and accesses a share, no piece of that flow touches Conditional Access. The Microsoft Learn overview is explicit about the scope [@ms-ca-overview].&lt;/p&gt;
&lt;p&gt;This is the operational seam between cloud identity and on-prem identity. State it plainly; do not soften.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Conditional Access does not gate Kerberos or NTLM against on-prem domain controllers. If your threat model includes lateral movement after credential theft on the on-prem side, CA is not your defence. Layer in Defender for Identity, on-prem MFA gateways, or a privileged-access workstation architecture instead.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;(b) Post-issuance token theft&lt;/h3&gt;
&lt;p&gt;Once a refresh token is exfiltrated -- whether via an adversary-in-the-middle phishing kit like Evilginx [@ms-aitm-phishing-blog], an infostealer that scrapes the token cache, or a malicious browser extension -- the pre-issuance CA evaluation is bypassed. The attacker has a bearer token. They can present it to the resource API directly. CAE-aware resource providers can revoke mid-session on the published critical-event list, but the latency ceiling is &quot;up to 15 minutes&quot; for non-IP events [@ms-cae-concept]. In fifteen minutes a competent attacker has done plenty.&lt;/p&gt;
&lt;p&gt;The mitigation is &lt;em&gt;device-bound&lt;/em&gt; credentials: Primary Refresh Tokens bound to &lt;a href=&quot;https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/&quot; rel=&quot;noopener&quot;&gt;TPM&lt;/a&gt; hardware, FIDO2 with hardware attestation, certificate-based authentication with hardware-protected keys [@ms-prt-concept]. A bearer token bound to a TPM is not exfiltratable in the same way; the wrapped key material never leaves the device.&lt;/p&gt;
&lt;h3&gt;(c) Consent-grant phishing&lt;/h3&gt;
&lt;p&gt;CA evaluates &lt;em&gt;authentication&lt;/em&gt;, not &lt;em&gt;authorization grants&lt;/em&gt; that a user makes to a malicious OAuth app. A user who clicks &quot;Allow&quot; on a permissions-consent prompt for an attacker-controlled app has performed an OAuth authorization, not a sign-in. The malicious app now has the user&apos;s delegated permissions for whatever scopes were granted. CA was not invoked because CA gates the user&apos;s sign-ins; it does not inspect the user&apos;s OAuth grants. Microsoft Defender for Cloud Apps documents the attack class as &quot;risky OAuth apps&quot; and ships investigation and remediation tooling on a separate plane from CA [@ms-illicit-consent-grant].&lt;/p&gt;
&lt;p&gt;Admin consent settings, app governance policies, and explicit allow-listing of acceptable publishers live on that different plane. The policy admin who deploys CA needs to deploy app governance separately.&lt;/p&gt;
&lt;h3&gt;(d) Risk evaluation is probabilistic&lt;/h3&gt;
&lt;p&gt;Identity Protection produces a &lt;em&gt;score&lt;/em&gt;, not a &lt;em&gt;proof&lt;/em&gt;. A &quot;high&quot; risk level is a confidence; it is not the assertion &quot;this sign-in is definitely an attack.&quot; No vendor in the Section 7 survey publishes precision or recall numbers for its risk engine. The operating point -- the threshold that maps a continuous score to discrete buckets -- is a trade-off that the vendor calibrates and the customer does not see.&lt;/p&gt;
&lt;p&gt;This is a &lt;em&gt;structural&lt;/em&gt; lower bound on any ML-driven risk plane, not a Microsoft-specific failure. Any classifier has false positives and false negatives. A risk-aware CA policy that says &quot;block at high risk&quot; will, with non-zero probability, block a legitimate sign-in. A policy that says &quot;require MFA at medium risk&quot; will, with non-zero probability, let through a sophisticated attacker whose detections fall under the threshold.&lt;/p&gt;
&lt;h3&gt;(e) Workload-identity CA is constrained by design&lt;/h3&gt;
&lt;p&gt;Block-only grants. No managed identities. No group assignments. The full human grant taxonomy does not transfer because a service principal cannot perform an MFA challenge, cannot register a FIDO2 key, cannot accept a terms-of-use document. The Microsoft Learn page on workload-identity CA enumerates the constraints precisely [@ms-workload-identity-ca]. Section 9 will name this as an &lt;em&gt;open&lt;/em&gt; problem; for now, treat it as a documented limit.&lt;/p&gt;
&lt;h3&gt;The theorems behind the limits&lt;/h3&gt;
&lt;p&gt;Some of these limits are engineering choices that could be different in a future product. Some are deeper.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Saltzer and Schroeder 1975&lt;/strong&gt; [@saltzer-schroeder-1975] give the upper bound on aspirations: complete mediation across every authentication and authorization decision &lt;em&gt;within scope of mediation&lt;/em&gt;. The principle does not constrain what is in scope. It constrains what you must do for whatever you have decided is in scope. On-prem AD is out of scope for CA by Microsoft&apos;s product decision; complete mediation cannot fix that, because the principle is about consistency &lt;em&gt;within&lt;/em&gt; the boundary, not about expanding the boundary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Harrison-Ruzzo-Ullman 1976&lt;/strong&gt; -- usually shortened to HRU [@harrison-ruzzo-ullman-1976] -- gives the lower bound on static analysis. The safety question in the general access-matrix model is &lt;em&gt;undecidable&lt;/em&gt;. In informal terms: there is no general algorithm that proves a Conditional Access policy edit cannot, under some future edit chain, leak a sensitive right. This is why every vendor in the survey relies on &lt;em&gt;evaluation-time&lt;/em&gt; mediation (the engine decides at the moment of the request) rather than &lt;em&gt;static-proof&lt;/em&gt; analysis (the engine certifies in advance that no edit can ever leak). Cedar&apos;s intentional restriction to a decidable fragment, in AWS Verified Access, is the counter-strategy: trade expressiveness for analysability.&lt;/p&gt;
&lt;p&gt;The bearer-token revocation trade-off is informal but real: the worst-case revocation latency is bounded below by the token&apos;s natural lifetime, unless a side channel exists. CAE is that side channel. Its latency is bounded by the propagation time of the channel (up to 15 minutes for non-IP events, instant for IP). Shorten the channel further and you discover that the IdP-to-resource-API event delivery has its own infrastructure costs.&lt;/p&gt;

The practical implication of HRU for a CA admin is that there is no tool, anywhere, that can examine your tenant&apos;s CA policies and certify that no sequence of policy edits could ever leak access to a sensitive resource. Vendors offer policy *testers* that simulate a single edit against the current population; that is decidable. The question &quot;is the system safe under all possible future edits?&quot; is not. This is why audit trails, change-control gates, and least-privilege role assignments on the CA admin role matter as much as the CA policies themselves.
&lt;p&gt;Naming the limits clears the way to name the &lt;em&gt;active&lt;/em&gt; unsolved problems -- the ones the field is still working on, where the current state of the art admits it is partial.&lt;/p&gt;
&lt;h2&gt;9. Where the policy plane is still incomplete&lt;/h2&gt;
&lt;p&gt;Microsoft&apos;s own 2026 documentation for Conditional Access on AI agents calls the current implementation &quot;a lightweight enforcement mechanism designed to block unauthorized or risky agents, not a full policy suite.&quot; That is not marketing modesty. It is an admission that the most active frontier of policy enforcement -- &lt;a href=&quot;https://paragmali.com/blog/agentic-identity-on-windows-when-the-process-acting-on-your-/&quot; rel=&quot;noopener&quot;&gt;agent identities&lt;/a&gt; -- is deliberately under-specified.&lt;/p&gt;
&lt;p&gt;Five open problems sit on that frontier in 2026.&lt;/p&gt;

Organizations are expanding Zero Trust across more users, applications, and now a growing population of AI agent identities ... the Conditional Access Optimization Agent moves beyond static guidance to continuous, context-aware identity posture optimization. [@ms-techcom-ca-optimization-agent]
&lt;h3&gt;9.1 Agent identity policy semantics&lt;/h3&gt;
&lt;p&gt;What grants should exist for AI agents beyond block and allow? Useful candidate grants include: &quot;read-but-not-move&quot; for mail or files; &quot;business-hours-only&quot;; &quot;any autonomous action requires a fresh sign-off from the on-behalf-of human.&quot; None of these exist as first-class CA grant types in 2026.&lt;/p&gt;
&lt;p&gt;What does exist: CA targeting of agent identities -- the ability to &lt;em&gt;match&lt;/em&gt; a policy on the agent identity rather than the human -- and the Conditional Access Optimization Agent, which gives administrators continuous recommendations on policy posture [@ms-techcom-ca-optimization-agent]. The targeting is there. The grant taxonomy is still mostly the human one, applied imperfectly.&lt;/p&gt;
&lt;h3&gt;9.2 Cross-vendor CAEP interop&lt;/h3&gt;
&lt;p&gt;The wire format was finalised in September 2025 [@helpnet-2025-openid][@openid-caep-final]. Production receiver coverage outside Microsoft Entra-internal resource providers is partial. Two large vendors agreeing on an event schema is necessary but not sufficient for cross-vendor revocation to work in practice; the receiving side needs to &lt;em&gt;act&lt;/em&gt; on the events. The next eighteen months are the period in which CAEP either becomes the cross-vendor wire format for revocation, or it does not.&lt;/p&gt;
&lt;h3&gt;9.3 Workload-identity grant set&lt;/h3&gt;
&lt;p&gt;What richer expressions could exist for non-human identities? The current Microsoft Learn page lists workload-identity detections: &lt;code&gt;investigationsThreatIntelligence&lt;/code&gt;, &lt;code&gt;suspiciousSignins&lt;/code&gt;, &lt;code&gt;adminConfirmedServicePrincipalCompromised&lt;/code&gt;, &lt;code&gt;leakedCredentials&lt;/code&gt;, &lt;code&gt;maliciousApplication&lt;/code&gt;, &lt;code&gt;suspiciousApplication&lt;/code&gt;, &lt;code&gt;anomalousServicePrincipalActivity&lt;/code&gt;, &lt;code&gt;suspiciousAPITraffic&lt;/code&gt; [@ms-workload-identity-risk]. The detections exist; the grant taxonomy stops at block.&lt;/p&gt;
&lt;p&gt;Candidate richer grants: &quot;workload attestation&quot; (the service principal proves it is running on attested infrastructure), &quot;verifiable claim from a trusted attester&quot; (a third party signs a statement about the workload), &quot;step-up authorization for sensitive scopes&quot; (a higher-privilege scope requires a separate per-request authorization step). None of these is generally available in 2026.&lt;/p&gt;

A non-human identity in Entra ID: a service principal, an application registration&apos;s owned service principal, or a managed identity in Azure. Workload identities authenticate via client secrets, client certificates, federated credentials, or (for managed identities) instance-metadata-service tokens. Conditional Access for workload identities currently applies only to single-tenant service principals registered in the tenant; it does not cover multi-tenant SaaS apps or managed identities [@ms-workload-identity-ca].
&lt;h3&gt;9.4 The break-glass paradox&lt;/h3&gt;
&lt;p&gt;Emergency-access accounts must be excluded from CA. If a CA misconfiguration locks out every admin, the break-glass account is the recovery path. But exclusion creates a high-value bypass: an attacker who compromises a break-glass account inherits its exclusion.&lt;/p&gt;
&lt;p&gt;There is no clean answer. Microsoft&apos;s guidance is exclusion plus FIDO2 binding plus alerting: the break-glass accounts have hardware-bound FIDO2 keys (so they cannot be phished), they are excluded from all CA policies (so misconfiguration cannot lock them out), and &lt;em&gt;every&lt;/em&gt; sign-in is alerted on (so misuse is detected within minutes) [@ms-emergency-access].&lt;/p&gt;

Run two break-glass accounts, not one. Store the FIDO2 keys in separate physical safes under separate custodians. Never use them for anything but a recovery exercise once per quarter; if they sign in unexpectedly, treat the alert as a P1 incident. The operational pattern accepts that you have a bypass and treats the bypass as the highest-value alert in the tenant [@ms-emergency-access].
&lt;h3&gt;9.5 The risk-engine transparency problem&lt;/h3&gt;
&lt;p&gt;No vendor in the Section 7 survey publishes model architecture, feature vector size, or per-detection precision and recall. Microsoft does not. Okta does not. Google does not. Defenders, auditors, and regulators must accept a black-box score.&lt;/p&gt;
&lt;p&gt;This matters in three places. First, for incident response: when an &quot;atypical travel&quot; detection fires for an executive, the responder cannot see which features contributed and how strongly. Second, for compliance: an auditor asked to evidence the effectiveness of the control plane gets the operating output (3-tier risk levels) but not a quantitative evaluation. Third, for the risk-engine vendors themselves, who must respond to legitimate regulatory questions about model bias and operational reliability without revealing the architecture that attackers would use to evade detection.&lt;/p&gt;
&lt;p&gt;The article does not predict a resolution. It names the gap.&lt;/p&gt;
&lt;p&gt;The architecture is incomplete by admission. It is also actionable today. A competent tenant administrator can deploy a sensible baseline in an afternoon.&lt;/p&gt;
&lt;h2&gt;10. Using Conditional Access today&lt;/h2&gt;
&lt;p&gt;The architectural story ends; the operational story begins. Here is what a competent tenant looks like in 2026.&lt;/p&gt;
&lt;h3&gt;The licensing reality&lt;/h3&gt;
&lt;p&gt;Conditional Access is not a feature every Microsoft 365 tenant gets. It is a feature gated by SKU. The licensing tiers are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Entra ID Free.&lt;/strong&gt; Security Defaults only [@ms-security-defaults]. No Conditional Access policies. No risk-based conditions. No CA-driven CAE (the critical-event-evaluation subsystem -- for events like account disable, password reset, and high user risk -- still propagates to CAE-aware M365 services at the service layer regardless of SKU; see Section 6.6) [@ms-cae-concept].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entra ID P1.&lt;/strong&gt; Conditional Access is unlocked [@ms-ca-overview]. You can author policies with any of the non-risk conditions: users, apps, locations, devices, client app, platform. You can demand any of the non-risk grants.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entra ID P2.&lt;/strong&gt; Adds risk-based conditions. &lt;code&gt;signInRiskLevels&lt;/code&gt; and &lt;code&gt;userRiskLevels&lt;/code&gt; become usable [@ms-id-protection-overview]. ID Protection&apos;s full report pane (risky users, risky sign-ins, risk detections) is accessible. The legacy ID-Protection-side risk policies retire 1 October 2026 [@ms-id-protection-policies].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Workload Identities Premium.&lt;/strong&gt; A separate SKU. Unlocks CA scoped to service principals [@ms-workload-identity-ca].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This corrects a premise discarded earlier: &quot;Conditional Access is the policy plane every M365 tenant runs on&quot; is &lt;em&gt;not&lt;/em&gt; true. Many tenants run on Security Defaults. The &quot;policy plane every tenant runs on&quot; is the cloud sign-in pipeline; CA is the configurable richer layer that P1+ tenants opt into.&lt;/p&gt;
&lt;h3&gt;Start with the managed baselines&lt;/h3&gt;
&lt;p&gt;Microsoft-managed Conditional Access policies are the recommended starting point [@ms-managed-policies]. They auto-deploy in Report-only mode, run for at least 45 days while administrators review the impact in the Sign-in logs, and are auto-enabled with a 28-day pre-enablement notification unless administrators opt out [@ms-managed-policies]. The currently shipping baselines, per Microsoft Learn, include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MFA for admins accessing Microsoft admin portals (the most-privileged roles).&lt;/li&gt;
&lt;li&gt;MFA for users who already have per-user MFA enabled (a migration aid).&lt;/li&gt;
&lt;li&gt;MFA and reauthentication for risky sign-ins (the P2 baseline).&lt;/li&gt;
&lt;li&gt;Block legacy authentication.&lt;/li&gt;
&lt;li&gt;Block access for high-risk users (P2-tier protection on the user-risk surface).&lt;/li&gt;
&lt;li&gt;Block all high-risk agents accessing all resources (Preview, AI-agent surface).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The original announcement called for a 90-day report-only window [@weinert-2023-managed-policies][@helpnet-2023-microsoft-entra-policies]. The current default is 45 days [@ms-managed-policies]; the window shrank as Microsoft gained confidence that customers were not surprised by the auto-enablement.&lt;/p&gt;
&lt;h3&gt;Five custom policies on top of the baselines&lt;/h3&gt;
&lt;p&gt;Beyond the managed policies, every well-run tenant in operational experience runs five custom policies on top of the baselines [@ms-ca-policy-common]: block legacy authentication unconditionally [@ms-managed-policies]; require the phishing-resistant Authentication Strength for any user in a privileged role [@ms-auth-strengths]; require &lt;code&gt;compliantDevice&lt;/code&gt; for admin centres, finance apps, and customer-data exports [@ms-intune-compliance-partners]; restrict privileged sign-ins to a named-location allow-list with block-or-step-up outside it [@ms-ca-network]; and, where Entra ID P2 is licensed, demand a sign-in-risk-based step-up (MFA at high risk, a passwordless or phishing-resistant method at medium risk) [@ms-id-protection-policies].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 1. Block legacy authentication. 2. Phishing-resistant Authentication Strength for admin roles. 3. Require compliant device for sensitive applications. 4. Named-location restrictions for privileged roles. 5. Sign-in-risk-based step-up where Entra ID P2 is available.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Automation entry points (Microsoft Graph)&lt;/h3&gt;
&lt;p&gt;The Graph endpoints administrators care about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /identity/conditionalAccess/policies&lt;/code&gt; -- list policies. &lt;code&gt;POST&lt;/code&gt; to create, &lt;code&gt;PATCH&lt;/code&gt; to update [@ms-graph-capolicy].&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /identityProtection/riskDetections&lt;/code&gt; -- the per-detection log. Filterable by &lt;code&gt;riskLevel&lt;/code&gt;, &lt;code&gt;riskState&lt;/code&gt;, &lt;code&gt;userPrincipalName&lt;/code&gt;, &lt;code&gt;activityDateTime&lt;/code&gt; [@ms-graph-riskdetection].&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /identityProtection/riskyUsers&lt;/code&gt; -- the per-user risk view.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A policy authored in code looks like this (truncated for readability):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;displayName&quot;: &quot;Require phishing-resistant for admins&quot;,
  &quot;state&quot;: &quot;enabledForReportingButNotEnforced&quot;,
  &quot;conditions&quot;: {
    &quot;users&quot;: { &quot;includeRoles&quot;: [&quot;62e90394-69f5-4237-9190-012177145e10&quot;] },
    &quot;applications&quot;: { &quot;includeApplications&quot;: [&quot;All&quot;] }
  },
  &quot;grantControls&quot;: {
    &quot;operator&quot;: &quot;OR&quot;,
    &quot;authenticationStrength&quot;: { &quot;id&quot;: &quot;00000000-0000-0000-0000-000000000004&quot; }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The recommended deployment dance is &lt;code&gt;enabledForReportingButNotEnforced&lt;/code&gt; first; let the Sign-in log show you the impact for a calibration window; promote to &lt;code&gt;enabled&lt;/code&gt; only after the report-only data matches expectations [@ms-ca-report-only].&lt;/p&gt;
&lt;h3&gt;Audit-time visibility&lt;/h3&gt;
&lt;p&gt;Three surfaces matter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sign-in logs&lt;/strong&gt; in the Entra portal show the per-sign-in evaluation, including which CA policies matched and which grants were satisfied.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Risk-detection log&lt;/strong&gt; in Identity Protection (P2 only) shows the per-detection narrative: which &lt;code&gt;riskEventType&lt;/code&gt; fired, with what &lt;code&gt;additionalInfo&lt;/code&gt;, against which user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The What-If tool&lt;/strong&gt; simulates a policy evaluation for a hypothetical sign-in, before you enable a policy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Detection engineering&lt;/h3&gt;
&lt;p&gt;For E5 tenants, the Sign-in logs and risk detections flow into Microsoft Sentinel (via the Microsoft Entra ID connector) or Defender XDR [@ms-sentinel-aad-connector]. A KQL skeleton for high-risk-with-CA-failure looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kusto&quot;&gt;SigninLogs
| where ResultType != 0
| join kind=inner (AADRiskDetections | where RiskLevel == &quot;high&quot;) on UserPrincipalName, CorrelationId
| project TimeGenerated, UserPrincipalName, IPAddress, ConditionalAccessStatus, RiskEventType, FailureReason
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The aggregate scale figure is worth remembering: Microsoft processes &quot;more than 100 trillion security signals&quot; daily across all identity products [@ms-managed-policies]. The detection engineer is consuming a small slice that landed in their tenant.&lt;/p&gt;

Run the following in Microsoft Sentinel or the Entra advanced hunting blade to surface sign-ins that succeeded *despite* a high-confidence risk detection -- the most operationally interesting subset. The query is original to this article; the schema it targets is the canonical Microsoft Sentinel Entra ID connector tables `SigninLogs` and `AADRiskDetections` [@ms-sentinel-aad-connector], and the join-and-filter pattern follows the practice documented in Microsoft&apos;s Sentinel hunting guidance [@ms-sentinel-hunting].&lt;pre&gt;&lt;code class=&quot;language-kusto&quot;&gt;let window = 7d;
SigninLogs
| where TimeGenerated &amp;gt; ago(window)
| where ResultType == 0
| where ConditionalAccessStatus == &quot;success&quot;
| join kind=inner (
    AADRiskDetections
    | where TimeGenerated &amp;gt; ago(window)
    | where RiskLevel == &quot;high&quot;
) on UserPrincipalName, CorrelationId
| project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName, RiskEventType, ConditionalAccessPolicies
| order by TimeGenerated desc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The expected count for a well-tuned tenant is small. Spikes warrant a P2 investigation.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;Break-glass&lt;/h3&gt;
&lt;p&gt;Two emergency-access accounts. FIDO2-bound. Excluded from every CA policy. Stored as separate hardware tokens in separate safes. Every sign-in is wired to a P1 alert. Per Section 9.4 and Microsoft Learn&apos;s emergency-access guidance, this is the acknowledged operational compromise to the break-glass paradox [@ms-emergency-access].&lt;/p&gt;

A non-personal Entra ID administrator account excluded from Conditional Access and from MFA enforcement, used only when the primary identity infrastructure has failed. Best practice: at least two such accounts, with hardware FIDO2 keys stored separately, monitored by an unconditional alert on any sign-in.
&lt;p&gt;The article has answered &quot;who decided?&quot; five times over: by signal, by policy, by token, by session, by operational pattern. One section remains: the misconceptions that keep recurring.&lt;/p&gt;
&lt;h2&gt;11. Misconceptions that recur&lt;/h2&gt;
&lt;p&gt;Every time these questions come up in practice, the same wrong answers come back. The corrections are worth memorising.&lt;/p&gt;

Only if you have Entra ID P1 or higher and have configured CA policies. Free SKU tenants run Security Defaults, which is a coarse tenant-wide on/off switch, not CA [@ms-security-defaults]. CA is unlocked at P1 [@ms-ca-overview]; risk-based conditions are unlocked at P2 [@ms-id-protection-overview]. The &quot;every tenant runs on CA&quot; framing you sometimes see in marketing material is incorrect.

No. CA is a cloud control plane. Kerberos and NTLM against on-prem domain controllers do not consult Entra at all [@ms-ca-overview]. If your threat model includes on-prem lateral movement, layer in Defender for Identity and the standard on-prem hardening playbook.

No. CAE is event-driven push from the policy plane to CAE-aware resource APIs. The Microsoft Learn CAE document gives the latency ceiling precisely: &quot;the goal for critical event evaluation is for response to be near real time, but latency of up to 15 minutes might be observed because of event propagation time; however, IP locations policy enforcement is instant&quot; [@ms-cae-concept]. There is no 30-second poll. The token can live up to 28 hours because the revocation is event-driven.

No. Clients advertise CAE-readiness via the `cp1` client capability in token requests, specifically by adding `cp1` to the `xms_cc` claim mechanism (or by calling `WithClientCapabilities(new[] { &quot;cp1&quot; })` in MSAL) [@ms-claims-challenge][@ms-app-resilience-cae]. The Microsoft Learn claims-challenge page is explicit: &quot;The only currently known value is `cp1`&quot; [@ms-claims-challenge]. The CAE-aware token is recognisable by its long lifetime (up to 28 hours) and by the resource API&apos;s willingness to issue an `insufficient_claims` challenge, not by a Boolean claim.

No. Third-party MDM compliance partners can write the device compliance state into Entra via Intune&apos;s compliance-partner API [@ms-intune-compliance-partners]. The CA grant reads `isCompliant` on the device object; it does not care which MDM wrote that value. Microsoft&apos;s preferred deployment is Intune, but the integration point is open by design.

In 2023. The public preview of CA filters for workload identities opened on 26 October 2022 [@vansurksum-2022-workload-ca]; the Microsoft Entra Workload Identities standalone product reached GA in late November 2022, and the Conditional Access feature itself reached general availability later in 2023 [@ms-workload-identity-ca]. Any article asserting a 2025 GA date for workload-identity CA is incorrect.

No. Every sign-in produces a Sign-in log entry; ID Protection emits a `riskDetection` only when at least one detector fires for that sign-in [@ms-graph-riskdetection]. Most sign-ins produce no `riskDetection`. Detection engineers querying for risk should join the Sign-in log with the riskDetections log and treat unjoined rows as &quot;no risk flagged at the moment.&quot;

No Microsoft primary source publicly describes the production model architecture or names a per-sign-in feature-vector size. What is published is the detection taxonomy (about two dozen named `riskEventType` values [@ms-id-protection-risks][@ms-graph-riskdetection]), the timing split (real-time / near-real-time / offline [@ms-risk-detection-types]), and the three-tier risk output. The &quot;transformer with 80+ signals&quot; framing is folk knowledge with no Microsoft primary source behind it. The article reframes it as &quot;ML-based with detailed architecture publicly undisclosed.&quot;

Not on its own. A standard MFA grant does not defeat a kit like Evilginx, which proxies both the password and the MFA challenge in real time. The defence is to require the *phishing-resistant Authentication Strength* in CA: FIDO2 with hardware attestation, Windows Hello for Business, or multifactor certificate-based authentication [@ms-auth-strengths]. The cryptographic origin-binding in WebAuthn-class credentials defeats AitM by construction. But the defence only works *when the grant is applied*. A CA policy that demands phishing-resistant for admin roles but not for users will block AitM against admins and not against users.
&lt;h2&gt;12. Two planes, one boundary&lt;/h2&gt;
&lt;p&gt;Replay Alice&apos;s Tuesday.&lt;/p&gt;
&lt;p&gt;Identity Protection&apos;s signal plane scored her 09:02 sign-in. The score was below the medium-risk threshold. Conditional Access&apos;s policy plane evaluated four matching policies. Two demanded MFA; her cached refresh token already satisfied that grant from yesterday. One demanded a compliant device; Intune had marked her laptop compliant overnight. None demanded the block grant. The token issuer issued a CAE-aware bearer token with a 28-hour lifetime. Exchange Online accepted the token. Outlook&apos;s data path opened. Bytes returned to Alice.&lt;/p&gt;
&lt;p&gt;If, twelve minutes later, an attacker tries to sign in with Alice&apos;s credentials from an anonymizing proxy, ID Protection will fire a detection. The detection will lift her user risk to high. CAE will deliver the high-user-risk event to Exchange. Exchange will issue a claims challenge on the next call from Alice&apos;s Outlook. Outlook will replay the challenge to Entra. Entra will re-run CA, see the elevated risk, demand step-up MFA, and either issue a fresh token (after Alice satisfies the step-up) or refuse.&lt;/p&gt;
&lt;p&gt;The modern identity boundary is not a wall. It is a conversation between planes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The boundary is a conversation between planes, not a wall.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The open frontier is real. Agent identities want a richer grant taxonomy than the human one provides. Cross-vendor CAEP wants production receivers outside Microsoft. Workload-identity policy wants grants that go beyond block. The break-glass paradox wants an answer that does not depend on operational discipline. None of these problems will resolve in 2026. They are the next frontier.&lt;/p&gt;
&lt;p&gt;What the reader should now be able to do: trace a sign-in through the signal, policy, token, and session planes; read a &lt;code&gt;conditionalAccessPolicy&lt;/code&gt; JSON and predict the evaluation outcome; identify which class of attack each grant defends against; and name, by reference to specific Microsoft Learn pages, what CA does &lt;em&gt;not&lt;/em&gt; defend against. The promise from Section 1 is delivered.&lt;/p&gt;

Today, 100 percent of consumer Microsoft accounts older than 60 days have multifactor authentication. -- Alex Weinert, Microsoft Identity, November 2023 [@weinert-2023-managed-policies]
&lt;p&gt;Who decided this token is good? The boundary itself decided, by composing the work of every plane named above.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;conditional-access-and-entra-id-protection&quot; keyTerms={[
  { term: &quot;Conditional Access (CA)&quot;, definition: &quot;Microsoft Entra&apos;s JSON-driven policy engine that matches users, apps, and conditions against grants such as block, MFA, and phishing-resistant Authentication Strength.&quot; },
  { term: &quot;Microsoft Entra ID Protection&quot;, definition: &quot;The ML-driven signal plane that emits riskDetection events tagged with riskEventType, riskLevel, riskState, and detectionTimingType.&quot; },
  { term: &quot;Continuous Access Evaluation (CAE)&quot;, definition: &quot;The event-driven session plane between Entra and CAE-aware resource APIs; uses HTTP 401 with WWW-Authenticate insufficient_claims to trigger mid-session re-evaluation.&quot; },
  { term: &quot;Sign-in risk vs user risk&quot;, definition: &quot;Sign-in risk is per-session probability the credential is being used by an attacker; user risk is per-user probability the account is compromised over recent history.&quot; },
  { term: &quot;Authentication Strength&quot;, definition: &quot;A named bundle of acceptable authentication methods that a CA grant can demand; the phishing-resistant strength defeats AitM by binding the credential to the relying-party origin via WebAuthn.&quot; },
  { term: &quot;Primary Refresh Token (PRT)&quot;, definition: &quot;A long-lived refresh token issued to a Windows session at user sign-in to Entra-joined or hybrid-joined devices, bound to the TPM where available, subject to CA at issuance.&quot; },
  { term: &quot;Claims challenge (insufficient_claims)&quot;, definition: &quot;HTTP 401 wire format CAE uses to demand a fresh token: WWW-Authenticate: Bearer error=&quot;insufficient_claims&quot;, claims=&quot;&quot;.&quot; },
  { term: &quot;Workload identity&quot;, definition: &quot;A non-human Entra identity (service principal, managed identity, or app registration&apos;s owned service principal); CA for workload identities applies only to single-tenant service principals with a block-only grant set.&quot; },
  { term: &quot;Break-glass account&quot;, definition: &quot;An emergency-access account excluded from Conditional Access, ideally FIDO2-bound, monitored by an unconditional sign-in alert.&quot; }
]} questions={[
  { q: &quot;What is the only API surface between Entra ID Protection (the signal plane) and Conditional Access (the policy plane), and why does the answer explain the maintainability of the architecture across a decade?&quot;, a: &quot;Two condition keys on the CA policy: signInRiskLevels and userRiskLevels. Because the contract is two strings, the risk model can be re-trained without policy rewrites, and policies can evolve without retraining the model.&quot; },
  { q: &quot;Why did Microsoft reject the &apos;shortened token lifetime&apos; approach to revocation, and what did they ship instead?&quot;, a: &quot;Shortened token lifetimes degraded user experience and reliability without eliminating risks (Microsoft&apos;s documented &apos;blunt object&apos; framing). CAE lengthens tokens (up to 28 hours) and adds an event-driven side channel that fires HTTP 401 with insufficient_claims when a critical event occurs.&quot; },
  { q: &quot;Name the documented critical events that fire a CAE claims challenge, and the documented latency ceiling.&quot;, a: &quot;Five critical events: account disabled or deleted, password change or reset, MFA enabled by an admin, admin token revocation, and high user risk detected by ID Protection. A parallel pathway propagates network-location and CA policy changes on the same channel. Latency is up to 15 minutes for non-IP events, instant for IP locations.&quot; },
  { q: &quot;Why does Conditional Access not gate on-prem Active Directory logons?&quot;, a: &quot;CA is a cloud control plane. Kerberos and NTLM against on-prem domain controllers authenticate against the on-prem KDC and do not consult Entra. This is a documented scope limit, not a bug.&quot; },
  { q: &quot;What HRU result establishes a theoretical lower bound on what CA can guarantee, and what is the practical implication?&quot;, a: &quot;Harrison-Ruzzo-Ullman 1976 proves the safety question in the general access-matrix model is undecidable. Practically, no tool can certify that no sequence of policy edits will ever leak access to a sensitive resource; vendors rely on evaluation-time mediation rather than static proof.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>conditional-access</category><category>entra-id</category><category>identity-protection</category><category>continuous-access-evaluation</category><category>zero-trust</category><category>security</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Inside the Primary Refresh Token: The Cryptographic Seam Between Windows Logon and Microsoft Entra ID</title><link>https://paragmali.com/blog/inside-the-primary-refresh-token-the-cryptographic-seam-betw/</link><guid isPermaLink="true">https://paragmali.com/blog/inside-the-primary-refresh-token-the-cryptographic-seam-betw/</guid><description>How one TPM-bound JWT issued at first sign-in bridges Windows logon and Microsoft Entra ID -- and how Pass-the-PRT taught Microsoft to bind the derivation to the message.</description><pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate><content:encoded>
The **Primary Refresh Token (PRT)** is the cryptographic seam where a Windows logon becomes a Microsoft Entra ID transaction. It is a JWT issued by Microsoft Entra ID to the CloudAP plugin in `lsass` at first interactive sign-in on an Entra-registered, Entra-joined, or Entra-hybrid-joined device. The PRT is signed at issuance by a TPM-bound **device key** (`dkpriv`); every downstream artifact -- the `x-ms-RefreshTokenCredential` browser cookie, app-token requests via WAM, Conditional Access claim flow -- is signed by a session key returned encrypted under the device&apos;s **transport key** (`tkpub`). In 2020, Dirk-jan Mollema and Lee Christensen showed that even with TPM-bound keys, admin on the live device could mint cookies anywhere -- the Pass-the-PRT class. Microsoft closed off-device replay with **KDFv2** (CVE-2021-33779, July 2021), then layered Continuous Access Evaluation, Token Protection, and Cloud Kerberos Trust on top. On-device Cookie-on-Demand attacks remain the open residual.
&lt;h2&gt;1. Three sign-ins, one credential&lt;/h2&gt;
&lt;p&gt;A user signs into a freshly enrolled Entra-joined laptop with &lt;a href=&quot;https://paragmali.com/blog/your-face-is-not-your-password-inside-windows-hellos-hardwar/&quot; rel=&quot;noopener&quot;&gt;Windows Hello for Business&lt;/a&gt;. Ten seconds later they open Outlook, which silently authenticates against Microsoft 365. An hour later they type &lt;code&gt;outlook.office.com&lt;/code&gt; into Edge -- and they are already signed in there too.&lt;/p&gt;
&lt;p&gt;Three sign-ins, one credential. The credential was issued during the Windows logon itself, and the user has never seen it.&lt;/p&gt;
&lt;p&gt;This article is about that credential -- the &lt;strong&gt;Primary Refresh Token&lt;/strong&gt; -- and about the cryptographic seam where Windows logon stops being a local NT-style event and becomes a Microsoft Entra ID transaction.&lt;/p&gt;

A device-bound JSON Web Token issued by Microsoft Entra ID to the Cloud Authentication Provider in `lsass.exe` at first interactive sign-in on a Microsoft Entra-registered, Entra-joined, or Entra-hybrid-joined device. The PRT is the artifact every other token broker on the device references to mint app access tokens, browser SSO cookies, and Conditional Access claims for the lifetime of the sign-in session [@prt-msft-learn].
&lt;p&gt;The questions worth asking are concrete. What does that token actually contain? How did it get from &lt;code&gt;lsass&lt;/code&gt; to a browser cookie without the user ever pasting it? Why is the cookie that rides in the browser called &lt;code&gt;x-ms-RefreshTokenCredential&lt;/code&gt; when the PRT itself never leaves the device? And -- the question that will define everything in §5 and §6 -- if the credential is bound to a TPM, how did three independent researchers in the summer of 2020 mint cookies anywhere they wanted to?&lt;/p&gt;
&lt;p&gt;The plan is to answer those questions in order. We will name every load-bearing primitive in the stack. We will walk a token request end-to-end. We will explain what the July 2021 KDFv2 patch actually changed at the byte level. And we will be honest about what the PRT cannot do -- because the rest of this series is about the identity surfaces that run alongside it, not under it.&lt;/p&gt;
&lt;p&gt;Before we can read the PRT itself, we have to understand the problem it was built to solve. That means going back to 2013, before Azure AD Join was a thing.&lt;/p&gt;
&lt;h2&gt;2. The cloud-identity gap, 2011 to 2014&lt;/h2&gt;
&lt;p&gt;Windows authentication, in 2011, did not speak cloud. &lt;a href=&quot;https://paragmali.com/blog/ntlmless-the-death-of-ntlm-in-windows/&quot; rel=&quot;noopener&quot;&gt;NTLM&lt;/a&gt; resolved against a local SAM database. &lt;a href=&quot;https://paragmali.com/blog/kerberos-in-windows-the-other-half-of-ntlmless/&quot; rel=&quot;noopener&quot;&gt;Kerberos&lt;/a&gt; resolved against an on-prem Key Distribution Center. Both predate the notion of a cloud identity provider by more than a decade. When a Windows endpoint authenticated, it talked to a domain controller it could see on the network -- and if it could not see a domain controller, it talked to the local SAM and called it a day.&lt;/p&gt;
&lt;p&gt;For a cloud-only workload, that left a gap shaped like a question. Where, exactly, does the user&apos;s identity live when there is no on-prem domain to resolve it against?&lt;/p&gt;
&lt;p&gt;The first answer was OAuth. RFC 6749 had shipped in October 2012, edited by Dick Hardt while at Microsoft, with refresh tokens explicitly modeled as long-lived bearer credentials redeemed at a token endpoint for short-lived access tokens [@rfc-6749]. Microsoft&apos;s Active Directory Authentication Library -- ADAL -- took the obvious next step: every application that wanted to talk to Microsoft&apos;s cloud APIs got its own client, its own redirect, and its own refresh token. SSO was approximated by sharing the underlying password prompt or, on a domain-joined machine, by hoping Integrated Windows Authentication smuggled the right Kerberos ticket to the right endpoint.&lt;/p&gt;
&lt;p&gt;That patchwork held for a while. It also taught Microsoft two things.&lt;/p&gt;
&lt;p&gt;The first lesson was about Conditional Access. If every app maintained its own refresh-token cache and re-presented credentials independently, the policy engine could only see what each token request happened to surface. Whether the request came from a managed Surface or from an unmanaged consumer laptop was anyone&apos;s guess. The device, in other words, was invisible.&lt;/p&gt;
&lt;p&gt;The second lesson was about the user. Ten apps meant ten silent renewal pipelines, ten password prompts when those pipelines broke, and ten different broker components asking &quot;are you sure?&quot; in slightly different language. The user experience and the security posture were on the same side of the ledger: both wanted a single device-bound credential that every broker could reference.&lt;/p&gt;
&lt;p&gt;The first move was small. On 28 June 2013, Adam Hall announced &lt;strong&gt;Workplace Join&lt;/strong&gt; as part of Windows Server 2012 R2: a device-registration primitive that put an X.509 certificate from the Device Registration Service into Active Directory, so that &quot;users can register their device using Workplace Join which creates a new device object in Active Directory and installs a certificate on the device, allowing IT to take into account the user&apos;s device authentication as part of conditional access policies&quot; [@workplace-join-2013].&lt;/p&gt;
&lt;p&gt;Workplace Join taught the directory that a device existed. It did not make the Windows sign-in itself a cloud event. The artifact it produced was a long-lived certificate, not a session-scoped credential, and it lived on the on-prem AD side of the seam, not the cloud side. For the rest, Microsoft would need a credential the cloud could mint &lt;em&gt;during&lt;/em&gt; the sign-in.&lt;/p&gt;
&lt;p&gt;That credential arrived in 2015 -- but its design took another year to harden.&lt;/p&gt;
&lt;h2&gt;3. Workplace Join, Azure AD Join, and the OAuth-refresh-token patchwork&lt;/h2&gt;
&lt;p&gt;What does it cost a Windows endpoint to authenticate to ten cloud apps if it has no PRT?&lt;/p&gt;
&lt;p&gt;Counting tokens is a good way to find out. Each app maintains its own refresh-token cache. Each refresh redeems against the same &lt;code&gt;login.microsoftonline.com&lt;/code&gt; endpoint but with a different &lt;code&gt;client_id&lt;/code&gt; and a different audience claim. Each app re-asserts the device claim as a separate transaction -- if it can; an app that does not ride a broker can only surface what its own credential flow knows. The architectural failure mode is not that authentication is &lt;em&gt;bad&lt;/em&gt;; it is that authentication is &lt;em&gt;redundant&lt;/em&gt;, and the policy engine sees a hundred small claims instead of one big one.&lt;/p&gt;
&lt;p&gt;Microsoft walked out of that failure mode in three steps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step one (June 2013): Workplace Join.&lt;/strong&gt; A device cert, signed by the Device Registration Service, written to a new device object in Active Directory. Adam Hall&apos;s announcement is the load-bearing primary source [@workplace-join-2013]. Nothing about a session: the certificate lives across reboots, across sign-ins, across user accounts. Microsoft now calls this state &lt;strong&gt;Microsoft Entra registered&lt;/strong&gt; -- the same primitive, renamed [@entra-devices-overview].&quot;Workplace Join&quot; was the 2013 marketing name. The same artifact is now called &quot;Microsoft Entra registered&quot; and is the device state used for personal (BYOD) devices that get conditional-access policies applied to corporate workloads. The taxonomy in §3 of the current Microsoft Learn documentation lists three states: Microsoft Entra registered, Microsoft Entra joined, and Microsoft Entra hybrid joined [@entra-devices-overview].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step two (May 2015): Azure AD Join.&lt;/strong&gt; On 28 May 2015, Alex Simons and Gary Henderson announced that Windows 10, build 1507, would let a device sign in against a cloud-only Microsoft identity at first boot. &quot;Azure AD join is optimized for users that primarily access cloud resources,&quot; the announcement reads -- a quiet way of saying that for the first time, a Windows machine did not need a domain controller on the network to give a user a sign-in surface [@techcomm-azure-ad-join-2015].&lt;/p&gt;
&lt;p&gt;This 28 May 2015 Tech Community post is the corrected primary source. An older URL in the same series (&lt;code&gt;.../ba-p/247010&lt;/code&gt;) was re-tagged by Microsoft&apos;s CMS to a 2010 RemoteFX article and now resolves to unrelated content; the 244005 post is the load-bearing technical announcement.&lt;/p&gt;
&lt;p&gt;The Azure AD Join story introduced one more component: &lt;strong&gt;CloudAP&lt;/strong&gt;, the Cloud Authentication Provider, an authentication-package framework hosted inside &lt;code&gt;lsass.exe&lt;/code&gt;. CloudAP is the LSASS-resident broker that an enterprise SSO surface talks to from inside the operating system. It is not yet a PRT engine -- in May 2015, it is mostly a routing layer for cloud sign-in primitives. The PRT itself does not exist yet.&lt;/p&gt;

A pluggable authentication-package framework introduced inside `lsass.exe` to host cloud-identity sign-in plugins. The Microsoft Entra ID plugin (`aadcloudap.dll`) is the canonical implementation; CloudAP is the LSASS-resident broker that, from Windows 10 1607 onward, owns the device-side PRT lifecycle on Entra-joined and Entra-hybrid-joined machines [@prt-msft-learn].
&lt;p&gt;&lt;strong&gt;Step three (August 2016): the first PRT.&lt;/strong&gt; Windows 10, version 1607 -- the Anniversary Update -- began rolling out on 2 August 2016 [@win10-anniv-1607]. In that build, CloudAP gained an Entra ID plugin that minted a PRT during interactive sign-in, alongside a &lt;a href=&quot;https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/&quot; rel=&quot;noopener&quot;&gt;TPM&lt;/a&gt;-bound key pair for proof of possession. From that moment, every other broker on the machine -- the Web Account Manager that backed native apps, Edge for browser SSO, third-party &lt;code&gt;mstsc&lt;/code&gt; flows that wanted to redirect a sign-in -- had a single artifact to reference. The architectural gap from §2 closed; the patchwork became a stack.&lt;/p&gt;
&lt;p&gt;By the time Microsoft Open Specifications publication MS-OAPXBC went public on 16 October 2015, version 1.0 -- contemporaneous with the Windows 10 1507 release, not three years later -- the protocol scaffolding was already in place [@ms-oapxbc-index]. The PRT itself was the credential the scaffolding had been waiting for.&lt;/p&gt;
&lt;p&gt;By 2016, Microsoft had a name for the missing primitive: one device-bound, session-scoped, cloud-issued credential that all brokers could reference. The Anniversary Update made it real. The next question is what that credential &lt;em&gt;is&lt;/em&gt; cryptographically -- and to answer that, we need to be precise about two key pairs that most descriptions of the PRT conflate.&lt;/p&gt;

timeline
    title PRT generations, 2013 to 2022
    2013 : Workplace Join (Windows Server 2012 R2)
         : Device cert in AD; no session credential
    2015 : Azure AD Join (Windows 10 1507)
         : CloudAP framework in lsass; no PRT yet
    2016 : First PRT (Windows 10 1607)
         : CloudAP + Entra plugin issue device-bound JWT
    2020 : Pass-the-PRT class disclosed
         : Christensen + Mollema + Syynimaa
    2021 : KDFv2 (CVE-2021-33779)
         : SHA256 of payload mixed into derivation
    2022 : CAE GA + Cloud Kerberos Trust + TROOPERS 22
         : Composition era begins
&lt;h2&gt;4. The two-key cryptographic model&lt;/h2&gt;
&lt;p&gt;Most descriptions of the PRT online say the cookie is &quot;DKey-signed.&quot; That phrase has been wrong since July 2021. Here is the actual cryptographic substrate.&lt;/p&gt;
&lt;p&gt;When a Windows device joins Microsoft Entra ID -- by way of the Out-of-Box Experience, by &lt;code&gt;dsreg&lt;/code&gt;&apos;s join command, or by the implicit registration that happens on a personal device -- the registration component generates &lt;strong&gt;two&lt;/strong&gt; key pairs on the device. One pair signs PRT &lt;em&gt;issuance&lt;/em&gt; requests. The other unwraps session keys returned &lt;em&gt;with&lt;/em&gt; the PRT. Microsoft&apos;s own documentation enumerates the two pairs the &lt;code&gt;dsreg&lt;/code&gt; component generates at device registration: Device key (&lt;code&gt;dkpub&lt;/code&gt;/&lt;code&gt;dkpriv&lt;/code&gt;) and Transport key (&lt;code&gt;tkpub&lt;/code&gt;/&lt;code&gt;tkpriv&lt;/code&gt;) [@prt-msft-learn].&lt;/p&gt;

The first of the two key pairs minted at Microsoft Entra registration. The private half (`dkpriv`) is TPM-resident on supported hardware (TPM 2.0 from Windows 10 1903 onward) and signs the JWT used to *request* a Primary Refresh Token from Microsoft Entra ID. The public half (`dkpub`) is registered with Microsoft Entra ID at join time and is what Entra ID uses to verify that the request originated from the registered device [@prt-msft-learn].

The second registration-time key pair. Entra ID encrypts the freshly minted PRT session key under `tkpub`; only `tkpriv` -- TPM-resident on supported hardware -- can unwrap it. Every downstream signing operation flows through a key derived from that session key, so the transport key is the asymmetric on-ramp to the device&apos;s symmetric proof-of-possession surface [@prt-msft-learn].

The Windows component that performs Microsoft Entra registration -- mints the device and transport key pairs, registers `dkpub`/`tkpub` with Entra ID, and produces the device certificate that backs the Microsoft Entra device object. `dsregcmd.exe` is its operator-facing interrogation tool; `dsregcmd /status` reports current state including AzureAdPrt, AzureAdPrtUpdateTime, and AzureAdPrtExpiryTime [@prt-msft-learn].
&lt;p&gt;The two-key model is not a typo, and the second-most-common reading of it is wrong. The device key signs &lt;em&gt;the request for&lt;/em&gt; a PRT. The transport key unwraps &lt;em&gt;the session key that arrives with&lt;/em&gt; a PRT. Once unwrapped, the session key signs everything from there on -- not the device key.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The device key signs PRT issuance, once per PRT mint. The transport key unwraps a &lt;em&gt;session key&lt;/em&gt;. Every downstream artifact -- the &lt;code&gt;x-ms-RefreshTokenCredential&lt;/code&gt; browser cookie, every WAM-mediated app-token request -- is signed by a key &lt;em&gt;derived from&lt;/em&gt; that session key, not by &lt;code&gt;dkpriv&lt;/code&gt; directly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The eight-step issuance flow makes this explicit.&lt;/p&gt;

sequenceDiagram
    participant User
    participant CloudAP as CloudAP (lsass)
    participant TPM
    participant Entra as Microsoft Entra ID
    participant CA as Conditional Access
    participant WAM
    User-&amp;gt;&amp;gt;CloudAP: 1. Interactive sign-in (Hello, password, FIDO2)
    CloudAP-&amp;gt;&amp;gt;TPM: 2. Sign authorization JWT with dkpriv
    TPM--&amp;gt;&amp;gt;CloudAP: 3. Signed assertion
    CloudAP-&amp;gt;&amp;gt;Entra: 4. Issuance request (signed assertion)
    Entra-&amp;gt;&amp;gt;CA: 5. Evaluate device + user + risk claims
    CA--&amp;gt;&amp;gt;Entra: 6. Issuance permitted
    Entra--&amp;gt;&amp;gt;CloudAP: 7. PRT + session_key encrypted under tkpub
    CloudAP-&amp;gt;&amp;gt;TPM: 8. Unwrap session_key with tkpriv
    Note over CloudAP,WAM: Session key now resident -- WAM, browser SSO, and CAE all derive from it
&lt;p&gt;A user provides an interactive credential -- a Hello gesture, a password, a FIDO2 security key. The CloudAP plugin in &lt;code&gt;lsass&lt;/code&gt; constructs a JWT carrying the user&apos;s authorization material and asks the TPM to sign it with &lt;code&gt;dkpriv&lt;/code&gt;. That signed assertion goes to Microsoft Entra ID. Entra evaluates Conditional Access; if the device, the user, and the risk profile pass policy, Entra returns a PRT (a long-lived JWT) and a fresh session key encrypted under &lt;code&gt;tkpub&lt;/code&gt;. The TPM unwraps the session key with &lt;code&gt;tkpriv&lt;/code&gt;. The session key now lives on the device, in CloudAP&apos;s hot path, available for every broker to use.&lt;/p&gt;

The symmetric key Microsoft Entra ID generates per PRT mint and returns to the device encrypted under `tkpub`. After the TPM unwraps it with `tkpriv`, the session key is the *proof-of-possession key* for the PRT lifetime: every renewal request, every `x-ms-RefreshTokenCredential` cookie, and every app-token request signed via the Web Account Manager is HMAC-signed by a key *derived from* the session key via SP800-108 KDF [@prt-msft-learn] [@ms-oapxbc-jwt].
&lt;p&gt;The session key is the part the rest of this article keeps coming back to. It is the artifact that, in 2020, three independent researchers would prove the TPM was not protecting in the way Microsoft&apos;s documentation implied.&lt;/p&gt;
&lt;p&gt;Once the session key is on the device, the &lt;strong&gt;Web Account Manager (WAM)&lt;/strong&gt; -- the user-mode broker process that handles native-app token requests -- and the browser SSO surface used by Edge, Chrome, and Firefox can mint subordinate artifacts. The most interesting one is a cookie.&lt;/p&gt;

The Windows user-mode broker that mediates access-token requests from native applications to Microsoft Entra ID. WAM presents each app-token request alongside a PRT-derived signed assertion, eliminating the per-app refresh-token cache that the pre-2016 ADAL design required. WAM is the Windows analogue of the Microsoft Enterprise SSO plug-in for Apple devices [@prt-msft-learn] [@apple-sso-plugin-learn].

The HTTP cookie Edge, Chrome, and Firefox attach to requests against `login.microsoftonline.com` and a small set of Microsoft cloud surfaces. It carries a JWT signed with `alg: HS256` whose header field `kdf_ver` indicates whether the cookie used KDFv1 or KDFv2 derivation [@ms-oapxbc-jwt]. The cookie is what makes the third sign-in in the §1 hook -- the silent Edge sign-in to `outlook.office.com` -- not require a credential prompt.
&lt;p&gt;Inside that cookie, the signing key is &lt;strong&gt;derived&lt;/strong&gt; from the session key via the SP800-108 key-derivation function. The label is the constant string &lt;code&gt;AzureAD-SecureConversation&lt;/code&gt;. The context (&lt;code&gt;ctx&lt;/code&gt;) is a per-cookie value chosen by the client. The MS-OAPXBC protocol specification gives the rule verbatim: under KDFv2, &quot;the client MUST use SHA256(ctx || assertion payload) instead of ctx as the context for deriving the signing key&quot; [@ms-oapxbc-jwt]. We will come back to that sentence in §6, because it is &lt;em&gt;the&lt;/em&gt; sentence.Microsoft Learn documents TPM 2.0 as the recommended version for all Microsoft Entra device-registration scenarios on Windows 10 or newer, and states that after the Windows 10 1903 update, Microsoft Entra ID no longer uses TPM 1.2 for any of the PRT keys due to reliability issues. In practice, TPM 2.0 is the only supported configuration on Windows 10 1903 or higher [@prt-msft-learn].&lt;/p&gt;
&lt;p&gt;On supported hardware, both &lt;code&gt;dkpriv&lt;/code&gt; and &lt;code&gt;tkpriv&lt;/code&gt; are non-extractable TPM 2.0 keys. On a device with &lt;a href=&quot;https://paragmali.com/blog/pluton-a-tpm-on-silicon-microsoft-can-patch/&quot; rel=&quot;noopener&quot;&gt;Microsoft Pluton&lt;/a&gt; (a TPM 2.0 implementation embedded in the SoC), the same model applies; Pluton is a TPM 2.0 implementation, not a replacement. On non-TPM Windows -- a virtual machine without a vTPM, a desktop where the TPM is disabled, certain consumer SKUs -- DPAPI is the fallback. DPAPI-protected keys live in user-profile state and can be unwrapped with the user&apos;s credentials, which is a meaningfully weaker contract than TPM non-extractability. We will come back to that distinction in §9.&lt;/p&gt;

The shorthand &quot;the PRT cookie is DKey-signed&quot; was already imprecise before July 2021, and it became actively wrong after the KDFv2 update. The cookie is HMAC-signed with `alg: HS256`, using a symmetric key derived from the *session key* via SP800-108 KDF, not signed with the asymmetric device key. blog.3or.de&apos;s reverse-engineering captures the post-2021 mechanic precisely: &quot;Before CVE-2021-33779, the key to sign the PRT Cookie was derived from the session key using a function that only required a client-chosen `ctx` value. Although the session key and derivation process were handled inside the TPM, the derived key was managed outside the TPM&quot; [@dimi-3or-de-kdfv2]. The asymmetric device key only signs the PRT *issuance* request; everything afterwards is HMAC over a derived key.
&lt;p&gt;If both keys live in the TPM and the cookie is signed with a key derived from a TPM-resident session key, the whole architecture &lt;em&gt;should&lt;/em&gt; make Pass-the-PRT impossible. In 2020, three independent researchers proved it didn&apos;t.&lt;/p&gt;
&lt;h2&gt;5. When TPM-binding is not enough&lt;/h2&gt;
&lt;p&gt;In July 2020, two researchers, working independently, asked the same question: if the session key is in the TPM, can I still mint a PRT cookie?&lt;/p&gt;
&lt;p&gt;The answer, on the architecture Microsoft shipped at the time, was yes -- and the answer came from three angles in less than two months.&lt;/p&gt;

A Primary Refresh Token can be compared to a long-term persistent Ticket Granting Ticket (TGT) in Active Directory... the Primary Refresh Token however can be used to authenticate to any application, and is thus even more valuable. This is why Microsoft has applied extra protection to this token. -- Dirk-jan Mollema, 21 July 2020
&lt;p&gt;&lt;strong&gt;Lee Christensen at SpecterOps, mid-July 2020.&lt;/strong&gt; Christensen&apos;s blog post -- &quot;Requesting Azure AD Refresh Tokens on Azure AD-joined Machines for Browser SSO&quot; -- documented a path through a Component Object Model interface, &lt;code&gt;IProofOfPossessionCookieInfoManager.GetCookieInfoForUri&lt;/code&gt;, that returned a fully signed &lt;code&gt;x-ms-RefreshTokenCredential&lt;/code&gt; cookie to a user-mode caller [@christensen-specterops-2020]. The CLSID is &lt;code&gt;{a9927f85-a304-4390-8b23-a75f1c668600}&lt;/code&gt;; the implementation lives in &lt;code&gt;MicrosoftAccountTokenProvider.dll&lt;/code&gt;; the workflow rides through &lt;code&gt;BrowserCore.exe&lt;/code&gt; over a named pipe. Christensen released the proof-of-concept as &lt;code&gt;RequestAADRefreshToken&lt;/code&gt; on GitHub [@gh-requestaadrefreshtoken]. An attacker -- specifically, a process running as the signed-in user -- could call the COM interface, lift the cookie, and paste it into a browser running anywhere on the planet.&lt;/p&gt;
&lt;p&gt;The COM-API path did not require admin. It did not require touching the TPM. It did not need to know anything about the session key. The operating system politely produced a signed cookie because that is what the COM API was built to do, and the contract did not distinguish the legitimate browser from the attacker process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dirk-jan Mollema, 21 July 2020.&lt;/strong&gt; A week later, Mollema published &quot;Abusing Azure AD SSO with the Primary Refresh Token&quot; on &lt;code&gt;dirkjanm.io&lt;/code&gt;. Mollema&apos;s framing was different: he wanted to understand the PRT as a forensic artifact. The blog opens with the TGT analogy quoted above and explicitly attributes parallel discovery to Christensen [@mollema-prt-2020-07]. The toolchain he documented, ROADtoken, lived inside the larger ROADtools framework that he was building for offensive Azure AD research [@gh-roadtools]. The threat model was the same as Christensen&apos;s: an attacker on the live device could mint cookies, and the TPM was not in the way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mollema, 5 August 2020.&lt;/strong&gt; This is the blog that mattered most. In &quot;Digging further into the Primary Refresh Token,&quot; Mollema reverse-engineered &lt;code&gt;aadcloudap.dll&lt;/code&gt;. He isolated the session-key handling, the cookie-construction routine, the SP800-108 derivation call, the eventual &lt;code&gt;BCryptKeyDerivation&lt;/code&gt;-then-HMAC flow. And he wrote the sentence that, in retrospect, defined the next year of Microsoft&apos;s response: &quot;despite the session key of the PRT is stored in the TPM whenever possible, this doesn&apos;t prevent us from extracting the PRT and the required information to create SSO cookies. The result of this is that regardless of whether the PRT is protected by the TPM or not, with Administrator access it is possible to extract the PRT from LSASS and use the PRT on a different device than it was issued to&quot; [@mollema-prt-2020-08].&lt;/p&gt;

despite the session key of the PRT is stored in the TPM whenever possible, this doesn&apos;t prevent us from extracting the PRT and the required information to create SSO cookies. -- Dirk-jan Mollema, 5 August 2020
&lt;p&gt;The reason is the most important thing in this article. The session key never left the TPM. But the &lt;em&gt;signing key derived from the session key&lt;/em&gt; did. The TPM dutifully performed an SP800-108 derivation -- HMAC-SHA256 with the label &lt;code&gt;AzureAD-SecureConversation&lt;/code&gt; and the client-chosen &lt;code&gt;ctx&lt;/code&gt; value -- and returned the derived key to caller memory. The TPM was protecting the root of the derivation, not the output of it. Once the derived key materialized in &lt;code&gt;lsass&lt;/code&gt;, an admin-with-debug-privilege attacker could simply read it.&lt;/p&gt;
&lt;p&gt;Around the same time, Benjamin Delpy -- the author of Mimikatz -- picked up Mollema&apos;s &quot;challenge&quot; of recovering PRT data from &lt;code&gt;lsass&lt;/code&gt;. Two days after Mollema&apos;s 5 August post, that collaboration produced the Mimikatz release tagged &lt;code&gt;2.2.0-20200807&lt;/code&gt;, which added the &lt;code&gt;sekurlsa::cloudap&lt;/code&gt; and &lt;code&gt;dpapi::cloudapkd&lt;/code&gt; modules [@gh-mimikatz]. The tag URL itself was later collapsed in GitHub&apos;s modern UI -- it returns 404 today, almost certainly because of repeated takedown requests during the Azure-PRT release period -- but a Wayback Machine snapshot from 20 September 2020 preserves the release page and proves the tag existed at the time [@wayback-mimikatz-tag].The GitHub URL &lt;code&gt;https://github.com/gentilkiwi/mimikatz/releases/tag/2.2.0-20200807&lt;/code&gt; returns HTTP 404 in the current GitHub UI; the modern releases list starts at &lt;code&gt;2.2.0-20210729&lt;/code&gt;. The Wayback snapshot at &lt;code&gt;web.archive.org/web/20200920005113/...&lt;/code&gt; preserves the release page (including the &quot;prt3&quot; animated demonstration GIF). Nestori Syynimaa&apos;s AADInternals post and Mollema&apos;s 5 August 2020 blog both reference the same tag URL, which is how we know the artifact was real [@wayback-mimikatz-tag] [@syynimaa-aadinternals-prt] [@mollema-prt-2020-08].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nestori Syynimaa and AADInternals, August through September 2020.&lt;/strong&gt; Syynimaa&apos;s AADInternals PowerShell module shipped &lt;code&gt;Get-AADIntUserPRTToken&lt;/code&gt; as part of v0.4.1 alongside the disclosure. On 29 September 2020, AADInternals&apos; blog post about the tool gained an inline update: &quot;It seems that PRT tokens must now include the &lt;code&gt;request_nonce&lt;/code&gt;. If not, Azure AD sends a redirect with &lt;code&gt;sso_nonce&lt;/code&gt; which must be added to the PRT token. This means that without access to session key, PRT tokens can&apos;t be used anymore&quot; [@syynimaa-aadinternals-prt]. That update is the first observable Microsoft mitigation: Entra ID began demanding that PRT cookies contain a server-issued nonce. It bought time. It did not solve the architectural problem.&lt;/p&gt;

sequenceDiagram
    participant Attacker
    participant LSASS
    participant TPM
    participant COM as IProofOfPossessionCookieInfoManager
    participant Entra as Microsoft Entra ID
    Note over Attacker,LSASS: Attacker has user or admin on the live device
    Attacker-&amp;gt;&amp;gt;LSASS: sekurlsa::cloudap (admin path)
    LSASS--&amp;gt;&amp;gt;Attacker: PRT + derived signing key + context
    Note over Attacker: Or, parallel user-only path:
    Attacker-&amp;gt;&amp;gt;COM: GetCookieInfoForUri(target_url)
    COM--&amp;gt;&amp;gt;Attacker: Pre-baked x-ms-RefreshTokenCredential
    Note over Attacker: Cookie is now portable
    Attacker-&amp;gt;&amp;gt;Entra: Replay cookie from an attacker-controlled host
    Entra--&amp;gt;&amp;gt;Attacker: SSO honored, access token issued
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; With admin on an Entra-joined device in summer 2020, an attacker could lift the PRT and the derived signing key from &lt;code&gt;lsass&lt;/code&gt;, mint fresh &lt;code&gt;x-ms-RefreshTokenCredential&lt;/code&gt; cookies on any host they controlled, and pass Conditional Access checks that included the cloned &lt;code&gt;DeviceId&lt;/code&gt; claim. Even without admin, the COM-API path returned signed cookies to a user-context process. The TPM was busy doing exactly what its contract said, and that contract was insufficient.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The community quickly settled on a name for this class: &lt;strong&gt;Pass-the-PRT&lt;/strong&gt;. By analogy to Pass-the-Hash and Pass-the-Ticket, the attack is &quot;lift a long-lived authentication artifact from one host, present it as your own elsewhere.&quot; For a credential that the entire cloud sign-in stack was about to trust, the implications were severe.&lt;/p&gt;
&lt;p&gt;By September 2020 Microsoft had bolted a nonce onto the cookie. By July 2021 they had something architecturally different: a single SHA-256 over the cookie&apos;s full payload that killed off-device Pass-the-PRT for good.&lt;/p&gt;
&lt;h2&gt;6. KDFv2 and the death of off-device Pass-the-PRT&lt;/h2&gt;
&lt;p&gt;The fix Microsoft shipped on 13 July 2021 fits on one line.&lt;/p&gt;
&lt;p&gt;The CVE is &lt;strong&gt;CVE-2021-33779&lt;/strong&gt;. NIST&apos;s National Vulnerability Database describes it as &quot;Windows AD FS Security Feature Bypass Vulnerability&quot; and provides no further public detail [@nvd-cve-2021-33779]. Microsoft&apos;s own KDFv2 documentation ties the patch explicitly to that CVE: &quot;On July 13, 2021, updates were released for AD FS to address token replay attacks, as described in CVE-2021-33779. These updates introduce new settings to enable and control a new, Key Derivation Function (KDF) called KDFv2&quot; [@kdfv2-learn].&lt;/p&gt;

The version-2 key-derivation rule introduced for the `x-ms-RefreshTokenCredential` cookie on 13 July 2021. Under KDFv2, the SP800-108 KDF context is `SHA256(ctx || assertion_payload)` rather than the bare client-chosen `ctx` value. The JWT header field `kdf_ver` carries the value `2` to indicate that KDFv2 was used. KDFv1 is preserved for backward compatibility but is disabled by default on a service that has been moved to &quot;Enforced&quot; mode [@ms-oapxbc-jwt] [@kdfv2-learn].
&lt;p&gt;A small subtlety lives in the attribution. NVD names AD FS. The community-side coverage -- blog.3or.de, Mollema&apos;s TROOPERS 22 deck, AADInternals -- names PRT-cookie forgery. The Microsoft KDFv2 page sits in the middle: it ties the patch to CVE-2021-33779 and walks through the same derivation change that closed off-device Pass-the-PRT, but it does not use the term &quot;Pass-the-PRT&quot; on the page itself. We will keep the hedge in mind.&lt;/p&gt;

NVD&apos;s one-line description -- &quot;Windows AD FS Security Feature Bypass Vulnerability&quot; -- is authoritative for the federal CVE record [@nvd-cve-2021-33779]. The community attribution to the Pass-the-PRT class comes from independent reverse-engineering: blog.3or.de&apos;s analysis is the most precise public reading. Both can be true; KDFv2 is the rollout vehicle, and it ships into both AD FS (the on-prem federation server) and the Microsoft Entra ID PRT path. The article reads CVE-2021-33779 as &quot;the rollout vehicle for KDFv2,&quot; not as a one-to-one CVE-to-attack mapping.
&lt;p&gt;The load-bearing rule is one sentence. MS-OAPXBC §3.2.5 puts it like this: &quot;If the client chooses to use KDFv2, the client MUST use &lt;code&gt;SHA256(ctx || assertion payload)&lt;/code&gt; instead of &lt;code&gt;ctx&lt;/code&gt; as the context for deriving the signing key. The client MUST also add the JWT header field &lt;code&gt;kdf_ver&lt;/code&gt; with value set to 2 to communicate that KDFv2 was used for creating the derived signing key&quot; [@ms-oapxbc-jwt].&lt;/p&gt;
&lt;p&gt;To see why that line matters, picture what the attacker in §5 was actually copying. The attacker lifted the derived signing key out of &lt;code&gt;lsass&lt;/code&gt;. The derived signing key was, under KDFv1, a function of the session key (TPM-resident) and the client-chosen context &lt;code&gt;ctx&lt;/code&gt; (any 256 bits the attacker liked). Any cookie the attacker built using the same &lt;code&gt;ctx&lt;/code&gt; would verify against the same derived key. The attacker could pick &lt;code&gt;ctx&lt;/code&gt; first, derive the key once, and stamp out as many cookies as they wanted.&lt;/p&gt;
&lt;p&gt;Under KDFv2, the context is no longer arbitrary. The context is &lt;code&gt;SHA256(ctx || assertion_payload)&lt;/code&gt;. The &lt;code&gt;assertion_payload&lt;/code&gt; is the JWT body the cookie is trying to assert. Change a single claim in the body, and the SHA-256 hash changes, and the SP800-108 derivation produces a different key. A key derived for one cookie cannot sign any other cookie. There is nothing to precompute.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The architectural insight is the same one Kerberos learned with PA-FX-FAST and TLS learned with channel binding: a session-key derivation must be bound to the message being signed, not just to a per-session label. Before KDFv2, the derivation contract was &quot;derive a key for this session, then sign anything.&quot; After KDFv2, the contract is &quot;derive a key for this specific message.&quot; An attacker who exfiltrates the session key off-device cannot precompute a useful signing key; an attacker who exfiltrates a derived signing key for one cookie cannot reuse it for the next. Off-device Pass-the-PRT is dead.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The residual is also explicit. The attacker who is still &lt;em&gt;on the device&lt;/em&gt; -- still has a process running as the user or as &lt;code&gt;SYSTEM&lt;/code&gt; -- can ask CloudAP to mint a fresh cookie. The TPM happily performs the new SHA-256-bound derivation, because that is its job; CloudAP returns the signed cookie to the calling process, because that is its job. The blog.3or.de reverse-engineering names this class precisely: &quot;This attack, referred to as Pass-the-PRT-Cookie, still works today but requires presence on the targeted device&quot; [@dimi-3or-de-kdfv2]. Mollema&apos;s TROOPERS 22 talk calls the same residual &quot;Cookie-on-Demand&quot; and walks the in-place cookie-minting flow on a fully patched Entra-joined endpoint [@troopers22-mollema-pdf] [@troopers22-abstract].&lt;/p&gt;
&lt;p&gt;The minimal cryptographic statement of the fix is small enough to write down. Let $H$ be HMAC-SHA256, $k_s$ be the session key, $\ell$ be the constant label &lt;code&gt;AzureAD-SecureConversation&lt;/code&gt;, $\mathit{ctx}$ be the per-cookie context, and $p$ be the JWT body to be signed. Under KDFv1, the derived signing key was $k_d = H(k_s, \ell \parallel \mathit{ctx})$. Under KDFv2, the derived signing key is $k_d = H(k_s, \ell \parallel \mathrm{SHA256}(\mathit{ctx} \parallel p))$. The difference is exactly the hash of the message body inside the derivation context.&lt;/p&gt;
&lt;p&gt;{`
// Illustrative; do NOT use as production crypto.
const crypto = require(&apos;crypto&apos;);&lt;/p&gt;
&lt;p&gt;function sha256(buf) { return crypto.createHash(&apos;sha256&apos;).update(buf).digest(); }
function hmac(key, data) { return crypto.createHmac(&apos;sha256&apos;, key).update(data).digest(); }&lt;/p&gt;
&lt;p&gt;function deriveKdfv2SigningKey(sessionKey, ctx, assertionPayload) {
  const label = Buffer.from(&apos;AzureAD-SecureConversation&apos;, &apos;utf8&apos;);
  const boundCtx = sha256(Buffer.concat([ctx, assertionPayload]));
  // SP800-108 KDF in counter mode is more involved; one HMAC stands in here.
  return hmac(sessionKey, Buffer.concat([label, boundCtx]));
}&lt;/p&gt;
&lt;p&gt;// The signing key is now uniquely tied to assertionPayload.
`}&lt;/p&gt;
&lt;p&gt;A side-by-side flowchart makes the structural shift legible.&lt;/p&gt;

flowchart LR
    subgraph KDFv1 [&quot;KDFv1 (pre-July 2021)&quot;]
        A1[Session key in TPM] --&amp;gt; A2[&quot;SP800-108 KDF&lt;br /&gt;label = AzureAD-SecureConversation&lt;br /&gt;context = ctx&quot;]
        A2 --&amp;gt; A3[Derived signing key]
        A3 --&amp;gt; A4[HMAC over any JWT body]
    end
    subgraph KDFv2 [&quot;KDFv2 (July 2021+)&quot;]
        B1[Session key in TPM] --&amp;gt; B2[&quot;SP800-108 KDF&lt;br /&gt;label = AzureAD-SecureConversation&lt;br /&gt;context = SHA256 of ctx || payload&quot;]
        B2 --&amp;gt; B3[Derived signing key]
        B3 --&amp;gt; B4[HMAC over the specific JWT body]
    end
&lt;p&gt;KDFv2 killed off-device replay. It did not kill the on-device signing oracle, and it did not shorten the PRT&apos;s 90-day lifetime. The next generation tackled both -- not by closing the on-device gap, which is architecturally hard, but by making issued access tokens revocable in seconds.&lt;/p&gt;
&lt;h2&gt;7. The seam: CAE, Token Protection, Cloud Kerberos Trust&lt;/h2&gt;
&lt;p&gt;By 2022 the PRT was &lt;em&gt;the&lt;/em&gt; credential. The work that remained was to make every artifact issued &lt;em&gt;from&lt;/em&gt; it -- every access token, every Kerberos TGT, every Conditional Access claim -- share the same device-binding contract.&lt;/p&gt;
&lt;p&gt;That work has three named pieces, and a quiet rename in the middle.&lt;/p&gt;
&lt;h3&gt;Continuous Access Evaluation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Continuous Access Evaluation&lt;/strong&gt; entered public preview in late 2020, a few months after Mollema&apos;s August blog. By 10 January 2022, Microsoft announced General Availability across Microsoft Entra ID; the announcement post came from Alex Simons, Corporate Vice President for Program Management in the Microsoft Identity Division [@twu-cae-ga-mirror]. CAE is the mechanism by which a &lt;em&gt;long-lived&lt;/em&gt; access token issued from a PRT can be invalidated in seconds when something critical changes.&lt;/p&gt;

An industry-standard near-real-time revocation channel for OAuth access tokens, implemented by Microsoft Entra ID as a claim-challenge protocol between Entra and CAE-aware resource providers. CAE is anchored in the OpenID Continuous Access Evaluation Profile (CAEP) [@caep-openid-spec]. CAE-aware resources reject a previously valid access token when Entra signals one of five critical events: user account deletion or disablement, password change, MFA enablement, admin token revocation, or high user-risk classification. Microsoft Learn documents an event-propagation upper bound of 15 minutes, with IP-location enforcement instantaneous [@cae-learn].
&lt;p&gt;Mechanically: a CAE-aware client requests an access token from Entra ID, and Entra issues a &lt;em&gt;long-lived&lt;/em&gt; token -- up to 28 hours rather than the conventional one hour -- with a &lt;code&gt;xms_cc&lt;/code&gt; claim signaling that the bearer understands the protocol. The resource provider serves requests against that token. When something changes -- the user gets disabled in HR, the IT admin resets the password, a sign-in trips a high-risk classification -- Entra ID fires a CAEP event. The resource provider receives the event and, on the next request, returns an HTTP 401 with a &lt;code&gt;WWW-Authenticate&lt;/code&gt; claim challenge. The client returns to Entra, presents the PRT, and asks for a fresh access token; Entra evaluates Conditional Access at that moment and either issues a new token or refuses. The user sees, at worst, a fast re-authentication; the access window for the revoked credential is on the order of seconds rather than the access token&apos;s original lifetime.&lt;/p&gt;

sequenceDiagram
    participant Admin
    participant Entra as Microsoft Entra ID
    participant Resource as Exchange Online
    participant Client
    Admin-&amp;gt;&amp;gt;Entra: Force password reset for user
    Entra--&amp;gt;&amp;gt;Resource: CAEP event: Credential Change
    Client-&amp;gt;&amp;gt;Resource: GET /mail (with long-lived token)
    Resource--&amp;gt;&amp;gt;Client: 401 WWW-Authenticate (claim challenge)
    Client-&amp;gt;&amp;gt;Entra: Refresh token + claim challenge
    Note over Entra: Re-evaluate Conditional Access against current user state
    Entra--&amp;gt;&amp;gt;Client: New short access token (or deny)
    Client-&amp;gt;&amp;gt;Resource: GET /mail (new token)
    Resource--&amp;gt;&amp;gt;Client: 200 OK
&lt;p&gt;The initial CAE deployment was constrained: only Exchange Online, SharePoint Online, and Teams understood the claim-challenge protocol at GA [@cae-learn]. Microsoft Graph followed. Other workloads still honor an access token until natural expiry, which is the open scope of the §9 caveat list.&lt;/p&gt;
&lt;h3&gt;Token Protection&lt;/h3&gt;
&lt;p&gt;If CAE is the &lt;em&gt;time&lt;/em&gt; dimension, &lt;strong&gt;Token Protection&lt;/strong&gt; is the &lt;em&gt;space&lt;/em&gt; dimension. The Conditional Access feature, also referred to as &quot;token binding,&quot; demands that an app-token request originate from a device-bound session token -- in practice, a PRT-signed assertion. The Microsoft Learn page defines it as a &quot;Conditional Access session control that attempts to reduce token replay attacks by ensuring only device bound sign-in session tokens, like Primary Refresh Tokens (PRTs), are accepted by Microsoft Entra ID when applications request access to protected resources&quot; [@token-protection-learn].&lt;/p&gt;

A Microsoft Entra Conditional Access session control that enforces device-bound sign-in for app-token requests against supported resources. Token Protection is the per-app analogue of the PRT&apos;s device-binding contract: every access token must originate from a device-bound session token. As of 2026, Token Protection is generally available on Windows for Exchange Online, SharePoint Online, Teams, Azure Virtual Desktop, and Windows 365; it is in preview on iOS/iPadOS and macOS via the Microsoft Enterprise SSO plug-in [@token-protection-learn] [@apple-sso-plugin-learn].
&lt;p&gt;The current scope is intentionally narrow. Native applications and the Microsoft Enterprise SSO plug-in for Apple devices both implement the device-bound assertion. Browsers do not. A browser visiting a Microsoft cloud resource still rides the &lt;code&gt;x-ms-RefreshTokenCredential&lt;/code&gt; cookie path. Closing that gap is what Device Bound Session Credentials -- the cross-vendor web standard Microsoft co-designed with Google -- exists to do, and we will return to that in §10.&lt;/p&gt;
&lt;h3&gt;Cloud Kerberos Trust&lt;/h3&gt;
&lt;p&gt;The third piece bridges the cloud-mediated PRT path back to on-prem Kerberos. The mechanism is simple in framing and intricate in implementation: Microsoft Entra ID provisions a virtual &lt;code&gt;AzureADKerberos&lt;/code&gt; read-only domain controller object inside the on-prem Active Directory domain, and an Entra-signed partial Kerberos TGT issued to a Hello-for-Business-signed-in device can be exchanged at any on-prem DC for a fully-formed TGT carrying SID and authorization data.&lt;/p&gt;

A Microsoft Entra ID mechanism by which Entra ID can mint Kerberos TGTs for one or more Active Directory domains. An Entra-signed partial TGT carries the user&apos;s identity; an on-prem domain controller, holding the cryptographic shared key represented by the virtual `AzureADKerberos` RODC computer object, completes the TGT with on-prem SID and group claims. The bridge requires Windows 10 21H2 (with KB5010415+) or later, and a Windows Server 2016+ functional level on the domain controller; it shipped in April-June 2022 [@cloud-kerberos-trust-learn] [@entra-passwordless-onprem].
&lt;p&gt;The Microsoft Learn deployment guide is explicit about the AzureADKerberos object&apos;s role: &quot;When Microsoft Entra Kerberos is enabled in an Active Directory domain, an AzureADKerberos computer object is created in the domain. This object: Appears as a read only domain controller (RODC) object, but isn&apos;t associated with any physical servers; Is only used by Microsoft Entra ID to generate TGTs for the Active Directory domain&quot; [@cloud-kerberos-trust-learn]. The architectural property to notice is that the user&apos;s NTLM hash is &lt;em&gt;not&lt;/em&gt; the binding key. Microsoft Entra ID never holds the on-prem NTLM hash; the cryptographic root is the AzureADKerberos RODC&apos;s keys, which Entra and the on-prem domain controller share without involving any user-side long-term secret.&lt;/p&gt;
&lt;p&gt;Cloud Kerberos Trust is the Kerberos PKINIT pattern from RFC 4556 [@rfc-4556-pkinit], reframed: the cloud identity provider is the public-key initial authenticator, and Entra ID issues the partial TGT exactly as a PKINIT-aware KDC would.&lt;/p&gt;
&lt;h3&gt;The Azure AD to Microsoft Entra ID rename&lt;/h3&gt;
&lt;p&gt;In the middle of all this, on 11 July 2023, the brand changed. Microsoft renamed Azure Active Directory to Microsoft Entra ID and consolidated several adjacent products under the Microsoft Entra umbrella [@entra-rename-2023]. The article uses &quot;Microsoft Entra ID&quot; throughout; in primary sources from before July 2023, the same product is &quot;Azure AD.&quot; The rename is real, and it matters when citing older documentation, but it does not change the protocol surface.&lt;/p&gt;
&lt;h3&gt;The seam restated&lt;/h3&gt;
&lt;p&gt;With Continuous Access Evaluation, Token Protection, and Cloud Kerberos Trust in place, the picture from §1 fills out. Every cloud-mediated identity feature on a modern Windows endpoint either issues, refreshes, presents, or evaluates a PRT. The PRT itself is the asymmetric handshake that binds the device. CAE makes the time dimension elastic. Token Protection makes the access surface device-bound at the resource-request layer. Cloud Kerberos Trust makes the on-prem Kerberos surface reachable from a PRT-bearing device.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The PRT is the cryptographic seam: a single device-bound credential, issued at first sign-in, that every other identity artifact on the device references. CAE, Token Protection, and Cloud Kerberos Trust are not three different bindings; they are three different ways the same PRT contract reaches three different surfaces -- the revocation surface, the per-resource access-token surface, and the on-prem Kerberos surface.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A small comparison matrix makes the support story explicit.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource / scenario&lt;/th&gt;
&lt;th&gt;CAE-aware&lt;/th&gt;
&lt;th&gt;Token Protection (Windows GA)&lt;/th&gt;
&lt;th&gt;Cloud Kerberos Trust&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Exchange Online&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SharePoint Online&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft Teams&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft Graph&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Not enforced&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Virtual Desktop&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 365&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On-prem file share&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser (any Microsoft cloud)&lt;/td&gt;
&lt;td&gt;Indirect via resource&lt;/td&gt;
&lt;td&gt;No (native apps only)&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;That is what the PRT does. But four sibling articles in this series describe identity surfaces the PRT does &lt;em&gt;not&lt;/em&gt; cover. Before we celebrate the seam, we have to be honest about where it stops.&lt;/p&gt;
&lt;h2&gt;8. Where PRT is not the answer&lt;/h2&gt;
&lt;p&gt;The PRT carries device state, MFA state, and Conditional Access claims for the &lt;em&gt;cloud-mediated&lt;/em&gt; identity path. There is no clause in that sentence that mentions on-prem Kerberos, NTLM hashes, local admin authorization, or workload identities -- and that is the point.&lt;/p&gt;
&lt;p&gt;Five surfaces the PRT does not cover, in the order operators most often confuse them:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On-prem Kerberos via the on-prem KDC.&lt;/strong&gt; A Windows user signing into a domain-joined or hybrid-joined machine still mints a Kerberos TGT against the on-prem Key Distribution Center on Windows logon. The PRT path is parallel, not replacement. The user&apos;s downstream &lt;code&gt;kerberos.dll&lt;/code&gt; ticket cache is populated by Kerberos AS_REQ/AS_REP exchanges between the workstation and the on-prem DC; the PRT lives in CloudAP&apos;s memory in &lt;code&gt;lsass&lt;/code&gt; and does not influence that flow. Cloud Kerberos Trust adds a bridge from PRT to on-prem TGT for users whose primary credential is in Entra; it does not retire the on-prem Kerberos path.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Credential Guard and LSAISO.&lt;/strong&gt; &lt;a href=&quot;https://paragmali.com/blog/the-empty-hash-credential-guard-the-lsaiso-trustlet-and-the-/&quot; rel=&quot;noopener&quot;&gt;Credential Guard&lt;/a&gt;, introduced on the Enterprise SKU of the original Windows 10 release in 2015, isolates NTLM hashes and Kerberos long-term keys inside the Local Security Authority Isolated Subsystem (LSAISO), which runs in Virtual Trust Level 1 (VTL1) on top of the Hyper-V hypervisor [@credential-guard-learn] [@credential-guard-itpro-2016-wayback]. Credential Guard predates the cloud-identity model entirely; its threat model is &lt;em&gt;on-prem credential theft via long-term-key extraction from &lt;code&gt;lsass&lt;/code&gt;.&lt;/em&gt; The load-bearing distinction for the threat model is this: &lt;strong&gt;PRT material does NOT live in LSAISO&lt;/strong&gt;. It lives in normal &lt;code&gt;lsass.exe&lt;/code&gt; under CloudAP. Mollema&apos;s August 2020 extraction worked because the PRT&apos;s session-key handling is in the same address space as ordinary user processes that hold debug privilege; LSAISO did not move there. Treat &quot;I have Credential Guard enabled&quot; and &quot;my PRT is hardware-isolated&quot; as independent statements.The LSAISO isolation contract is for on-prem credentials -- NTLM hashes, Kerberos &lt;code&gt;krbtgt&lt;/code&gt; keys, the kinds of long-term secrets that the 2010s-era &quot;Pass-the-Hash&quot; tooling was designed to extract. The PRT&apos;s session key is a per-PRT artifact that lives in CloudAP&apos;s memory under normal LSASS. Credential Guard protects you against a different attack class. Get it for those reasons; do not get it expecting PRT-class mitigation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adminless and local-admin removal.&lt;/strong&gt; &quot;&lt;a href=&quot;https://paragmali.com/blog/adminless-how-windows-finally-made-elevation-a-security-boun/&quot; rel=&quot;noopener&quot;&gt;Adminless&lt;/a&gt;&quot; is an authorization pattern -- removing standing local-admin rights, requiring just-in-time elevation -- not an authentication pattern. It is orthogonal to the PRT. A device can be PRT-bound and still have a thousand local admins; a device can have zero local admins and still mint PRTs. The PRT addresses &quot;who is signing in;&quot; Adminless addresses &quot;what they can do once signed in.&quot; Conflating them is a common rhetorical move in Microsoft documentation and a common source of confusion in audits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://paragmali.com/blog/windows-app-identity-33-year-reinvention/&quot; rel=&quot;noopener&quot;&gt;App Identity&lt;/a&gt;, managed identities, and workload identities.&lt;/strong&gt; Workloads in Microsoft cloud environments authenticate through a separate broker path: the Azure Instance Metadata Service (IMDS) on VMs, Workload Identity Federation for cross-cloud Kubernetes flows, managed identities on Functions and App Service. None of these always involve a PRT. A managed identity is a non-human principal in Entra ID with a system-issued credential, not a device-bound JWT, and the broker path that produces its access tokens is structurally different. The App Identity sibling article addresses that surface in detail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Remote Credential Guard versus Azure AD RDP sign-in.&lt;/strong&gt; These two are often introduced together because both involve credentials over RDP, and conflating them is the load-bearing threat-model error in this section. &lt;strong&gt;Remote Credential Guard&lt;/strong&gt; redirects Kerberos credentials over the RDP hop: the client&apos;s TGT is reachable to the remote &lt;code&gt;mstsc&lt;/code&gt; session via a CredSSP-mediated redirection mechanism, so that the remote session can fetch downstream service tickets without re-prompting. It does &lt;em&gt;not&lt;/em&gt; transport PRT material across the connection. &lt;strong&gt;Azure AD RDP sign-in&lt;/strong&gt; -- the separate scenario where the RDP host itself is Entra-joined and accepts an Entra sign-in at session establishment -- is the PRT-mediated path, and it happens at the &lt;em&gt;host&lt;/em&gt; side, not as a redirection from the client.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If your threat model says &quot;I am redirecting credentials over RDP, therefore my PRT is exposed,&quot; you are reading the Remote Credential Guard documentation wrong. Remote Credential Guard ferries Kerberos tickets between the client &lt;code&gt;mstsc&lt;/code&gt; and the remote session host; the PRT lives in the client&apos;s LSASS and does not cross the RDP wire under that feature. Azure AD RDP sign-in is the separate, host-side scenario where the remote session establishes its own PRT against Entra. The Stage 0a audit flagged this conflation as one of the most common errors in the wild, and the Microsoft Learn pages are not co-located.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The pattern across all five is the same. PRT is the cloud-mediated authentication path. Kerberos is the on-prem authentication path. Credential Guard is the on-prem long-term-credential isolation path. Adminless is the local-authorization pattern. App Identity is the workload-authentication path. Remote Credential Guard is an on-prem credential redirection over RDP. They run alongside each other on a modern Windows endpoint; they answer different questions. Mistaking the PRT for any of them is how good threat models go sideways.&lt;/p&gt;
&lt;h2&gt;9. Theoretical limits&lt;/h2&gt;
&lt;p&gt;The single most important sentence in the W3C Device Bound Session Credentials draft is also the single most important sentence about the PRT -- and it does not mention the PRT at all.&lt;/p&gt;

DBSC will not prevent temporary access to the browser session while the attacker is resident on the user&apos;s device. The private key should be stored as safely as modern operating systems allow, preventing exfiltration of the session private key, but the signing capability will likely still be available for any program running as the user on the user&apos;s device. -- W3C Web Application Security Working Group, Device Bound Session Credentials draft
&lt;p&gt;That paragraph is the architectural lower bound. Every device-bound session credential ever proposed inherits it. The PRT is no exception. Five bounded promises follow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. The on-device-attacker floor is architectural.&lt;/strong&gt; A hardware-bound key whose &lt;em&gt;signing surface&lt;/em&gt; is reachable by a same-privilege process can be used by that process for the lifetime of its presence. The TPM holds the key; the operating system mediates the signing operation; any process the operating system trusts to talk to CloudAP can ask for a signature. KDFv2 closed &lt;em&gt;off-device&lt;/em&gt; replay because the signing key is now uniquely bound to one cookie -- but the on-device process can simply ask for the next signature. The DBSC working draft is explicit that this is the floor for the entire class [@dbsc-w3c-draft]. The composition argument we will name in §10 is the practical response.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Non-TPM Windows reopens the pre-2021 attack class.&lt;/strong&gt; When the device key and transport key are protected by DPAPI rather than by a TPM 2.0, the key material can be unwrapped with the user&apos;s profile credentials. Pre-2021 Pass-the-PRT becomes available again because the attacker is no longer trying to extract a derived signing key from &lt;code&gt;lsass&lt;/code&gt; -- they are extracting the &lt;em&gt;root&lt;/em&gt; of the derivation from disk. Microsoft Learn names &quot;TPM 2.0 on Windows 10 1903 or higher&quot; as the supported configuration; everything else is best-effort [@prt-msft-learn]. TPM 2.0 is load-bearing, not optional, for the security claims this article makes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Phishing-resistance inheritance is one-shot.&lt;/strong&gt; The PRT records the authentication strength of the &lt;em&gt;issuing&lt;/em&gt; credential -- whether the user signed in with Hello for Business, a FIDO2 key, a password, or a password plus an MFA factor. The &lt;code&gt;mfa&lt;/code&gt; claim on the PRT carries this through to downstream tokens. If the user authenticated with a phishable factor at issuance, every downstream access token transitively trusts that weaker factor for the PRT lifetime. The PRT does &lt;em&gt;not&lt;/em&gt; upgrade. To enforce phishing-resistant authentication, the deployer must configure Conditional Access Authentication Strengths at the Entra ID side -- the PRT will record what arrived, but it will not refuse to mint downstream tokens because the issuing factor was weak.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. CAE coverage is not universal.&lt;/strong&gt; Continuous Access Evaluation is the time dimension of revocation -- but only for CAE-aware resources. Exchange Online, SharePoint Online, Teams, and Microsoft Graph honor the claim-challenge protocol; many other workloads still treat the access token as valid until its native expiry [@cae-learn]. If your tenant&apos;s risk surface is a CAE-unaware first- or third-party application, the deployment-time guarantee is the access token&apos;s natural lifetime, not 15 minutes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. The PRT lifetime is 90 days by design.&lt;/strong&gt; A device offline for more than the PRT lifetime cannot silently refresh; the user will see a re-authentication prompt the next time the device reaches Entra ID. That window is the Conditional Access trade-off: longer windows reduce friction for travelers and offline scenarios; shorter windows reduce the attacker&apos;s window after a device compromise. Microsoft chose 90 days; the deployer can tune it via Conditional Access Sign-In Frequency policies but cannot move it independently of the broader refresh-token configuration.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To approximate the ideal -- a device-bound, near-real-time-revocable, phishing-resistant cross-app SSO credential -- a deployer composes: &lt;strong&gt;PRT&lt;/strong&gt; (device binding) + &lt;strong&gt;CAE&lt;/strong&gt; (near-real-time revocation) + &lt;strong&gt;Token Protection&lt;/strong&gt; (per-resource device binding for native apps) + &lt;strong&gt;Authentication Strengths&lt;/strong&gt; (Conditional Access policy that upgrades phishing resistance at issuance) + &lt;strong&gt;DBSC&lt;/strong&gt; (per-origin web defense once it is available). No single artifact closes all five gaps; composition is the deployer&apos;s job, and the gaps in any one artifact are the joints another is supposed to cover.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Four of the five limits are bounded -- TPM rollout, claim-strength policy, CAE rollout, offline cadence. They get smaller as Microsoft ships, as administrators tighten policy, as more resources become CAE-aware. One is architectural and applies to every device-bound session credential ever proposed: same-device admin equals access while the admin has it. That is the open problem the next section traces.&lt;/p&gt;
&lt;h2&gt;10. Open problems&lt;/h2&gt;
&lt;p&gt;Five open problems sit on the PRT model right now. None of them have a &quot;just ship a patch&quot; answer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cookie-on-Demand on the live device.&lt;/strong&gt; The architectural defense is bounded by the §9 floor. Mollema&apos;s TROOPERS 22 talk makes the case that &lt;strong&gt;trustlet-level isolation&lt;/strong&gt; of the PRT signing path -- moving the CloudAP cookie-construction code from normal &lt;code&gt;lsass&lt;/code&gt; into an isolated user-mode environment in VTL1, the same security boundary that protects LSAISO -- would close the residual class [@troopers22-mollema-pdf]. Microsoft has not shipped that move. The cost is non-trivial: every downstream broker (WAM, the browser SSO surface, every native app that talks to CloudAP) would need to route through a trustlet-mediated signing API, and the trustlet itself would need to make policy decisions about which callers are entitled to a cookie. The benefit is real -- it removes the same-user-attacker class for the most powerful credential on the device -- but the engineering cost has not been deemed worth it as of 2026.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-vendor near-real-time revocation.&lt;/strong&gt; CAE works inside the Microsoft Entra perimeter. If a user is compromised at Entra and Microsoft revokes the session, the signal does not automatically propagate to Okta-protected resources, Google Workspace, AWS IAM Identity Center, or any other identity provider the same user happens to have a session against. The standardization vehicle exists: the OpenID Shared Signals Framework defines a cross-IdP event-receiver protocol, and the OpenID CAEP specification provides the event taxonomy [@caep-openid-spec]. The bilateral transmit/receive deployments are sparse. Stage 3 of the research pipeline found no public production cross-vendor CAE deployment that wires Entra revocation events into a non-Microsoft IdP. The standard is ready; the deployments are not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DBSC and PRT composition for browser SSO.&lt;/strong&gt; Google&apos;s Device Bound Session Credentials began general availability for Chrome 146 on Windows in late 2025, with Microsoft co-designing the standard through the W3C process [@dbsc-google-blog] [@dbsc-w3c-draft]. The Chrome developer documentation references Chrome 145 as the rollout-start build, and the Google security blog references Chrome 146 as the GA build; the version drift reflects a phased rollout, and the article uses the later figure [@dbsc-chrome-developer]. The composition question is unresolved: when a browser on Windows visits &lt;code&gt;login.microsoftonline.com&lt;/code&gt;, the request will carry both a DBSC-bound short cookie (per-origin) and an &lt;code&gt;x-ms-RefreshTokenCredential&lt;/code&gt; cookie from the WAM attachment path. Which binding wins, and how the two bindings are composed in the resource provider&apos;s evaluation, has not been publicly documented. The Stage 3 research found no Microsoft engineering blog explaining the contract.The Chrome developer documentation page on DBSC cites &quot;Chrome 145&quot; while the Google Security Blog post about DBSC GA cites &quot;Chrome 146.&quot; The two pages are co-published by Google; the security blog is dated later in 2025 and represents the GA figure. Stage 4 flagged this as an internal-inconsistency artifact. The article uses Chrome 146 for the GA framing and notes Chrome 145 as the rollout-start build [@dbsc-chrome-developer] [@dbsc-google-blog].&lt;/p&gt;

A modern Windows Edge session against `login.microsoftonline.com` already carries `x-ms-RefreshTokenCredential`. A modern Chrome 146 session on Windows carries a DBSC-bound short cookie for the same origin. Token Protection enforces device binding for *native-app* access-token requests, not browser ones. The three bindings are not redundant -- they cover different surfaces -- but Microsoft has not published a precedence rule or a unified &quot;this is how the browser proves device binding to Entra&quot; reference, and the open question is whether the W3C DBSC draft will be the home for that contract or whether Microsoft will document the composition independently. The composition story for browser SSO is, in 2026, the single most active open problem in this space.
&lt;p&gt;&lt;strong&gt;PRT-aware Conditional Access for AI agents and workload identities.&lt;/strong&gt; As organizations deploy autonomous AI agents that act on behalf of users -- Copilot agents, Office Studio bots, third-party LangGraph-style systems -- the identity story is genuinely unsettled. Some agents authenticate as the user via delegated permissions on a PRT-mediated path. Others authenticate as their own service principal via Workload Identity Federation. Conditional Access policies designed for human users -- &quot;require compliant device, require MFA, require sign-in frequency under four hours&quot; -- do not map cleanly to either. Microsoft Entra Agent ID entered public preview at Ignite 2025 with Conditional Access extended to agent identities via custom security attributes and agent-identity-blueprint policy targeting [@entra-agent-id-conditional-access], but the precise PRT-side claim semantics for agent-on-behalf-of-user vs autonomous-agent paths are still settling. The Conditional Access for AI Agents sibling article addresses the evolving model in detail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PRT across RDP.&lt;/strong&gt; There is no clean &quot;redirect PRT&quot; primitive analogous to Remote Credential Guard&apos;s Kerberos redirection. Inside an RDP session to an Entra-joined host, a user can perform an Azure AD RDP sign-in that mints a &lt;em&gt;new&lt;/em&gt; PRT at the host -- but the client&apos;s PRT does not transit the RDP hop. Forensic and operational tooling that wants to know &quot;what PRT does this remote user have, and is it the same as the client&apos;s?&quot; has to query both endpoints separately. Active Microsoft work in this area is referenced in Mollema&apos;s TROOPERS 22 deck, but no public solution has shipped.&lt;/p&gt;
&lt;p&gt;These five problems share an architecture: they are all about composition. The PRT is one of several primitives that have to work together. The next section walks the practical guide for making them work in your environment today.&lt;/p&gt;
&lt;h2&gt;11. Practical guide&lt;/h2&gt;
&lt;p&gt;Here is what you actually do with the PRT this week.&lt;/p&gt;
&lt;h3&gt;Verifying PRT issuance&lt;/h3&gt;
&lt;p&gt;The operator-facing surface is &lt;code&gt;dsregcmd /status&lt;/code&gt;, which prints the PRT state under the &lt;code&gt;SSO State&lt;/code&gt; section. The three fields to read are &lt;code&gt;AzureAdPrt&lt;/code&gt; (Yes if a PRT is present), &lt;code&gt;AzureAdPrtUpdateTime&lt;/code&gt; (the timestamp of the last refresh), and &lt;code&gt;AzureAdPrtExpiryTime&lt;/code&gt; (the absolute expiry on the current PRT, by default 90 days after issuance) [@prt-msft-learn] [@dsregcmd-troubleshoot].&lt;/p&gt;
&lt;p&gt;{&lt;code&gt; // Models the section of dsregcmd /status output you care about. // On a real Windows host, you would run: dsregcmd /status | findstr AzureAdPrt const sampleOutput = \&lt;/code&gt;
+----------------------------------------------------------------------+
| SSO State                                                            |
+----------------------------------------------------------------------+
             AzureAdPrt : YES
       AzureAdPrtUpdateTime : 2026-05-12 09:31:14.000 UTC
       AzureAdPrtExpiryTime : 2026-08-10 09:31:14.000 UTC
        AzureAdPrtAuthority : login.microsoftonline.com/
              EnterprisePrt : NO
`;
const lines = sampleOutput.split(&apos;\n&apos;).filter(l =&amp;gt; l.match(/AzureAdPrt/));
console.log(lines.map(l =&amp;gt; l.trim()).join(&apos;\n&apos;));
// Healthy: AzureAdPrt=YES and AzureAdPrtUpdateTime within the last 4 hours.
`}&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;AzureAdPrt&lt;/code&gt; is &lt;code&gt;NO&lt;/code&gt; on a device that should have one, the most common causes are (a) the device is not actually Entra-joined, (b) the user has never signed in interactively since the last reboot, or (c) the device&apos;s TPM is malfunctioning and CloudAP could not complete the issuance handshake. &lt;code&gt;dsregcmd /status&lt;/code&gt; will print device-state diagnostics directly above the SSO State section that disambiguate these.&lt;/p&gt;
&lt;h3&gt;Forcing PRT renewal&lt;/h3&gt;
&lt;p&gt;The PRT refreshes silently every four hours, driven by CloudAP -- this is the renewal cadence Microsoft Learn documents as the device-side refresh schedule, not a Conditional Access policy [@prt-msft-learn]. To force an out-of-band renewal, the supported path is to sign the user out and back in with a Hello-for-Business gesture or a strong credential. A locked-and-unlocked session does &lt;em&gt;not&lt;/em&gt; generally force a new PRT mint; CloudAP treats unlock as a continuation event, not a fresh issuance.&lt;/p&gt;
&lt;h3&gt;Hunting PRT-mediated sign-ins in Entra logs&lt;/h3&gt;
&lt;p&gt;In the Microsoft Entra audit and sign-in logs, the load-bearing fields are &lt;code&gt;authenticationDetails&lt;/code&gt;, &lt;code&gt;authenticationProcessingDetails&lt;/code&gt;, and the &lt;code&gt;IsCompliantDevice&lt;/code&gt; and &lt;code&gt;DeviceDetail&lt;/code&gt; claims attached to the sign-in event. A sign-in that rode the PRT path will surface a &lt;code&gt;PRT&lt;/code&gt; indicator in &lt;code&gt;authenticationProcessingDetails&lt;/code&gt;. In Microsoft Defender XDR&apos;s advanced-hunting tables, the corresponding views are &lt;code&gt;IdentityLogonEvents&lt;/code&gt; (for on-prem and federated paths) and &lt;code&gt;AADSignInEventsBeta&lt;/code&gt; (for native Entra sign-in events) [@defender-xdr-schema]. The latter is the table to query when looking for unusual &lt;code&gt;x-ms-RefreshTokenCredential&lt;/code&gt;-driven sign-ins -- specifically, sign-ins from device-claim-bearing tokens whose &lt;code&gt;DeviceId&lt;/code&gt; does not match the device&apos;s &lt;code&gt;DeviceId&lt;/code&gt; in Intune.&lt;/p&gt;
&lt;h3&gt;Conditional Access patterns&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;What it enforces&lt;/th&gt;
&lt;th&gt;What it cannot enforce&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Require compliant device&lt;/td&gt;
&lt;td&gt;Sign-in only from devices Intune (or a partner MDM) reports as compliant&lt;/td&gt;
&lt;td&gt;Whether the compliance signal is fresh; an attacker who can spoof an Intune compliance attestation passes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Require Microsoft Entra hybrid joined device&lt;/td&gt;
&lt;td&gt;Sign-in only from hybrid-joined devices&lt;/td&gt;
&lt;td&gt;Personal Entra-registered devices that meet compliance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Require MFA at sign-in&lt;/td&gt;
&lt;td&gt;A fresh MFA factor at PRT issuance&lt;/td&gt;
&lt;td&gt;Whether the MFA factor is phishing-resistant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication Strengths (FIDO2-only)&lt;/td&gt;
&lt;td&gt;Phishing-resistant credential at issuance, propagated as a strong &lt;code&gt;mfa&lt;/code&gt; claim into the PRT&lt;/td&gt;
&lt;td&gt;Downstream phishability through cookie theft (KDFv2 fix applies; on-device residual remains)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token Protection for sign-in tokens&lt;/td&gt;
&lt;td&gt;Device-bound assertion required for app-token requests&lt;/td&gt;
&lt;td&gt;Browser sessions (DBSC is the per-origin counterpart)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sign-in Frequency = 4 hours&lt;/td&gt;
&lt;td&gt;Re-authentication every four hours&lt;/td&gt;
&lt;td&gt;The 90-day PRT lifetime independent of sign-in cadence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The right policy stack for most enterprises is: require compliant device (or hybrid-joined), require Authentication Strengths for privileged users, require Token Protection where the resource supports it, and set a Sign-In Frequency policy that matches your risk appetite. CAE is on by default on modern tenants and does not need explicit opt-in.&lt;/p&gt;
&lt;h3&gt;CAE enablement and tenant configuration&lt;/h3&gt;
&lt;p&gt;CAE was made the default for all Entra tenants at GA on 10 January 2022; the announcement explicitly noted that Microsoft &quot;auto-enabled it for all tenants&quot; [@twu-cae-ga-mirror]. Microsoft Outlook, Microsoft Teams, and Office on Windows are CAE-aware clients [@cae-learn]; third-party apps that want to participate need to implement the claim-challenge protocol. Microsoft Graph clients gain CAE participation by including &lt;code&gt;cp1&lt;/code&gt; in the requested client capabilities [@cae-client-capabilities]. If your tenant is a CAE outlier, the cause is almost always a custom OIDC application that has not implemented the claim challenge.&lt;/p&gt;
&lt;h3&gt;Forensic indicators&lt;/h3&gt;
&lt;p&gt;Three signals deserve hunting attention:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Anomalous &lt;code&gt;x-ms-RefreshTokenCredential&lt;/code&gt; cookie origins.&lt;/strong&gt; A sign-in where the cookie&apos;s IP geolocation does not match the device&apos;s last known location -- particularly across time zones -- is a candidate Pass-the-PRT-Cookie signal even after KDFv2, because the on-device class survives.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Device-claim-bearing tokens whose &lt;code&gt;DeviceId&lt;/code&gt; does not match Intune state.&lt;/strong&gt; An attacker who lifted a PRT off-device cannot mint cookies post-KDFv2, but a cloned &lt;code&gt;DeviceId&lt;/code&gt; claim in a token request is a strong off-the-rails signal in older logs and a useful retrospective hunt for July 2021 and earlier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;lsass&lt;/code&gt; broker-process anomalies.&lt;/strong&gt; Mimikatz-class memory-reading tools typically attach to &lt;code&gt;lsass&lt;/code&gt; with debug privileges. The current EDR generation (Microsoft Defender for Endpoint, CrowdStrike Falcon, SentinelOne) detects the canonical access patterns; deploy that telemetry, then validate the alert-rule coverage with &lt;code&gt;Get-MpComputerStatus&lt;/code&gt; and the EDR-specific equivalents.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;What NOT to do&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The single biggest operational mistake is to disable the broker because something else is broken. WAM, CloudAP, and the browser SSO surface are not optional add-ons; they are the cryptographic floor your Conditional Access policies are built on. If a particular app is breaking on PRT-mediated sign-in, the right move is to diagnose the broker integration, not to suppress it. Likewise, do not suppress Conditional Access in lieu of trusting the PRT -- the PRT carries claims that Conditional Access evaluates; disabling Conditional Access keeps the claims but throws away the policy engine.&lt;/p&gt;
&lt;/blockquote&gt;

Open an elevated command prompt. Run `dsregcmd /status`. Confirm `AzureAdJoined : YES`, `DeviceId` is populated, and `AzureAdPrt : YES` with a recent `AzureAdPrtUpdateTime`. Then in PowerShell, run `Get-CimInstance -ClassName Win32_Tpm` and confirm the TPM is present, ready, and at spec version 2.0. Finally, in the Entra ID portal, search for the device by `DeviceId` and confirm the registration state, the OS version, and the compliance posture. Those three checks rule out 90% of &quot;is my PRT working?&quot; questions.
&lt;p&gt;That is the PRT -- what it is, how it broke, how Microsoft fixed it, where it stops. Now the FAQ.&lt;/p&gt;
&lt;h2&gt;12. FAQ and closing&lt;/h2&gt;

No. They are different protocols, issued by different authorities, with different lifetimes. A Kerberos TGT is issued by an on-prem Key Distribution Center, lives 10 hours by default, and rides the AS_REQ/AS_REP protocol. A PRT is issued by Microsoft Entra ID, lives 90 days by default, and rides the MS-OAPXBC protocol over HTTPS. Cloud Kerberos Trust *issues a TGT to a PRT holder* via the Microsoft Entra Kerberos partial-TGT mechanism [@cloud-kerberos-trust-learn], but the two artifacts are distinct and serve different protocol clients.

No. The PRT is the cloud-mediated authentication path. On-prem Kerberos still flows through the on-prem KDC for resources protected by the on-prem Active Directory domain. NTLM remains in use for legacy applications until those applications migrate. The PRT, Cloud Kerberos Trust, and the in-progress &quot;NTLM-less&quot; effort together describe a path that *reduces* reliance on NTLM, but they do not delete the on-prem authentication surface on day one.

Not since July 2021. The asymmetric device key (`dkpriv`) signs the PRT *issuance* request -- a single asymmetric signature per PRT mint. The `x-ms-RefreshTokenCredential` cookie, by contrast, is HMAC-signed with `alg: HS256` using a symmetric key derived from the PRT *session key* via the SP800-108 KDF. Under KDFv2, the derivation context binds the cookie&apos;s full payload via `SHA256(ctx || assertion_payload)` [@ms-oapxbc-jwt] [@dimi-3or-de-kdfv2].

No. Dirk-jan Mollema&apos;s seminal PRT-cookie extraction work appeared in two blog posts on `dirkjanm.io` -- 21 July 2020 and 5 August 2020 [@mollema-prt-2020-07] [@mollema-prt-2020-08]. His 2022 conference talk on the same body of research was at TROOPERS 22 in Heidelberg in June 2022, not at DEF CON 30 [@troopers22-abstract]. Mollema&apos;s DEF CON history covers DC 27 (2019), DC 32 (2024), and DC 33 (2025); he did not present at DC 30 (2022) [@dirkjanm-talks-index]. The &quot;DEF CON 2022&quot; anchor that occasionally appears in summaries of the PRT-attack story is a memory error.

Yes. Conditional Access evaluates each *token request*, including app-token requests via the Web Account Manager and `x-ms-RefreshTokenCredential` cookie redemptions at `login.microsoftonline.com`. The PRT carries device-state, MFA, and risk claims; Conditional Access uses those claims plus the resource and request context to allow or deny each request. CAE additionally revokes already-issued long-lived access tokens in near real time when critical events fire [@cae-learn].

No. Microsoft Pluton *is* a TPM 2.0 implementation -- the same TPM 2.0 contract, embedded in the SoC rather than as a discrete chip. The PRT two-key model is unchanged. `dkpriv` and `tkpriv` are TPM 2.0 keys on Pluton just as they are on a discrete TPM 2.0; CloudAP does not branch on TPM provenance in its issuance path.

All three device states issue PRTs at first interactive sign-in. The differences are about device-management posture and which Conditional Access claims attach. **Microsoft Entra registered** is the personal-device / BYOD state -- the device has a cloud identity but is not the primary management surface; the PRT exists but the device is not necessarily compliant in the management sense. **Microsoft Entra joined** is the cloud-primary state -- the device&apos;s primary identity authority is Entra ID. **Microsoft Entra hybrid joined** is the dual state -- the device has both an on-prem AD computer object and an Entra ID device object; both authentication paths are active in parallel. Microsoft documents hybrid join as &quot;an interim step on the road to Microsoft Entra join&quot; for organizations migrating away from on-prem AD [@entra-devices-overview].
&lt;p&gt;The PRT is not a replacement for Kerberos, NTLM, or Credential Guard. It is the cryptographic seam where Windows logon becomes a Microsoft Entra ID transaction -- and the rest of this series is about what runs alongside it: Hello for Business as the issuing credential, WebAuthn and FIDO2 as the per-relying-party authenticator class, Cloud Kerberos Trust as the on-prem bridge, Credential Guard as the on-prem-credential isolation path, Adminless as the local-authorization pattern, App Identity as the workload broker. Each of those articles starts from a question this one raises, and each closes on a question that connects back. The seam is the part you can name when somebody asks how the three sign-ins from §1 are secretly one event.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;entra-id-and-the-primary-refresh-token-how-azure-ad-sign-on-bridges-windows-logo&quot; keyTerms={[
  { term: &quot;Primary Refresh Token (PRT)&quot;, definition: &quot;Device-bound JWT issued by Microsoft Entra ID to CloudAP at first interactive sign-in; cryptographic seam between Windows logon and Entra-mediated SSO.&quot; },
  { term: &quot;CloudAP&quot;, definition: &quot;Cloud Authentication Provider plugin framework in lsass.exe; the Entra ID plugin owns the device-side PRT lifecycle.&quot; },
  { term: &quot;Device key (dkpub/dkpriv)&quot;, definition: &quot;TPM-bound key pair that signs PRT issuance requests; registered with Entra ID at join time.&quot; },
  { term: &quot;Transport key (tkpub/tkpriv)&quot;, definition: &quot;TPM-bound key pair Entra ID uses to wrap session keys; only tkpriv can unwrap them on-device.&quot; },
  { term: &quot;Session key&quot;, definition: &quot;Symmetric proof-of-possession key for the PRT lifetime; signs cookies and app-token requests via SP800-108 KDF derivation.&quot; },
  { term: &quot;x-ms-RefreshTokenCredential&quot;, definition: &quot;HMAC-signed JWT cookie that carries PRT-derived authentication to login.microsoftonline.com from supported browsers.&quot; },
  { term: &quot;KDFv2&quot;, definition: &quot;Post-CVE-2021-33779 derivation rule that mixes SHA256(ctx || payload) into the cookie&apos;s signing-key derivation, closing off-device replay.&quot; },
  { term: &quot;Continuous Access Evaluation (CAE)&quot;, definition: &quot;Near-real-time revocation channel for OAuth access tokens; 15-minute event-propagation upper bound; CAEP-anchored claim-challenge protocol.&quot; },
  { term: &quot;Token Protection&quot;, definition: &quot;Conditional Access session control that requires device-bound assertions for app-token requests; the per-app analogue of PRT device binding.&quot; },
  { term: &quot;Cloud Kerberos Trust&quot;, definition: &quot;Bridge that lets a PRT-bearing device receive on-prem Kerberos TGTs from Entra ID via the AzureADKerberos virtual RODC object.&quot; }
]} questions={[
  { q: &quot;Why is &apos;the PRT cookie is DKey-signed&apos; wrong?&quot;, a: &quot;The device key signs the asymmetric PRT issuance request once per PRT mint. Cookies are HMAC-signed with a symmetric key derived from the session key via SP800-108 KDF; under KDFv2 the derivation context is SHA256(ctx || assertion_payload).&quot; },
  { q: &quot;What did CVE-2021-33779 fix, in one sentence?&quot;, a: &quot;It introduced KDFv2, which binds the cookie&apos;s full payload into the SP800-108 derivation context, so a key derived for one cookie cannot sign another -- killing off-device Pass-the-PRT.&quot; },
  { q: &quot;What does the on-device-attacker floor mean for the PRT?&quot;, a: &quot;A same-privilege attacker on the live device can ask CloudAP to mint a fresh cookie; the TPM signs it, because that is its job. Off-device replay is closed; on-device Cookie-on-Demand is the architectural residual.&quot; },
  { q: &quot;Where does the PRT NOT apply?&quot;, a: &quot;On-prem Kerberos via the on-prem KDC, Credential Guard / LSAISO (NTLM/Kerberos long-term keys), Adminless (authorization), App Identity / workload identities, and Remote Credential Guard (which redirects Kerberos, not PRT).&quot; },
  { q: &quot;How does CAE revoke an in-flight access token?&quot;, a: &quot;Entra fires a CAEP event on a critical change (user deletion, password reset, MFA enable, admin revocation, high user risk). The CAE-aware resource provider issues an HTTP 401 with a claim challenge on the next request; the client re-presents the PRT and Entra evaluates Conditional Access fresh, issuing a new token or denying.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>entra-id</category><category>azure-ad</category><category>windows-authentication</category><category>primary-refresh-token</category><category>tpm</category><category>conditional-access</category><category>identity</category><author>noreply@paragmali.com (Parag Mali)</author></item></channel></rss>