# Inside the Primary Refresh Token: The Cryptographic Seam Between Windows Logon and Microsoft Entra ID

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

*Published: 2026-05-12*
*Canonical: https://paragmali.com/blog/inside-the-primary-refresh-token-the-cryptographic-seam-betw*
*License: CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/*

---
<TLDR>
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'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.
</TLDR>

## 1. Three sign-ins, one credential

A user signs into a freshly enrolled Entra-joined laptop with [Windows Hello for Business](/blog/your-face-is-not-your-password-inside-windows-hellos-hardwar/). Ten seconds later they open Outlook, which silently authenticates against Microsoft 365. An hour later they type `outlook.office.com` into Edge -- and they are already signed in there too.

Three sign-ins, one credential. The credential was issued during the Windows logon itself, and the user has never seen it.

This article is about that credential -- the **Primary Refresh Token** -- and about the cryptographic seam where Windows logon stops being a local NT-style event and becomes a Microsoft Entra ID transaction.

<Definition term="Primary Refresh Token (PRT)">
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].
</Definition>

The questions worth asking are concrete. What does that token actually contain? How did it get from `lsass` to a browser cookie without the user ever pasting it? Why is the cookie that rides in the browser called `x-ms-RefreshTokenCredential` 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?

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.

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.

## 2. The cloud-identity gap, 2011 to 2014

Windows authentication, in 2011, did not speak cloud. [NTLM](/blog/ntlmless-the-death-of-ntlm-in-windows/) resolved against a local SAM database. [Kerberos](/blog/kerberos-in-windows-the-other-half-of-ntlmless/) 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.

For a cloud-only workload, that left a gap shaped like a question. Where, exactly, does the user's identity live when there is no on-prem domain to resolve it against?

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's Active Directory Authentication Library -- ADAL -- took the obvious next step: every application that wanted to talk to Microsoft'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.

That patchwork held for a while. It also taught Microsoft two things.

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's guess. The device, in other words, was invisible.

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 "are you sure?" 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.

The first move was small. On 28 June 2013, Adam Hall announced **Workplace Join** 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 "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's device authentication as part of conditional access policies" [@workplace-join-2013].

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 *during* the sign-in.

That credential arrived in 2015 -- but its design took another year to harden.

## 3. Workplace Join, Azure AD Join, and the OAuth-refresh-token patchwork

What does it cost a Windows endpoint to authenticate to ten cloud apps if it has no PRT?

Counting tokens is a good way to find out. Each app maintains its own refresh-token cache. Each refresh redeems against the same `login.microsoftonline.com` endpoint but with a different `client_id` 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 *bad*; it is that authentication is *redundant*, and the policy engine sees a hundred small claims instead of one big one.

Microsoft walked out of that failure mode in three steps.

**Step one (June 2013): Workplace Join.** A device cert, signed by the Device Registration Service, written to a new device object in Active Directory. Adam Hall'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 **Microsoft Entra registered** -- the same primitive, renamed [@entra-devices-overview].

<Sidenote>"Workplace Join" was the 2013 marketing name. The same artifact is now called "Microsoft Entra registered" 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].</Sidenote>

**Step two (May 2015): Azure AD Join.** 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. "Azure AD join is optimized for users that primarily access cloud resources," 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].

<MarginNote>This 28 May 2015 Tech Community post is the corrected primary source. An older URL in the same series (`.../ba-p/247010`) was re-tagged by Microsoft's CMS to a 2010 RemoteFX article and now resolves to unrelated content; the 244005 post is the load-bearing technical announcement.</MarginNote>

The Azure AD Join story introduced one more component: **CloudAP**, the Cloud Authentication Provider, an authentication-package framework hosted inside `lsass.exe`. 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.

<Definition term="Cloud Authentication Provider (CloudAP)">
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].
</Definition>

**Step three (August 2016): the first PRT.** 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 [TPM](/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/)-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 `mstsc` 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.

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.

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 *is* cryptographically -- and to answer that, we need to be precise about two key pairs that most descriptions of the PRT conflate.

<Mermaid caption="From Workplace Join (2013) to KDFv2 (2021): the PRT evolution timeline">
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
</Mermaid>

## 4. The two-key cryptographic model

Most descriptions of the PRT online say the cookie is "DKey-signed." That phrase has been wrong since July 2021. Here is the actual cryptographic substrate.

When a Windows device joins Microsoft Entra ID -- by way of the Out-of-Box Experience, by `dsreg`'s join command, or by the implicit registration that happens on a personal device -- the registration component generates **two** key pairs on the device. One pair signs PRT *issuance* requests. The other unwraps session keys returned *with* the PRT. Microsoft's own documentation enumerates the two pairs the `dsreg` component generates at device registration: Device key (`dkpub`/`dkpriv`) and Transport key (`tkpub`/`tkpriv`) [@prt-msft-learn].

<Definition term="Device key (dkpub/dkpriv)">
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].
</Definition>

<Definition term="Transport key (tkpub/tkpriv)">
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's symmetric proof-of-possession surface [@prt-msft-learn].
</Definition>

<Definition term="dsreg">
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].
</Definition>

The two-key model is not a typo, and the second-most-common reading of it is wrong. The device key signs *the request for* a PRT. The transport key unwraps *the session key that arrives with* a PRT. Once unwrapped, the session key signs everything from there on -- not the device key.

> **Note:** The device key signs PRT issuance, once per PRT mint. The transport key unwraps a *session key*. Every downstream artifact -- the `x-ms-RefreshTokenCredential` browser cookie, every WAM-mediated app-token request -- is signed by a key *derived from* that session key, not by `dkpriv` directly.

The eight-step issuance flow makes this explicit.

<Mermaid caption="The eight-step PRT issuance flow: Hello sign-in to first WAM token">
sequenceDiagram
    participant User
    participant CloudAP as CloudAP (lsass)
    participant TPM
    participant Entra as Microsoft Entra ID
    participant CA as Conditional Access
    participant WAM
    User->>CloudAP: 1. Interactive sign-in (Hello, password, FIDO2)
    CloudAP->>TPM: 2. Sign authorization JWT with dkpriv
    TPM-->>CloudAP: 3. Signed assertion
    CloudAP->>Entra: 4. Issuance request (signed assertion)
    Entra->>CA: 5. Evaluate device + user + risk claims
    CA-->>Entra: 6. Issuance permitted
    Entra-->>CloudAP: 7. PRT + session_key encrypted under tkpub
    CloudAP->>TPM: 8. Unwrap session_key with tkpriv
    Note over CloudAP,WAM: Session key now resident -- WAM, browser SSO, and CAE all derive from it
</Mermaid>

A user provides an interactive credential -- a Hello gesture, a password, a FIDO2 security key. The CloudAP plugin in `lsass` constructs a JWT carrying the user's authorization material and asks the TPM to sign it with `dkpriv`. 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 `tkpub`. The TPM unwraps the session key with `tkpriv`. The session key now lives on the device, in CloudAP's hot path, available for every broker to use.

<Definition term="Session key (PRT session key)">
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].
</Definition>

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's documentation implied.

Once the session key is on the device, the **Web Account Manager (WAM)** -- 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.

<Definition term="Web Account Manager (WAM)">
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].
</Definition>

<Definition term="x-ms-RefreshTokenCredential cookie">
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.
</Definition>

Inside that cookie, the signing key is **derived** from the session key via the SP800-108 key-derivation function. The label is the constant string `AzureAD-SecureConversation`. The context (`ctx`) is a per-cookie value chosen by the client. The MS-OAPXBC protocol specification gives the rule verbatim: under KDFv2, "the client MUST use SHA256(ctx || assertion payload) instead of ctx as the context for deriving the signing key" [@ms-oapxbc-jwt]. We will come back to that sentence in §6, because it is *the* sentence.

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

On supported hardware, both `dkpriv` and `tkpriv` are non-extractable TPM 2.0 keys. On a device with [Microsoft Pluton](/blog/pluton-a-tpm-on-silicon-microsoft-can-patch/) (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's credentials, which is a meaningfully weaker contract than TPM non-extractability. We will come back to that distinction in §9.

<Aside label="Why the 'DKey-signed cookie' shorthand was wrong">
The shorthand "the PRT cookie is DKey-signed" 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's reverse-engineering captures the post-2021 mechanic precisely: "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" [@dimi-3or-de-kdfv2]. The asymmetric device key only signs the PRT *issuance* request; everything afterwards is HMAC over a derived key.
</Aside>

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 *should* make Pass-the-PRT impossible. In 2020, three independent researchers proved it didn't.

## 5. When TPM-binding is not enough

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?

The answer, on the architecture Microsoft shipped at the time, was yes -- and the answer came from three angles in less than two months.

<PullQuote>
"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
</PullQuote>

**Lee Christensen at SpecterOps, mid-July 2020.** Christensen's blog post -- "Requesting Azure AD Refresh Tokens on Azure AD-joined Machines for Browser SSO" -- documented a path through a Component Object Model interface, `IProofOfPossessionCookieInfoManager.GetCookieInfoForUri`, that returned a fully signed `x-ms-RefreshTokenCredential` cookie to a user-mode caller [@christensen-specterops-2020]. The CLSID is `{a9927f85-a304-4390-8b23-a75f1c668600}`; the implementation lives in `MicrosoftAccountTokenProvider.dll`; the workflow rides through `BrowserCore.exe` over a named pipe. Christensen released the proof-of-concept as `RequestAADRefreshToken` 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.

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.

**Dirk-jan Mollema, 21 July 2020.** A week later, Mollema published "Abusing Azure AD SSO with the Primary Refresh Token" on `dirkjanm.io`. Mollema'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's: an attacker on the live device could mint cookies, and the TPM was not in the way.

**Mollema, 5 August 2020.** This is the blog that mattered most. In "Digging further into the Primary Refresh Token," Mollema reverse-engineered `aadcloudap.dll`. He isolated the session-key handling, the cookie-construction routine, the SP800-108 derivation call, the eventual `BCryptKeyDerivation`-then-HMAC flow. And he wrote the sentence that, in retrospect, defined the next year of Microsoft's response: "despite the session key of the PRT is stored in the TPM whenever possible, this doesn'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" [@mollema-prt-2020-08].

<PullQuote>
"despite the session key of the PRT is stored in the TPM whenever possible, this doesn't prevent us from extracting the PRT and the required information to create SSO cookies." -- Dirk-jan Mollema, 5 August 2020
</PullQuote>

The reason is the most important thing in this article. The session key never left the TPM. But the *signing key derived from the session key* did. The TPM dutifully performed an SP800-108 derivation -- HMAC-SHA256 with the label `AzureAD-SecureConversation` and the client-chosen `ctx` 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 `lsass`, an admin-with-debug-privilege attacker could simply read it.

Around the same time, Benjamin Delpy -- the author of Mimikatz -- picked up Mollema's "challenge" of recovering PRT data from `lsass`. Two days after Mollema's 5 August post, that collaboration produced the Mimikatz release tagged `2.2.0-20200807`, which added the `sekurlsa::cloudap` and `dpapi::cloudapkd` modules [@gh-mimikatz]. The tag URL itself was later collapsed in GitHub'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].

<Sidenote>The GitHub URL `https://github.com/gentilkiwi/mimikatz/releases/tag/2.2.0-20200807` returns HTTP 404 in the current GitHub UI; the modern releases list starts at `2.2.0-20210729`. The Wayback snapshot at `web.archive.org/web/20200920005113/...` preserves the release page (including the "prt3" animated demonstration GIF). Nestori Syynimaa's AADInternals post and Mollema'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].</Sidenote>

**Nestori Syynimaa and AADInternals, August through September 2020.** Syynimaa's AADInternals PowerShell module shipped `Get-AADIntUserPRTToken` as part of v0.4.1 alongside the disclosure. On 29 September 2020, AADInternals' blog post about the tool gained an inline update: "It seems that PRT tokens must now include the `request_nonce`. If not, Azure AD sends a redirect with `sso_nonce` which must be added to the PRT token. This means that without access to session key, PRT tokens can't be used anymore" [@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.

<Mermaid caption="Pass-the-PRT (2020): how Mimikatz, ROADtoken, and the COM-API path produced off-device cookies">
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->>LSASS: sekurlsa::cloudap (admin path)
    LSASS-->>Attacker: PRT + derived signing key + context
    Note over Attacker: Or, parallel user-only path:
    Attacker->>COM: GetCookieInfoForUri(target_url)
    COM-->>Attacker: Pre-baked x-ms-RefreshTokenCredential
    Note over Attacker: Cookie is now portable
    Attacker->>Entra: Replay cookie from an attacker-controlled host
    Entra-->>Attacker: SSO honored, access token issued
</Mermaid>

> **Note:** With admin on an Entra-joined device in summer 2020, an attacker could lift the PRT and the derived signing key from `lsass`, mint fresh `x-ms-RefreshTokenCredential` cookies on any host they controlled, and pass Conditional Access checks that included the cloned `DeviceId` 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.

The community quickly settled on a name for this class: **Pass-the-PRT**. By analogy to Pass-the-Hash and Pass-the-Ticket, the attack is "lift a long-lived authentication artifact from one host, present it as your own elsewhere." For a credential that the entire cloud sign-in stack was about to trust, the implications were severe.

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's full payload that killed off-device Pass-the-PRT for good.

## 6. KDFv2 and the death of off-device Pass-the-PRT

The fix Microsoft shipped on 13 July 2021 fits on one line.

The CVE is **CVE-2021-33779**. NIST's National Vulnerability Database describes it as "Windows AD FS Security Feature Bypass Vulnerability" and provides no further public detail [@nvd-cve-2021-33779]. Microsoft's own KDFv2 documentation ties the patch explicitly to that CVE: "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" [@kdfv2-learn].

<Definition term="KDFv2">
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 "Enforced" mode [@ms-oapxbc-jwt] [@kdfv2-learn].
</Definition>

A small subtlety lives in the attribution. NVD names AD FS. The community-side coverage -- blog.3or.de, Mollema'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 "Pass-the-PRT" on the page itself. We will keep the hedge in mind.

<Aside label="What NVD says vs what blog.3or.de says about CVE-2021-33779">
NVD's one-line description -- "Windows AD FS Security Feature Bypass Vulnerability" -- 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'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 "the rollout vehicle for KDFv2," not as a one-to-one CVE-to-attack mapping.
</Aside>

The load-bearing rule is one sentence. MS-OAPXBC §3.2.5 puts it like this: "If the client chooses to use KDFv2, the client MUST use `SHA256(ctx || assertion payload)` instead of `ctx` as the context for deriving the signing key. The client MUST also add the JWT header field `kdf_ver` with value set to 2 to communicate that KDFv2 was used for creating the derived signing key" [@ms-oapxbc-jwt].

To see why that line matters, picture what the attacker in §5 was actually copying. The attacker lifted the derived signing key out of `lsass`. The derived signing key was, under KDFv1, a function of the session key (TPM-resident) and the client-chosen context `ctx` (any 256 bits the attacker liked). Any cookie the attacker built using the same `ctx` would verify against the same derived key. The attacker could pick `ctx` first, derive the key once, and stamp out as many cookies as they wanted.

Under KDFv2, the context is no longer arbitrary. The context is `SHA256(ctx || assertion_payload)`. The `assertion_payload` 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.

> **Note:** 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 "derive a key for this session, then sign anything." After KDFv2, the contract is "derive a key for this specific message." 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.

The residual is also explicit. The attacker who is still *on the device* -- still has a process running as the user or as `SYSTEM` -- 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: "This attack, referred to as Pass-the-PRT-Cookie, still works today but requires presence on the targeted device" [@dimi-3or-de-kdfv2]. Mollema's TROOPERS 22 talk calls the same residual "Cookie-on-Demand" and walks the in-place cookie-minting flow on a fully patched Entra-joined endpoint [@troopers22-mollema-pdf] [@troopers22-abstract].

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 `AzureAD-SecureConversation`, $\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.

<RunnableCode lang="js" title="The KDFv2 derivation in 12 lines (illustrative)">{`
// Illustrative; do NOT use as production crypto.
const crypto = require('crypto');

function sha256(buf) { return crypto.createHash('sha256').update(buf).digest(); }
function hmac(key, data) { return crypto.createHmac('sha256', key).update(data).digest(); }

function deriveKdfv2SigningKey(sessionKey, ctx, assertionPayload) {
  const label = Buffer.from('AzureAD-SecureConversation', 'utf8');
  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]));
}

// The signing key is now uniquely tied to assertionPayload.
`}</RunnableCode>

A side-by-side flowchart makes the structural shift legible.

<Mermaid caption="KDFv1 vs KDFv2: what the post-CVE-2021-33779 derivation actually changed">
flowchart LR
    subgraph KDFv1 ["KDFv1 (pre-July 2021)"]
        A1[Session key in TPM] --> A2["SP800-108 KDF<br/>label = AzureAD-SecureConversation<br/>context = ctx"]
        A2 --> A3[Derived signing key]
        A3 --> A4[HMAC over any JWT body]
    end
    subgraph KDFv2 ["KDFv2 (July 2021+)"]
        B1[Session key in TPM] --> B2["SP800-108 KDF<br/>label = AzureAD-SecureConversation<br/>context = SHA256 of ctx || payload"]
        B2 --> B3[Derived signing key]
        B3 --> B4[HMAC over the specific JWT body]
    end
</Mermaid>

KDFv2 killed off-device replay. It did not kill the on-device signing oracle, and it did not shorten the PRT'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.

## 7. The seam: CAE, Token Protection, Cloud Kerberos Trust

By 2022 the PRT was *the* credential. The work that remained was to make every artifact issued *from* it -- every access token, every Kerberos TGT, every Conditional Access claim -- share the same device-binding contract.

That work has three named pieces, and a quiet rename in the middle.

### Continuous Access Evaluation

**Continuous Access Evaluation** entered public preview in late 2020, a few months after Mollema'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 *long-lived* access token issued from a PRT can be invalidated in seconds when something critical changes.

<Definition term="Continuous Access Evaluation (CAE)">
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].
</Definition>

Mechanically: a CAE-aware client requests an access token from Entra ID, and Entra issues a *long-lived* token -- up to 28 hours rather than the conventional one hour -- with a `xms_cc` 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 `WWW-Authenticate` 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's original lifetime.

<Mermaid caption="Continuous Access Evaluation: how a password reset revokes a 28-hour access token in seconds">
sequenceDiagram
    participant Admin
    participant Entra as Microsoft Entra ID
    participant Resource as Exchange Online
    participant Client
    Admin->>Entra: Force password reset for user
    Entra-->>Resource: CAEP event: Credential Change
    Client->>Resource: GET /mail (with long-lived token)
    Resource-->>Client: 401 WWW-Authenticate (claim challenge)
    Client->>Entra: Refresh token + claim challenge
    Note over Entra: Re-evaluate Conditional Access against current user state
    Entra-->>Client: New short access token (or deny)
    Client->>Resource: GET /mail (new token)
    Resource-->>Client: 200 OK
</Mermaid>

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.

### Token Protection

If CAE is the *time* dimension, **Token Protection** is the *space* dimension. The Conditional Access feature, also referred to as "token binding," 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 "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" [@token-protection-learn].

<Definition term="Token Protection">
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'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].
</Definition>

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 `x-ms-RefreshTokenCredential` 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.

### Cloud Kerberos Trust

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 `AzureADKerberos` 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.

<Definition term="Cloud Kerberos Trust">
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'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].
</Definition>

The Microsoft Learn deployment guide is explicit about the AzureADKerberos object's role: "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't associated with any physical servers; Is only used by Microsoft Entra ID to generate TGTs for the Active Directory domain" [@cloud-kerberos-trust-learn]. The architectural property to notice is that the user's NTLM hash is *not* the binding key. Microsoft Entra ID never holds the on-prem NTLM hash; the cryptographic root is the AzureADKerberos RODC's keys, which Entra and the on-prem domain controller share without involving any user-side long-term secret.

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.

### The Azure AD to Microsoft Entra ID rename

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 "Microsoft Entra ID" throughout; in primary sources from before July 2023, the same product is "Azure AD." The rename is real, and it matters when citing older documentation, but it does not change the protocol surface.

### The seam restated

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.

> **Key idea:** 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.

A small comparison matrix makes the support story explicit.

| Resource / scenario | CAE-aware | Token Protection (Windows GA) | Cloud Kerberos Trust |
|---|---|---|---|
| Exchange Online | Yes | Yes | n/a |
| SharePoint Online | Yes | Yes | n/a |
| Microsoft Teams | Yes | Yes | n/a |
| Microsoft Graph | Yes | Not enforced | n/a |
| Azure Virtual Desktop | Partial | Yes | n/a |
| Windows 365 | Partial | Yes | n/a |
| On-prem file share | n/a | n/a | Yes |
| Browser (any Microsoft cloud) | Indirect via resource | No (native apps only) | n/a |

That is what the PRT does. But four sibling articles in this series describe identity surfaces the PRT does *not* cover. Before we celebrate the seam, we have to be honest about where it stops.

## 8. Where PRT is not the answer

The PRT carries device state, MFA state, and Conditional Access claims for the *cloud-mediated* 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.

Five surfaces the PRT does not cover, in the order operators most often confuse them:

**On-prem Kerberos via the on-prem KDC.** 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's downstream `kerberos.dll` ticket cache is populated by Kerberos AS_REQ/AS_REP exchanges between the workstation and the on-prem DC; the PRT lives in CloudAP's memory in `lsass` 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.

**Credential Guard and LSAISO.** [Credential Guard](/blog/the-empty-hash-credential-guard-the-lsaiso-trustlet-and-the-/), 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 *on-prem credential theft via long-term-key extraction from `lsass`.* The load-bearing distinction for the threat model is this: **PRT material does NOT live in LSAISO**. It lives in normal `lsass.exe` under CloudAP. Mollema's August 2020 extraction worked because the PRT's session-key handling is in the same address space as ordinary user processes that hold debug privilege; LSAISO did not move there. Treat "I have Credential Guard enabled" and "my PRT is hardware-isolated" as independent statements.

<Sidenote>The LSAISO isolation contract is for on-prem credentials -- NTLM hashes, Kerberos `krbtgt` keys, the kinds of long-term secrets that the 2010s-era "Pass-the-Hash" tooling was designed to extract. The PRT's session key is a per-PRT artifact that lives in CloudAP'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.</Sidenote>

**Adminless and local-admin removal.** "[Adminless](/blog/adminless-how-windows-finally-made-elevation-a-security-boun/)" 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 "who is signing in;" Adminless addresses "what they can do once signed in." Conflating them is a common rhetorical move in Microsoft documentation and a common source of confusion in audits.

**[App Identity](/blog/who-is-this-code----the-quiet-33-year-reinvention-of-app-ide/), managed identities, and workload identities.** 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.

**Remote Credential Guard versus Azure AD RDP sign-in.** 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. **Remote Credential Guard** redirects Kerberos credentials over the RDP hop: the client's TGT is reachable to the remote `mstsc` session via a CredSSP-mediated redirection mechanism, so that the remote session can fetch downstream service tickets without re-prompting. It does *not* transport PRT material across the connection. **Azure AD RDP sign-in** -- 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 *host* side, not as a redirection from the client.

> **Note:** If your threat model says "I am redirecting credentials over RDP, therefore my PRT is exposed," you are reading the Remote Credential Guard documentation wrong. Remote Credential Guard ferries Kerberos tickets between the client `mstsc` and the remote session host; the PRT lives in the client'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.

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.

## 9. Theoretical limits

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.

<PullQuote>
"DBSC will not prevent temporary access to the browser session while the attacker is resident on the user'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's device." -- W3C Web Application Security Working Group, Device Bound Session Credentials draft
</PullQuote>

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.

**1. The on-device-attacker floor is architectural.** A hardware-bound key whose *signing surface* 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 *off-device* 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.

**2. Non-TPM Windows reopens the pre-2021 attack class.** 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'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 `lsass` -- they are extracting the *root* of the derivation from disk. Microsoft Learn names "TPM 2.0 on Windows 10 1903 or higher" 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.

**3. Phishing-resistance inheritance is one-shot.** The PRT records the authentication strength of the *issuing* credential -- whether the user signed in with Hello for Business, a FIDO2 key, a password, or a password plus an MFA factor. The `mfa` 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 *not* 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.

**4. CAE coverage is not universal.** 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's risk surface is a CAE-unaware first- or third-party application, the deployment-time guarantee is the access token's natural lifetime, not 15 minutes.

**5. The PRT lifetime is 90 days by design.** 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'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.

> **Note:** To approximate the ideal -- a device-bound, near-real-time-revocable, phishing-resistant cross-app SSO credential -- a deployer composes: **PRT** (device binding) + **CAE** (near-real-time revocation) + **Token Protection** (per-resource device binding for native apps) + **Authentication Strengths** (Conditional Access policy that upgrades phishing resistance at issuance) + **DBSC** (per-origin web defense once it is available). No single artifact closes all five gaps; composition is the deployer's job, and the gaps in any one artifact are the joints another is supposed to cover.

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.

## 10. Open problems

Five open problems sit on the PRT model right now. None of them have a "just ship a patch" answer.

**Cookie-on-Demand on the live device.** The architectural defense is bounded by the §9 floor. Mollema's TROOPERS 22 talk makes the case that **trustlet-level isolation** of the PRT signing path -- moving the CloudAP cookie-construction code from normal `lsass` 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.

**Cross-vendor near-real-time revocation.** 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.

**DBSC and PRT composition for browser SSO.** Google'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 `login.microsoftonline.com`, the request will carry both a DBSC-bound short cookie (per-origin) and an `x-ms-RefreshTokenCredential` cookie from the WAM attachment path. Which binding wins, and how the two bindings are composed in the resource provider's evaluation, has not been publicly documented. The Stage 3 research found no Microsoft engineering blog explaining the contract.

<Sidenote>The Chrome developer documentation page on DBSC cites "Chrome 145" while the Google Security Blog post about DBSC GA cites "Chrome 146." 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].</Sidenote>

<Aside label="PRT, DBSC, and Token Protection in the same browser tab">
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 "this is how the browser proves device binding to Entra" 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.
</Aside>

**PRT-aware Conditional Access for AI agents and workload identities.** 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 -- "require compliant device, require MFA, require sign-in frequency under four hours" -- 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.

**PRT across RDP.** There is no clean "redirect PRT" primitive analogous to Remote Credential Guard'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 *new* PRT at the host -- but the client's PRT does not transit the RDP hop. Forensic and operational tooling that wants to know "what PRT does this remote user have, and is it the same as the client's?" has to query both endpoints separately. Active Microsoft work in this area is referenced in Mollema's TROOPERS 22 deck, but no public solution has shipped.

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.

## 11. Practical guide

Here is what you actually do with the PRT this week.

### Verifying PRT issuance

The operator-facing surface is `dsregcmd /status`, which prints the PRT state under the `SSO State` section. The three fields to read are `AzureAdPrt` (Yes if a PRT is present), `AzureAdPrtUpdateTime` (the timestamp of the last refresh), and `AzureAdPrtExpiryTime` (the absolute expiry on the current PRT, by default 90 days after issuance) [@prt-msft-learn] [@dsregcmd-troubleshoot].

<RunnableCode lang="js" title="dsregcmd /status: what to grep for (illustrative output parser)">{`
// Models the section of dsregcmd /status output you care about.
// On a real Windows host, you would run: dsregcmd /status | findstr AzureAdPrt
const sampleOutput = \`
+----------------------------------------------------------------------+
| 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/<tenant-id>
              EnterprisePrt : NO
\`;
const lines = sampleOutput.split('\\n').filter(l => l.match(/AzureAdPrt/));
console.log(lines.map(l => l.trim()).join('\\n'));
// Healthy: AzureAdPrt=YES and AzureAdPrtUpdateTime within the last 4 hours.
`}</RunnableCode>

If `AzureAdPrt` is `NO` 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's TPM is malfunctioning and CloudAP could not complete the issuance handshake. `dsregcmd /status` will print device-state diagnostics directly above the SSO State section that disambiguate these.

### Forcing PRT renewal

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 *not* generally force a new PRT mint; CloudAP treats unlock as a continuation event, not a fresh issuance.

### Hunting PRT-mediated sign-ins in Entra logs

In the Microsoft Entra audit and sign-in logs, the load-bearing fields are `authenticationDetails`, `authenticationProcessingDetails`, and the `IsCompliantDevice` and `DeviceDetail` claims attached to the sign-in event. A sign-in that rode the PRT path will surface a `PRT` indicator in `authenticationProcessingDetails`. In Microsoft Defender XDR's advanced-hunting tables, the corresponding views are `IdentityLogonEvents` (for on-prem and federated paths) and `AADSignInEventsBeta` (for native Entra sign-in events) [@defender-xdr-schema]. The latter is the table to query when looking for unusual `x-ms-RefreshTokenCredential`-driven sign-ins -- specifically, sign-ins from device-claim-bearing tokens whose `DeviceId` does not match the device's `DeviceId` in Intune.

### Conditional Access patterns

| Pattern | What it enforces | What it cannot enforce |
|---|---|---|
| Require compliant device | Sign-in only from devices Intune (or a partner MDM) reports as compliant | Whether the compliance signal is fresh; an attacker who can spoof an Intune compliance attestation passes |
| Require Microsoft Entra hybrid joined device | Sign-in only from hybrid-joined devices | Personal Entra-registered devices that meet compliance |
| Require MFA at sign-in | A fresh MFA factor at PRT issuance | Whether the MFA factor is phishing-resistant |
| Authentication Strengths (FIDO2-only) | Phishing-resistant credential at issuance, propagated as a strong `mfa` claim into the PRT | Downstream phishability through cookie theft (KDFv2 fix applies; on-device residual remains) |
| Token Protection for sign-in tokens | Device-bound assertion required for app-token requests | Browser sessions (DBSC is the per-origin counterpart) |
| Sign-in Frequency = 4 hours | Re-authentication every four hours | The 90-day PRT lifetime independent of sign-in cadence |

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.

### CAE enablement and tenant configuration

CAE was made the default for all Entra tenants at GA on 10 January 2022; the announcement explicitly noted that Microsoft "auto-enabled it for all tenants" [@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 `cp1` 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.

### Forensic indicators

Three signals deserve hunting attention:

- **Anomalous `x-ms-RefreshTokenCredential` cookie origins.** A sign-in where the cookie's IP geolocation does not match the device'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.
- **Device-claim-bearing tokens whose `DeviceId` does not match Intune state.** An attacker who lifted a PRT off-device cannot mint cookies post-KDFv2, but a cloned `DeviceId` 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.
- **`lsass` broker-process anomalies.** Mimikatz-class memory-reading tools typically attach to `lsass` 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 `Get-MpComputerStatus` and the EDR-specific equivalents.

### What NOT to do

> **Note:** 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.

<Spoiler kind="solution" label="A 60-second sanity check for an Entra-joined device">
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 "is my PRT working?" questions.
</Spoiler>

That is the PRT -- what it is, how it broke, how Microsoft fixed it, where it stops. Now the FAQ.

## 12. FAQ and closing

<FAQ title="Frequently asked questions">

<FAQItem question="Is the PRT the same as a Kerberos TGT?">
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.
</FAQItem>

<FAQItem question="Does the PRT replace NTLM and Kerberos?">
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 "NTLM-less" effort together describe a path that *reduces* reliance on NTLM, but they do not delete the on-prem authentication surface on day one.
</FAQItem>

<FAQItem question="Is the PRT cookie 'DKey-signed'?">
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's full payload via `SHA256(ctx || assertion_payload)` [@ms-oapxbc-jwt] [@dimi-3or-de-kdfv2].
</FAQItem>

<FAQItem question="Did dirkjanm.io disclose PRT extraction at DEF CON 2022?">
No. Dirk-jan Mollema'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'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 "DEF CON 2022" anchor that occasionally appears in summaries of the PRT-attack story is a memory error.
</FAQItem>

<FAQItem question="If my user has a PRT, are they still subject to Conditional Access?">
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].
</FAQItem>

<FAQItem question="Does Pluton replace the TPM in the PRT model?">
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.
</FAQItem>

<FAQItem question="What is the difference between Entra registered, Entra joined, and Entra hybrid joined for PRT purposes?">
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'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 "an interim step on the road to Microsoft Entra join" for organizations migrating away from on-prem AD [@entra-devices-overview].
</FAQItem>

</FAQ>

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.

<StudyGuide slug="entra-id-and-the-primary-refresh-token-how-azure-ad-sign-on-bridges-windows-logo" keyTerms={[
  { term: "Primary Refresh Token (PRT)", definition: "Device-bound JWT issued by Microsoft Entra ID to CloudAP at first interactive sign-in; cryptographic seam between Windows logon and Entra-mediated SSO." },
  { term: "CloudAP", definition: "Cloud Authentication Provider plugin framework in lsass.exe; the Entra ID plugin owns the device-side PRT lifecycle." },
  { term: "Device key (dkpub/dkpriv)", definition: "TPM-bound key pair that signs PRT issuance requests; registered with Entra ID at join time." },
  { term: "Transport key (tkpub/tkpriv)", definition: "TPM-bound key pair Entra ID uses to wrap session keys; only tkpriv can unwrap them on-device." },
  { term: "Session key", definition: "Symmetric proof-of-possession key for the PRT lifetime; signs cookies and app-token requests via SP800-108 KDF derivation." },
  { term: "x-ms-RefreshTokenCredential", definition: "HMAC-signed JWT cookie that carries PRT-derived authentication to login.microsoftonline.com from supported browsers." },
  { term: "KDFv2", definition: "Post-CVE-2021-33779 derivation rule that mixes SHA256(ctx || payload) into the cookie's signing-key derivation, closing off-device replay." },
  { term: "Continuous Access Evaluation (CAE)", definition: "Near-real-time revocation channel for OAuth access tokens; 15-minute event-propagation upper bound; CAEP-anchored claim-challenge protocol." },
  { term: "Token Protection", definition: "Conditional Access session control that requires device-bound assertions for app-token requests; the per-app analogue of PRT device binding." },
  { term: "Cloud Kerberos Trust", definition: "Bridge that lets a PRT-bearing device receive on-prem Kerberos TGTs from Entra ID via the AzureADKerberos virtual RODC object." }
]} questions={[
  { q: "Why is 'the PRT cookie is DKey-signed' wrong?", a: "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)." },
  { q: "What did CVE-2021-33779 fix, in one sentence?", a: "It introduced KDFv2, which binds the cookie'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." },
  { q: "What does the on-device-attacker floor mean for the PRT?", a: "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." },
  { q: "Where does the PRT NOT apply?", a: "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)." },
  { q: "How does CAE revoke an in-flight access token?", a: "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." }
]} />
