• Read the release note for Xcode 27 beta 6 (build 27A5252f, posted 10 August) and you’ll get exactly two links: downloads and release notes. No headline features, no deprecation drama. That’s normal for a beta 6 — this deep into the cycle Apple is stabilizing, not shipping new surface area.

    The trap is treating the thin note as “nothing to do here.” The build you don’t care about carries the iOS 27, iPadOS 27, macOS 27, watchOS 27, tvOS 27, and visionOS 27 SDKs. Those SDKs become the ones the App Store expects your submissions to be built against, and the identity APIs inside them have been shifting from optional to load-bearing all cycle. If your login stack still assumes iOS 17-era assumptions, this is the beta where you should be fixing that — not the week the GA drops in September.

    What you’re actually installing

    Xcode 27 beta 6 requires macOS 26 (Tahoe) or later on the Mac running it, and it’s the toolchain that produces binaries linked against the 27 SDKs. Confirm what you’ve got before you trust a build:

    xcodebuild -version
    # Xcode 27.0
    # Build version 27A5252f
    
    xcodebuild -showsdks | grep -iE "ios|macos"
    # iOS 27.0                        -sdk iphoneos27.0
    # macOS 27.0                      -sdk macosx27.0
    
    xcrun --sdk iphoneos27.0 --show-sdk-version
    # 27.0

    Apple’s pattern for the last several cycles: roughly six months after a major SDK ships, new App Store submissions must be built with it. For the iOS 26 SDK that deadline landed in spring 2026. Plan for the iOS 27 SDK to gate submissions around April 2027. That sounds far off until you remember how many identity flows you’d need to regression-test before flipping the compiler over.

    Automatic passkey upgrades stop being a demo

    The single biggest identity win in this SDK lineage isn’t new to 27 — it’s conditional passkey registration, and it’s finally mature enough to ship in production without babysitting. If your users still authenticate with a password, you can mint a passkey for them silently at sign-in, no modal, no interruption, provided the platform decides the moment is safe (device passcode set, iCloud Keychain available).

    import AuthenticationServices
    
    func upgradeToPasskey(userName: String,
                          userID: Data,
                          challenge: Data) {
        let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
            relyingPartyIdentifier: "example.com")
    
        let request = provider.createCredentialRegistrationRequest(
            challenge: challenge,
            name: userName,
            userID: userID)
    
        // The whole point: conditional == automatic upgrade.
        // The system creates the passkey only if it can do so silently.
        request.requestStyle = .conditional
    
        let controller = ASAuthorizationController(authorizationRequests: [request])
        controller.delegate = self
        controller.performRequests()
    }

    Two things bite people here. First, .conditional is silent by design — if your associated domain file is wrong or the webcredentials entitlement is missing, the request doesn’t error loudly, it just quietly does nothing. You’ll swear the API is broken. It isn’t; your apple-app-site-association is. Verify it directly:

    curl -s https://example.com/.well-known/apple-app-site-association \
      | python3 -m json.tool
    # Confirm the "webcredentials" key lists "TEAMID.com.your.bundleid"

    Second, this is table stakes now, not a differentiator. Android’s Credential Manager has offered conditional passkey creation for two cycles. If you’re a consumer-facing shop still forcing password-only, you’re behind both platforms, not ahead of one.

    Credential Exchange: the lock-in excuse is gone

    The quieter shift that started in the iOS 26 cycle and carries forward is the Credential Exchange Protocol (CXP) and its format sibling CXF — the FIDO Alliance standard for moving passkeys and passwords between credential managers without exporting plaintext to a CSV. On device it surfaces under Settings → General → Transfer or Reset, and Passwords → move accounts to another app.

    Why an identity architect should care: the number-one objection to standardizing on passkeys inside an enterprise was “we can’t get them back out if we switch password managers.” That objection is now technically false. If you’re a credential-manager vendor or building an enterprise password tool for Apple platforms, supporting CXP import/export is the difference between being a destination and being a roach motel. Users increasingly know the difference.

    The enterprise side: Platform SSO is where the real money is

    None of the developer APIs matter to a fleet admin if the Mac can’t get an identity in the first place. Platform SSO — the macOS Extensible Single Sign-On extension that lets a Mac authenticate against Entra ID, Okta, or Google directly at the login window — is the piece that’s genuinely matured across the 26/27 cycle, and it’s where I’d spend admin effort right now.

    The configuration that matters is AuthenticationMethod. Set it to UserSecureEnclaveKey and the user’s IdP authentication is backed by a hardware-bound key in the Secure Enclave — phishing-resistant, passwordless, and closer to what Windows Hello for Business does on the other side of the fence. Here’s the payload shape for a Microsoft Entra deployment:

    <dict>
        <key>PayloadType</key>
        <string>com.apple.extensiblesso</string>
        <key>PayloadIdentifier</key>
        <string>com.example.psso</string>
        <key>PayloadUUID</key>
        <string>E2C9F1A4-4A7B-4E1D-9F0C-3B2A1D6E8F00</string>
        <key>PayloadVersion</key>
        <integer>1</integer>
        <key>ExtensionIdentifier</key>
        <string>com.microsoft.CompanyPortalMac.ssoextension</string>
        <key>TeamIdentifier</key>
        <string>UBF8T346G9</string>
        <key>Type</key>
        <string>Redirect</string>
        <key>URLs</key>
        <array>
            <string>https://login.microsoftonline.com</string>
            <string>https://login.microsoft.com</string>
            <string>https://sts.windows.net</string>
        </array>
        <key>PlatformSSO</key>
        <dict>
            <key>AuthenticationMethod</key>
            <string>UserSecureEnclaveKey</string>
            <key>UseSharedDeviceKeys</key>
            <true/>
            <key>EnableCreateUserAtLogin</key>
            <true/>
        </dict>
    </dict>

    Verify registration actually took on an enrolled Mac — the extension will happily install and still not register the user:

    # Is the SSO extension loaded and which method is active?
    app-sso platform -s
    
    # Broader profile/identity state
    sudo profiles status -type enrollment
    

    The thing Apple’s documentation soft-pedals: EnableCreateUserAtLogin plus UseSharedDeviceKeys changes your account model on shared and new devices, and getting the ordering wrong against your IdP’s provisioning leaves you with local accounts that don’t line up with directory identities. Pilot it on a ring of ten machines before you push it to the fleet. Six months from now the admin who blanket-enabled passwordless Platform SSO without testing recovery paths is the one filing the “users locked out after IdP password reset” ticket.

    Digital credentials and the verification story

    Worth having on your radar for this SDK generation: the Digital Credentials verification path for ISO 18013-5 mobile driver’s licences and other documents in Wallet. If you’re building age or identity verification into an app, the platform now brokers a request to Wallet rather than you rolling your own camera-and-barcode nightmare, with the presentation gated behind Face ID or Touch ID and scoped to the specific fields you ask for. Request only the claim you need — over-18, not date of birth — because ATT-era users and, increasingly, regulators will punish apps that hoover up the full document when a boolean would do.

    The bottom line

    • Install beta 6 for the SDK, not the note. The changelog is empty; the toolchain is the point. Building against the 27 SDK now buys you six months of margin before it’s mandatory for submissions around April 2027.
    • Ship conditional passkey registration if you haven’t. It’s silent, it’s low-risk, and it’s now behind both Apple and Android as a default expectation. Check your apple-app-site-association first — that’s where 90% of “it doesn’t work” ends.
    • Admins: pilot Platform SSO with UserSecureEnclaveKey. This is the highest-leverage identity change available to an Apple fleet right now. Test IdP password-reset and account-recovery flows on a small ring before you scale.
    • Support Credential Exchange if you build credential tooling. The lock-in argument against enterprise passkeys is dead. Act like it.

    Betas this late are boring on purpose. The identity work they’re carrying is not.

  • The MSRC entry for CVE-2026-65787 updated today, and if you got paged about it, calm down. The change is an “acknowledgement” edit — Microsoft adjusted who gets credit for reporting the Desktop Window Manager elevation-of-privilege flaw. No revised CVSS, no new affected builds, no re-released cumulative update. Nothing you need to redeploy.

    So why write about it? Because “informational change only” is exactly the kind of line that gets a real vulnerability filed under “already handled” when, in a fair number of environments, it wasn’t. DWM EoP bugs are boring in the way SYSTEM-level privilege escalation is always boring: nobody breaks in through them, everybody finishes the job with them. That makes them worth a five-minute audit even when the news is a footnote.

    What DWM actually is, and why an EoP there hurts

    Desktop Window Manager is the compositor behind everything you see on a Windows desktop — window transparency, animations, the whole GPU-accelerated rendering pipeline. It runs as dwm.exe backed by dwmcore.dll and udwm.dll, and critically it processes input that low-privilege applications can influence. That’s the recurring problem: a component running with high privilege that parses data reachable from a sandboxed or standard-user context.

    An elevation-of-privilege bug here follows a predictable script. The attacker already has code running as a normal user — from a phishing payload, a malicious document, a compromised app. They don’t have admin. They trigger the DWM flaw, corrupt memory in a privileged context, and walk out with SYSTEM. Game over for that host: credential dumping, service installation, tampering with security tooling, the usual.

    The reason attackers love this class is that it’s the second stage they can rely on. Initial access is noisy and variable; a dependable local privilege escalation is gold. That’s precisely the profile that gets these bugs weaponised.

    This isn’t a hypothetical class

    DWM Core Library elevation flaws have been exploited in the wild before, and recently. In 2024, CVE-2024-30051 — a DWM Core Library heap-based buffer overflow leading to SYSTEM — was found being used in the wild, tied to activity delivering the QakBot loader. That one was a textbook example: the exploit was the elevation step in an existing infection chain, not the way in.

    So while CVE-2026-65787’s paperwork update is genuinely nothing, the underlying category has a demonstrated appetite from financially motivated crews and, historically, from targeted-intrusion actors who bundle a fresh LPE with each campaign. Treat any DWM EoP as “assume this becomes a post-exploitation tool” and you’ll rarely be wrong.

    My read: the vulnerability is real and the class is serious, but this specific news item is overhyped by whatever alert dragged you here. The action isn’t to panic — it’s to confirm your fleet is on the cumulative update that already carries the fix.

    Who’s exposed

    DWM ships with the OS, so any supported Windows client or server SKU running the affected component is in scope until patched via its monthly cumulative update. The exposure that matters is operational, not architectural: machines that miss cumulative updates, that are imaged from stale golden images, or that sit in “we’ll reboot it eventually” limbo. Because these fixes arrive inside the rollup, a single skipped Patch Tuesday leaves the door open — there’s no standalone hotfix to cherry-pick.

    If you’re unsure whether CVE-2026-65787 is covered by the build you’re running, don’t guess from the CVE page. Check the actual binary version and last-installed cumulative update on real endpoints.

    Audit it today

    Run this to pull the DWM binary version and the most recent cumulative/security update per host. It’s read-only — it reports, it changes nothing.

    #requires -Version 5.1
    # DWM patch-state audit. Report only. Makes no changes.
    
    $ErrorActionPreference = 'Stop'
    
    function Get-DwmPatchState {
        [CmdletBinding()]
        param([string]$ComputerName = $env:COMPUTERNAME)
    
        try {
            $dll = Join-Path $env:SystemRoot 'System32\dwmcore.dll'
            if (-not (Test-Path $dll)) {
                Write-Warning "dwmcore.dll not found on $ComputerName"
                return
            }
    
            $ver = (Get-Item $dll).VersionInfo.FileVersion
    
            # Most recent installed update (cumulative updates carry DWM fixes)
            $lastCu = Get-HotFix -ComputerName $ComputerName -ErrorAction Stop |
                      Where-Object { $_.InstalledOn } |
                      Sort-Object InstalledOn -Descending |
                      Select-Object -First 1
    
            [pscustomobject]@{
                Computer        = $ComputerName
                DwmCoreVersion  = $ver
                LastUpdateKB    = $lastCu.HotFixID
                LastUpdateDate  = $lastCu.InstalledOn
                OSBuild         = [System.Environment]::OSVersion.Version.ToString()
            }
        }
        catch {
            Write-Warning ("Failed on {0}: {1}" -f $ComputerName, $_.Exception.Message)
        }
    }
    
    # Single host
    Get-DwmPatchState | Format-Table -AutoSize
    
    # Fleet: feed a list, e.g.
    # Get-Content .\hosts.txt | ForEach-Object { Get-DwmPatchState -ComputerName $_ } |
    #   Export-Csv .\dwm-audit.csv -NoTypeInformation
    

    Cross-reference the reported DwmCoreVersion and LastUpdateKB against the “Security Updates” table on the MSRC page for CVE-2026-65787 — that table lists the exact KB and build number that first carried the fix for each OS. If a host’s last update predates that KB, it’s unpatched, full stop.

    Hunt for the abuse pattern

    Privilege escalation via DWM tends to leave behavioural traces even when the exploit itself is quiet. In Microsoft Defender for Endpoint, look for dwm.exe behaving unlike a compositor — spawning child processes, or a non-system parent chain producing a token elevation. This KQL is a starting hunt, not a finished detection; tune it to your baseline before alerting.

    // Defender Advanced Hunting - anomalous DWM process behaviour
    DeviceProcessEvents
    | where Timestamp > ago(7d)
    | where InitiatingProcessFileName =~ "dwm.exe"
    | where FileName !in~ ("dwm.exe", "conhost.exe")
    // dwm.exe almost never legitimately launches other executables
    | project Timestamp, DeviceName, AccountName,
              InitiatingProcessFileName, FileName, ProcessCommandLine,
              InitiatingProcessAccountSid
    | order by Timestamp desc
    

    For Sysmon shops, the equivalent is a process-create (Event ID 1) filter where ParentImage ends in dwm.exe and the child image is anything unexpected. Pair that with Event ID 4672 (special privileges assigned) landing on an account that shouldn’t be getting SYSTEM.

    Remediation, in priority order

    • Confirm the cumulative update is deployed. The fix for CVE-2026-65787 rides inside the monthly rollup for each affected OS. If your audit shows hosts behind the KB named on the MSRC page, get them current on the next reboot window. This is the only real remediation — there’s no config toggle that neutralises a memory-corruption EoP.
    • Fix the source, not just the fleet. If unpatched machines trace back to a golden image or a WSUS/Intune ring that stalled, patch the image and unstick the ring. Otherwise you re-provision the vulnerability into every new build.
    • Reduce the pre-conditions. DWM EoP needs an attacker already executing as a local user. Standard-user-by-default, application control (WDAC/AppLocker), and blocking the common initial-access delivery — macro-enabled docs, LNK droppers, loader families like the QakBot lineage — all raise the cost of ever reaching the escalation step.
    • Don’t re-patch over a paperwork edit. Today’s change is an acknowledgement. If your systems already have the KB, you are done. Re-running deployment against an informational revision just burns a maintenance window.

    Urgency, honestly

    If you’re already current on cumulative updates: no action, close the ticket. If your audit turns up hosts behind the fix KB, treat it as a next-patch-cycle item at worst and this week for anything internet-adjacent or handling privileged workloads — not because of today’s news, but because DWM elevation bugs are proven finishers in real intrusion chains and there’s no compensating control that fully replaces the patch.

    As for Microsoft’s posture: DWM has been hardened repeatedly, yet EoP flaws keep surfacing in it because it’s a large, privileged, input-facing surface — that’s structural, not sloppy. The cadence of these bugs isn’t obviously rising or falling; what’s changed is that attackers now bundle a fresh LPE into loader campaigns as a matter of course. Which means the boring advice wins again: keep the rollups flowing, and don’t let an “informational change only” lull you into assuming the patch actually landed.

  • Here’s a scene every hybrid-meeting admin has debugged at least once. A large conference room has a Teams Rooms on Android front-of-room bar driving the displays, plus an Android touch board on the table for whiteboarding and content. Both are Teams-certified endpoints. Both have a resource account. Someone starts the meeting on the touch board, someone else taps Join on the front-of-room console, and now the room is in the call twice — two participants, two audio pipelines, one glorious feedback loop until somebody mutes the wrong device and kills the room mic for everyone.

    That is the exact problem coordinated meetings solves, and roadmap item 569420 confirms it’s finally coming to Teams Rooms on Android and Android-based touch boards. The catch: general availability is slated for January CY2027. Windows-based Teams Rooms and Surface Hub have had this for years. Android is getting parity — eventually.

    What “coordinated meetings” actually does

    Coordinated meetings pairs two room devices so Teams treats them as a single logical room presence rather than two independent participants. Concretely, once you pair a front-of-room device with a companion touch console:

    • Coordinated join and leave — start or end the meeting on one device and the paired device follows. No double-join, no orphaned endpoint sitting in the lobby.
    • Split roles across the glass — the front-of-room display shows remote participants and shared content; the touch board becomes the collaboration surface (whiteboard, annotations, content-in) without both surfaces fighting over the same audio path.
    • One audio identity — the paired devices coordinate mic and speaker so you don’t get the echo cascade described above.

    If you’ve deployed a Surface Hub next to a Windows MTR, you already know the pattern. The news here is narrow but real: Android endpoints — which now make up a large share of new Teams Rooms deployments because the hardware is cheaper — join the club.

    My honest read: this is a catch-up feature, not an innovation. The interesting question isn’t whether coordinated meetings is good (it is), it’s why Android buyers spent years without it while Microsoft steered enterprises toward Android bars on cost. Plan your dual-device rooms accordingly and don’t let a vendor tell you Android has “full parity” today — it doesn’t until this ships.

    The part nobody puts on the roadmap card: licensing

    Coordinated meetings is a Teams Rooms Pro capability, and it needs Pro on both paired devices. A room running one Pro license and one Basic license won’t pair. Teams Rooms Basic is capped at 25 rooms per tenant and deliberately omits the advanced in-room experiences, coordinated meetings among them.

    So the spend lands before the feature does. If you’re standardizing dual-screen Android rooms for a 2027 rollout, you’re buying two Pro licenses per room now, during your FY26 planning cycle — not when GA hits. That’s the thing Microsoft isn’t loud about on the roadmap entry.

    Report what you’ve actually got, before you plan pairings

    Before anyone talks about pairing, you need an accurate inventory: which rooms run Android vs Windows, which have more than one Teams-certified device, and which resource accounts carry a Pro license. The Microsoft Graph Teamwork Devices API (currently beta) is the cleanest source for the device side. Use the Microsoft.Graph.Beta module — never the retired AzureAD or MSOnline modules.

    # Requires: Microsoft.Graph.Beta module
    # Scopes: TeamworkDevice.Read.All, Directory.Read.All, Organization.Read.All
    Connect-MgGraph -Scopes "TeamworkDevice.Read.All","Directory.Read.All","Organization.Read.All"
    
    # Pull ALL Teams-certified devices. -All handles paging for you;
    # the raw endpoint returns @odata.nextLink pages of 100.
    $devices = Get-MgBetaTeamworkDevice -All -ErrorAction Stop
    
    $report = foreach ($d in $devices) {
        # Device categories: collaborationBar, touchDisplay, teamsRoom, ipPhone, panel...
        # Android room bars usually surface as 'collaborationBar' or 'teamsRoom';
        # touch boards as 'touchDisplay'.
        try {
            $health = Get-MgBetaTeamworkDeviceHealth -TeamworkDeviceId $d.Id -ErrorAction Stop
        } catch {
            $health = $null
            Write-Warning "Health lookup failed for $($d.Id): $($_.Exception.Message)"
        }
    
        [pscustomobject]@{
            DeviceId       = $d.Id
            DisplayName    = $d.CurrentUser.DisplayName
            ResourceUPN    = $d.CurrentUser.UserPrincipalName
            DeviceType     = $d.DeviceType
            HardwareModel  = $d.HardwareDetail.Model
            Manufacturer   = $d.HardwareDetail.Manufacturer
            Platform       = $d.HardwareDetail.UniqueId  # correlate to OS via model
            HealthStatus   = $health.HealthStatus
            ActivityState  = $d.ActivityState
        }
    }
    
    # Rooms with more than one device = your coordinated-meeting candidates
    $report | Group-Object ResourceUPN | Where-Object Count -gt 1 |
        Select-Object Name, Count | Sort-Object Count -Descending
    
    $report | Export-Csv .\TeamsRoomDeviceInventory.csv -NoTypeInformation
    

    Grouping by resource account only gets you part of the way — coordinated pairs typically use two different resource accounts in the same physical room, so cross-reference against your room-naming convention or the room list. Which brings us to the license check.

    # Confirm which room resource accounts hold Teams Rooms Pro.
    # Pro SKU part number: Microsoft_Teams_Rooms_Pro
    $proSku = Get-MgSubscribedSku -All |
        Where-Object SkuPartNumber -eq 'Microsoft_Teams_Rooms_Pro'
    
    $roomAccounts = Get-MgUser -All -Filter "accountEnabled eq true" `
        -Property Id,UserPrincipalName,DisplayName,AssignedLicenses |
        Where-Object { $_.UserPrincipalName -like 'room-*' -or $_.DisplayName -like '*Room*' }
    
    $roomAccounts | ForEach-Object {
        [pscustomobject]@{
            Room       = $_.DisplayName
            UPN        = $_.UserPrincipalName
            HasPro     = ($_.AssignedLicenses.SkuId -contains $proSku.SkuId)
        }
    } | Sort-Object HasPro | Format-Table -AutoSize
    

    Any candidate room where one device’s account shows HasPro = False is a room that won’t support coordinated meetings until you fix the license. That’s your gap list.

    Assigning the missing Pro licenses — dry run first, always

    Do not pipe a live Graph query straight into a license assignment. Export the gap list, eyeball it, and feed the reviewed CSV back in. The script below defaults to a dry run and touches nothing until you explicitly pass -Execute.

    param(
        [string]$InputCsv = ".\ProGaps-Reviewed.csv",
        [switch]$Execute   # omit this and the script only reports
    )
    
    $proSku = (Get-MgSubscribedSku -All |
        Where-Object SkuPartNumber -eq 'Microsoft_Teams_Rooms_Pro').SkuId
    
    Import-Csv $InputCsv | ForEach-Object {
        $target = $_.UPN
        if (-not $Execute) {
            Write-Host "[DRY RUN] Would assign Teams Rooms Pro to $target" -ForegroundColor Yellow
            return
        }
        try {
            Set-MgUserLicense -UserId $target `
                -AddLicenses @{ SkuId = $proSku } `
                -RemoveLicenses @() -ErrorAction Stop
            Write-Host "[APPLIED] Pro assigned to $target" -ForegroundColor Green
        } catch {
            Write-Warning "FAILED for $target : $($_.Exception.Message)"
        }
    }
    

    Run it once with no switch, read every line, then re-run with -Execute. There is no undo button on a bulk license change that strips something you didn’t mean to touch.

    Where you’ll configure the pairing itself

    The actual pairing is not a PowerShell operation — it’s device configuration. When the feature ships you’ll enable it in two places:

    • On the device: Teams Rooms on Android settings → Coordinated meetings, where you nominate the paired device’s account and set which device owns front-of-room vs console roles.
    • Centrally, in the Teams Rooms Pro Management portal (pro.teams.microsoft.com) and the Teams admin center under Teams Rooms → Android, where you’ll manage configuration profiles, firmware, and health at scale rather than walking room to room.

    The wider Android room story you should be planning around

    Coordinated meetings doesn’t arrive in isolation. Several Android room workstreams are converging, and they touch the same admin muscle:

    • AOSP management via Intune. Microsoft is moving Teams Rooms on Android off legacy Android Device Administrator enrollment toward AOSP-based management. If your MDM posture still assumes Device Administrator, that assumption has an expiry date. Get your Android room enrollment strategy onto Intune AOSP now.
    • Cloud IntelliFrame and multi-stream on Android. The intelligent speaker-framing and multi-camera experiences that shipped on Windows first are landing on Android endpoints, which is part of why the platform gap is closing.
    • Teams Rooms Pro Management parity. The centralized management, analytics, and health monitoring that Windows rooms enjoy continue to expand coverage for Android fleets — the same portal, more device types.

    The through-line: Android Teams Rooms are being pulled up to feature and management parity with Windows, and coordinated meetings is one visible marker on that road. Budget for Pro licensing across dual-device rooms, and get your Intune AOSP enrollment sorted regardless of coordinated meetings, because that migration will bite fleets that ignore it.

    What to do this quarter

    1. Inventory now. Run the Graph Teamwork device report and flag every room with two certified endpoints. That’s your coordinated-meetings target list.
    2. Close the license gaps. Confirm Pro on both devices in every candidate room. This is the real dependency and the one with lead time — do it in FY26 planning, not in January 2027.
    3. Fix enrollment. Move Android rooms to Intune AOSP management independent of this feature. It’s the bigger operational shift.
    4. Don’t over-promise the date. GA is January 2027 and Microsoft roadmap dates slip. Design the rooms, buy the licenses, but keep the “single-join room” wording out of your user comms until it’s actually in your tenant.

    Coordinated meetings is a genuinely good fix for a genuinely annoying problem. Just remember what the roadmap card doesn’t say: the feature is free with a license you’re already paying a premium for, on both devices, and the value only shows up in rooms you’ve bothered to pair correctly. Inventory first. Everything else follows from that.

  • Someone in your finance department installs a “smart invoicing” app from a vendor demo. The consent dialog says it wants to “Read and write financials data.” They click Accept because they always click Accept. Six weeks later that vendor has a persistent OAuth token that can read your entire chart of accounts, post journal entries, and pull every customer invoice — and it never touched a firewall, a VPN, or an admin.

    That’s the actual story behind the Entra changelog line that reads “Added financials APIs for Dynamics 365 Business Central.” It’s filed under a Graph API reference and it looks like ERP plumbing that has nothing to do with identity. It has everything to do with identity. Every endpoint Microsoft adds to Graph is backed by an Entra permission, and permissions are the thing your users hand out for free.

    What actually shipped

    The Financials API for Dynamics 365 Business Central is now exposed under the Microsoft Graph v1.0 endpoint — general availability, not preview. It surfaces resources you’d expect from an ERP: companies, accounts, customers, vendors, salesInvoices, journals, generalLedgerEntries, and the rest of the ledger. The reference lives under the Graph dynamics-graph-reference resource set.

    Who’s affected: any tenant with Dynamics 365 Business Central licensed and provisioned. If you don’t run Business Central, this API is inert in your tenant — the permission exists in the catalog but there’s nothing behind it to grant access to. If you do run Business Central, your app registration and consent posture just gained a new attack surface that reads money.

    The permission that gates it is Financials.ReadWrite.All, published on the Microsoft Graph resource application (00000003-0000-0000-c000-000000000000) as both a delegated scope and an application role. There is no read-only variant. That’s the first thing Microsoft isn’t shouting about: it’s read/write or nothing. An app that only needs to display invoices on a dashboard still asks for the ability to post to your ledger, because Microsoft never split the scope.

    Why this is better than the old way (and where it still bites)

    The genuine improvement is real. Before this, integrating Business Central meant its own OData/SOAP web services, per-environment service accounts, and basic-auth API keys that got pasted into config files and never rotated. Moving Financials onto Graph means:

    • One token model. The same OAuth 2.0 / Entra token that governs Exchange, SharePoint, and Teams now governs your ERP. Conditional Access, token lifetime, and revocation apply uniformly instead of Business Central being an island with its own auth.
    • Workload identity governance. Because access runs through a service principal, you can put it under Conditional Access for workload identities, apply risk-based blocking, and audit it in the sign-in logs — none of which the legacy web-service keys supported.
    • No standing secrets in code. App-only access uses certificates or federated identity credentials, so you can finally kill the basic-auth key that’s been in someone’s PowerShell script since 2021.

    Against a competing stack — say, a third-party iPaaS bridging QuickBooks or SAP with bearer tokens minted outside your directory — the Graph model wins on one thing that matters: the token lives in your tenant and dies when you revoke it. You are never phoning a vendor to ask them to please stop having access.

    The part that bites in six months: consent sprawl. The moment Financials is a Graph scope, it’s in the same consent prompt pool as every low-risk scope, and your default user consent settings decide whether a finance clerk can grant it to a random multi-tenant app without an admin ever seeing it.

    The adjacent changes that make this urgent

    This API doesn’t land in a vacuum. Three things in the current Entra surface change how you should treat it:

    1. Azure AD Graph is gone — so this is your only ledger API path

    The retirement of the legacy Azure AD Graph endpoints is complete, and Microsoft has been steadily forcing apps onto Microsoft Graph. If you were putting off consolidating ERP integrations, there’s no longer a legacy path to fall back on. Everything routes through Graph permissions now, which means your Graph permission hygiene is your integration security posture.

    2. The Microsoft.Entra PowerShell module is GA

    The Microsoft.Entra module reached general availability and is the intended successor to the deprecated AzureAD and MSOnline modules — both of which are retired and will stop authenticating. If your app-audit scripts still start with Connect-AzureAD, they’re on borrowed time. Everything below uses Microsoft.Graph, which is fully supported and interoperable.

    3. App consent policies and the admin consent workflow

    Microsoft’s recommended default — and the one you should already have on — restricts non-admin users to consenting only to apps from verified publishers requesting low-impact permissions. Financials.ReadWrite.All is not low impact. If your tenant still runs the old “users can consent to all apps” setting, a finance user can grant ledger access with two clicks. Check this before you do anything else.

    Audit what can touch your ledger

    Before you worry about new grants, find out what already holds Financials access. This script reports every service principal with the application permission and every delegated grant — with pagination and error handling, read-only.

    #Requires -Modules Microsoft.Graph.Applications, Microsoft.Graph.Authentication
    
    # Read-only audit of who can reach Business Central Financials via Graph
    Connect-MgGraph -Scopes 'Application.Read.All','Directory.Read.All','DelegatedPermissionGrant.Read.All' -NoWelcome
    
    $graphAppId   = '00000003-0000-0000-c000-000000000000'  # Microsoft Graph
    $targetScope  = 'Financials.ReadWrite.All'
    
    try {
        $graphSp = Get-MgServicePrincipal -Filter "appId eq '$graphAppId'" -ErrorAction Stop
    }
    catch {
        Write-Error "Could not resolve the Microsoft Graph service principal: $($_.Exception.Message)"
        return
    }
    
    # Resolve the app role (application permission) id for Financials.ReadWrite.All
    $appRole = $graphSp.AppRoles | Where-Object { $_.Value -eq $targetScope }
    if (-not $appRole) {
        Write-Warning "'$targetScope' is not published in this tenant's Graph catalog. Nothing to audit."
        return
    }
    
    Write-Host "=== Application (app-only) grants of $targetScope ===" -ForegroundColor Cyan
    
    # App role assignments TO Microsoft Graph, filtered to the Financials role
    $appGrants = Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $graphSp.Id -All -ErrorAction SilentlyContinue |
        Where-Object { $_.AppRoleId -eq $appRole.Id }
    
    if (-not $appGrants) {
        Write-Host "  None." -ForegroundColor Green
    }
    else {
        foreach ($g in $appGrants) {
            [pscustomobject]@{
                Type         = 'Application'
                PrincipalId  = $g.PrincipalId
                DisplayName  = $g.PrincipalDisplayName
                GrantedOn    = $g.CreatedDateTime
                AssignmentId = $g.Id
            }
        }
    }
    
    Write-Host "`n=== Delegated grants of $targetScope ===" -ForegroundColor Cyan
    
    # OAuth2 delegated grants against Graph, matched on the scope string (paged)
    $delegated = Get-MgOauth2PermissionGrant -All -Filter "resourceId eq '$($graphSp.Id)'" -ErrorAction SilentlyContinue |
        Where-Object { $_.Scope -match [regex]::Escape($targetScope) }
    
    if (-not $delegated) {
        Write-Host "  None." -ForegroundColor Green
    }
    else {
        foreach ($d in $delegated) {
            $clientSp = Get-MgServicePrincipal -ServicePrincipalId $d.ClientId -ErrorAction SilentlyContinue
            [pscustomobject]@{
                Type        = 'Delegated'
                ClientApp   = $clientSp.DisplayName
                ClientId    = $d.ClientId
                ConsentType = $d.ConsentType   # AllPrincipals = admin-consented tenant-wide
                PrincipalId = $d.PrincipalId    # null when AllPrincipals
                GrantId     = $d.Id
            }
        }
    }
    
    Disconnect-MgGraph | Out-Null
    

    Feed that into | Format-Table -AutoSize or | Export-Csv. The ConsentType of AllPrincipals is the one to stare at — it means an admin granted the app access on behalf of the whole tenant, so every user’s Business Central context is reachable through that client.

    Check your consent default, then close the door

    Reporting is half the job. Here’s the audit for your tenant-wide user consent policy — read-only — so you know whether a clerk can grant Financials without you:

    #Requires -Modules Microsoft.Graph.Identity.SignIns, Microsoft.Graph.Authentication
    Connect-MgGraph -Scopes 'Policy.Read.All' -NoWelcome
    
    $auth = Get-MgPolicyAuthorizationPolicy -ErrorAction Stop
    [pscustomobject]@{
        AllowUserConsentForApps = $auth.DefaultUserRolePermissions.PermissionGrantPoliciesAssigned
        Note = 'Empty array = users cannot consent. "ManagePermissionGrantsForSelf.microsoft-user-default-low" = low-impact only (recommended).'
    } | Format-List
    
    Disconnect-MgGraph | Out-Null
    

    If you decide to revoke a specific risky delegated grant, do it deliberately — never pipe a live query straight into a delete. This wrapper defaults to a dry run and forces you to opt in:

    function Revoke-FinancialsGrant {
        [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]
        param(
            [Parameter(Mandatory)][string]$GrantId,
            [switch]$Execute   # nothing happens without this
        )
        # Connect-MgGraph -Scopes 'DelegatedPermissionGrant.ReadWrite.All' first
        if (-not $Execute) {
            Write-Host "DRY RUN: would remove OAuth2 grant $GrantId. Re-run with -Execute to apply." -ForegroundColor Yellow
            return
        }
        if ($PSCmdlet.ShouldProcess($GrantId, 'Remove delegated permission grant')) {
            try   { Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId $GrantId -ErrorAction Stop
                    Write-Host "Removed $GrantId." -ForegroundColor Green }
            catch { Write-Error "Failed to remove $GrantId : $($_.Exception.Message)" }
        }
    }
    

    Where to verify this in the admin center

    • Enterprise applications → Consent and permissions → User consent settings — confirm it’s set to “Allow user consent for apps from verified publishers, for selected permissions.” Turn on the admin consent workflow under the same node so risky requests route to you instead of dying silently.
    • Enterprise applications → [app] → Permissions — read the granted Graph permissions for any Business Central connector; Financials.ReadWrite.All should be there if the app touches the ledger.
    • Identity → Monitoring & health → Sign-in logs → Service principal sign-ins — watch for the connector’s app-only sign-ins to confirm what’s actually calling the API versus what merely holds the permission.
    • Protection → Conditional Access → Workload identities — scope a policy to the connector’s service principal to block it from unexpected IP ranges.

    Bottom line

    1. Run the audit script today if you have Business Central. You want the list of principals holding Financials.ReadWrite.All before an auditor asks for it.
    2. Fix your user consent default if it still allows all apps. This single setting decides whether ledger access is a self-service giveaway.
    3. Turn on the admin consent workflow so Financials requests reach a human.
    4. Retire legacy Business Central web-service keys and move integrations onto Graph app-only auth with certificates or federated credentials.
    5. Migrate your audit tooling off AzureAD/MSOnline — they’re retired — onto Microsoft.Graph or GA Microsoft.Entra.

    The API is a genuine upgrade over pasted-in keys. But Microsoft shipped a read/write-only scope into the same consent pool as calendar-read permissions, and left the door-lock setting up to you. Go check the lock.

  • OpenAI Wants to Write the Rules It’s About to Break

    A new OpenAI blog called AI Futures promises big thinking about power, governance, and freedom. It arrives from the lab least trusted to hold any of them.

    The company that gutted its own nonprofit oversight in 2024 now wants to tell you how AI should govern the world.

    That’s the subtext of AI Futures, OpenAI’s new blog exploring how transformative AI could reshape power, governance, the economy, and individual freedom. The essays are genuinely thoughtful. They’re also a bank robber publishing a paper on vault security. Both things are true at once, and the second one is why this launch matters more than the prose inside it.

    What it actually is

    Strip away the framing and AI Futures is a house-published series of policy and philosophy essays. No new model. No benchmark. No API change. It’s OpenAI staking a claim on the narrative of what comes after the models get scary-good — who holds power, who gets displaced, what freedom means when a machine can do most cognitive work.

    Those are the right questions. OpenAI is not the only lab asking them, and it’s not the best at it. Anthropic has been doing this work with receipts for over a year. Its Economic Index ships actual anonymized data on how Claude is used across occupations — real numbers about which jobs are getting automated versus augmented, updated over time. Dario Amodei’s “Machines of Loving Grace” laid out a concrete, falsifiable vision of AI’s upside. Google DeepMind publishes a versioned Frontier Safety Framework with capability thresholds you can point to.

    OpenAI’s contribution, so far, is prose. Well-written prose that arrives conveniently detached from data. That’s the tell.

    The credibility problem nobody at OpenAI will name

    Here’s what makes AI Futures land funny. This is the same company that:

    • Restructured to strip meaningful control from the nonprofit board that was supposed to keep it honest, converting the for-profit arm into a public benefit corporation with investors holding real leverage.
    • Watched its entire original safety leadership walk out the door — Jan Leike, Ilya Sutskever, and much of the Superalignment team, which was then dissolved after being promised 20% of compute it reportedly never got.
    • Used aggressive non-disparagement clauses that threatened departing employees’ vested equity, until public exposure forced a walk-back.

    Now it’s publishing essays on individual freedom and the concentration of power. When the lab most responsible for concentrating AI power writes think-pieces warning about the concentration of AI power, that’s not thought leadership. It’s narrative pre-positioning ahead of regulation.

    Head-to-head: who’s actually credible on this

    If you’re going to read one lab’s take on AI’s political and economic future, read Anthropic’s, and it isn’t close.

    Anthropic backs claims with published data (the Economic Index), a versioned Responsible Scaling Policy with hard capability triggers, and a track record of holding models back — it delayed capabilities and shipped ASL-3 protections around Claude Opus 4 when its own evals flagged uplift risk. You can argue with the conclusions, but the work is auditable.

    Google DeepMind comes second: the Frontier Safety Framework is concrete and versioned, though the essays sit closer to research than public discourse.

    OpenAI comes third on credibility despite frequently leading on raw capability. AI Futures is smart writing unmoored from mechanism. There’s no “here’s the data, here’s the threshold, here’s what we’ll do.” It’s vibes about governance from the company with the worst governance story in the industry.

    Winner: Anthropic. Not because its models are always ahead — the GPT-5 and Claude Opus generations trade blows on SWE-bench Verified in the mid-70s, close enough that the coding-benchmark race is basically a tie — but because on the specific question AI Futures claims to own, only one lab shows its work.

    What to watch in the next 3–6 months

    This blog is a leading indicator, not an endpoint. Track these:

    • Regulatory timing. Expect AI Futures posts to align suspiciously well with EU AI Act enforcement milestones and any renewed US federal push. When a lab starts publishing on “governance,” a lobbying position is usually forming underneath it.
    • The agent authorization fight. As GPT-5-class agents get real permissions — spending money, sending email, touching production systems — the actual governance question isn’t philosophical. It’s OAuth. Who authorizes an AI agent to act as you, and how do you revoke it? Watch for OpenAI to tie AI Futures rhetoric to concrete identity and delegation tooling. That’s where “individual freedom” gets operational.
    • Anthropic’s counter. Expect a new Economic Index drop with harder displacement numbers. Data beats essays.
    • Whether OpenAI publishes anything falsifiable. If AI Futures ever ships a threshold, a commitment, or a dataset instead of a manifesto, take it seriously. Until then, read it as strategy.

    Do something more useful than reading essays

    You don’t have to wait for a lab to tell you how AI is reshaping your job. Measure it. Pull your own usage data and see what you’re actually offloading to a model versus what you still do yourself — that’s your personal economic index. Here’s a starting point against the OpenAI API:

    import os
    from openai import OpenAI
    
    client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
    
    # Classify your last week of AI tasks: augmentation vs automation
    tasks = [
        "drafted a client proposal",
        "wrote and shipped a unit test suite",
        "summarized a 40-page contract",
        "generated marketing copy I sent unedited",
    ]
    
    resp = client.responses.create(
        model="gpt-5",
        input=(
            "For each task, label it AUGMENTATION (human still in loop) "
            "or AUTOMATION (no human review). Return JSON with a one-line "
            "reason each.\n\n" + "\n".join(f"- {t}" for t in tasks)
        ),
    )
    
    print(resp.output_text)
    

    Run that weekly. The ratio of automation to augmentation in your own workflow tells you more about AI’s impact on your life than any lab’s blog about power and freedom. Then compare it against Anthropic’s public Economic Index to see where you sit versus your whole occupation.

    The bottom line

    AI Futures is worth reading — critically, the way you’d read a company’s sustainability report. The questions are real, some of the writing is sharp, and OpenAI does sit at the center of the story it’s narrating. That’s exactly the problem. The lab with the most power to shape AI’s political future is now shaping the conversation about it, and it’s the one whose own governance collapsed under the first real test. Read the essays. Trust the data. Those aren’t the same source.

  • The Excel RCE That Got a Footnote Edit — and Why the Bug Underneath Still Matters
    The Excel RCE That Got a Footnote Edit — and Why the Bug Underneath Still Matters

    Here’s the anticlimax up front: the “update” Microsoft pushed to the CVE-2026-68801 page changes exactly one thing — who gets credited for reporting the bug. The Security Update Guide flags it as an informational change only. No new patch, no revised severity, no expanded affected-products list. If your patch pipeline flagged this and paged someone at 2 a.m., you can go back to sleep.

    So why write about it at all? Because the acknowledgement edit is a decent excuse to check whether you actually deployed the underlying fix — an Excel remote code execution vulnerability, which is not a class of bug you want lingering on endpoints. Metadata churn on MSRC pages is routine and boring. The RCE it points at is neither.

    What the CVE actually is

    CVE-2026-68801 is tracked by Microsoft as a remote code execution flaw in Microsoft Excel. Microsoft, as usual, doesn’t publish exploit internals in the advisory, and I’m not going to invent a mechanism I can’t confirm. But the shape of these bugs is extremely consistent across years of Patch Tuesdays, so here’s the honest read on the class rather than fabricated specifics:

    • Excel RCEs are almost always memory-corruption bugs — use-after-free, type confusion, or heap overflow triggered while the parser chews through a malformed spreadsheet (XLS, XLSX, XLSB, or one of the legacy binary formats Excel still opens without complaint).
    • The attack vector is opening a crafted file. That means phishing attachments, files pulled from a compromised share, or a link that lands a document in the Downloads folder. “Remote” here does not mean unauthenticated network worm — it means the code runs when the victim opens the thing.
    • Execution happens in the context of the user running Excel. On a workstation where the user is a local admin — still depressingly common — that’s game over for the machine. On a properly least-privileged box, it’s a foothold, not a checkmate.

    One detail worth confirming against the live advisory rather than assuming: check the “Access Vector” and whether the Preview Pane is listed as an attack vector. For some Office file-format bugs it is, which drops the required user interaction from “open the file” to “click it once in Explorer.” That materially changes your urgency. Read the actual CVE page’s exploitability assessment — “Exploitation More Likely” versus “Less Likely” is the number that should drive your timeline, not the CVSS score.

    Who’s exposed

    If Microsoft shipped this in a monthly rollup, the affected footprint is the usual Office spread: Microsoft 365 Apps (Click-to-Run), the perpetual-license Office 2016 / 2019 / 2021 / 2024 builds, and standalone Excel installs. I’m not going to quote a specific fixed build number here because I can’t verify the exact one for this CVE — pull it from the advisory’s “Security Updates” table, which lists the KB and the minimum patched version per channel.

    The practical exposure map:

    • Managed M365 Apps machines on Current or Monthly Enterprise Channel — likely already patched if your auto-update is healthy. Verify, don’t assume.
    • Volume-license Office installs that rely on WSUS/SCCM/Intune — these lag, and this is where you’ll find the stragglers.
    • Kiosks, shared terminals, and that one finance workstation nobody reboots — the classic long tail.

    Audit what you’ve actually got deployed

    Before you touch remediation, find out where you stand. This PowerShell reports the installed Click-to-Run version, Protected View posture, and the Attack Surface Reduction rules that blunt Office-spawned payloads. It’s read-only — nothing here changes state.

    #requires -Version 5.1
    # Excel / Office exposure audit - REPORT ONLY, makes no changes
    $ErrorActionPreference = 'Stop'
    
    function Get-OfficeC2RVersion {
        $key = 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration'
        try {
            $c = Get-ItemProperty -Path $key -ErrorAction Stop
            [PSCustomObject]@{
                Product     = 'Office Click-to-Run'
                Version     = $c.VersionToReport
                Channel     = $c.CDNBaseUrl
                InstallType = 'C2R'
            }
        } catch {
            Write-Warning "No Click-to-Run install found (MSI/volume license may be present instead)."
            $null
        }
    }
    
    function Get-ExcelProtectedView {
        # Checks the current user's hive; run per-user for full coverage
        $ver = @('16.0')   # Office 2016+ all report 16.0
        foreach ($v in $ver) {
            $pv = "HKCU:\SOFTWARE\Microsoft\Office\$v\Excel\Security\ProtectedView"
            try {
                $p = Get-ItemProperty -Path $pv -ErrorAction Stop
                [PSCustomObject]@{
                    DisableInternetFilesInPV = $p.DisableInternetFilesInPV
                    DisableUnsafeLocationsInPV = $p.DisableUnsafeLocationsInPV
                    DisableAttachmentsInPV     = $p.DisableAttachmentsInPV
                }
            } catch {
                Write-Warning "Protected View keys not set for $v (defaults apply = Protected View ON)."
            }
        }
    }
    
    function Get-RelevantASR {
        try {
            $pref = Get-MpPreference -ErrorAction Stop
            # 'Block all Office applications from creating child processes'
            $ruleId = 'D4F940AB-401B-4EFC-AADC-AD5F3C50688A'
            $ids    = $pref.AttackSurfaceReductionRules_Ids
            $acts   = $pref.AttackSurfaceReductionRules_Actions
            if (-not $ids) { Write-Warning 'No ASR rules configured.'; return }
            for ($i=0; $i -lt $ids.Count; $i++) {
                if ($ids[$i] -eq $ruleId) {
                    $state = switch ($acts[$i]) {0{'Disabled'}1{'Block'}2{'Audit'}6{'Warn'}default{'Unknown'}}
                    [PSCustomObject]@{ Rule='Office child process'; State=$state }
                }
            }
        } catch {
            Write-Warning "Defender not available or Get-MpPreference failed: $($_.Exception.Message)"
        }
    }
    
    Write-Host "== Office version ==" -ForegroundColor Cyan
    Get-OfficeC2RVersion | Format-List
    Write-Host "== Excel Protected View ==" -ForegroundColor Cyan
    Get-ExcelProtectedView | Format-List
    Write-Host "== Relevant ASR rule ==" -ForegroundColor Cyan
    Get-RelevantASR | Format-Table -AutoSize
    

    Compare the reported VersionToReport against the fixed build in the advisory. Anything lower is unpatched. For fleet-wide reporting, run the same logic through a Defender advanced hunting query against DeviceTvmSoftwareVulnerabilities — Microsoft’s own vuln management will list CVE-2026-68801 by device once the definition propagates.

    Remediation, in priority order

    1. Deploy the update. For Click-to-Run, force it: "C:\Program Files\Common Files\Microsoft Shared\ClickToRun\OfficeC2RClient.exe" /update user. For volume-license, push the KB via your management stack. This is the actual fix; everything below is compensating control.
    2. Confirm Protected View is on for internet, unsafe-location, and attachment files. It’s the default, but it gets turned off by well-meaning users who got tired of the yellow bar. Protected View opens untrusted files in a sandbox, which defeats the “open and pop” path for most of these bugs.
    3. Enable the ASR rule that blocks Office apps from spawning child processes — Audit first, then Block once you’ve confirmed no legitimate macro workflow depends on it. This won’t stop in-process code execution, but it stops the common next stage (Excel launching PowerShell or cmd).
    4. Keep Mark-of-the-Web enforcement intact so files from email and browsers actually inherit the untrusted zone that triggers Protected View. If you strip MOTW somewhere in your file pipeline, you’re quietly disarming the sandbox.

    None of these steps are irreversible, but flip the ASR rule to Block only after an audit window — going straight to Block on a finance team that lives in macro-heavy workbooks will generate the kind of helpdesk tickets that get security controls rolled back.

    The honest verdict

    Office file-format RCEs are not going away, and Excel is the perennial worst offender because it parses the most legacy binary formats and has the deepest, oldest C++ parsing code. Expect several more of these per year — that’s the baseline, not an anomaly. Microsoft has genuinely narrowed the blast radius over the last few years: Protected View, blocking macros from the internet by default, and MOTW propagation mean a single memory-corruption bug no longer translates cleanly into mass compromise the way it did a decade ago. The bugs keep coming; the exploitation ceiling has dropped. Both things are true.

    As for this specific event — an acknowledgement update is exactly what it says on the tin, and treating it as a security event would be theater. The right move is unglamorous: use it as a prompt to confirm the real patch landed, because “informational change only” on a memory-corruption RCE still assumes you fixed the memory-corruption RCE.

    Urgency: the acknowledgement change is zero-priority. The underlying patch is a next-patch-cycle-at-latest item for hardened, least-privileged fleets — but pull it forward to this week if the advisory rates exploitation “More Likely,” lists Preview Pane as a vector, or if you’ve got local-admin users opening attachments from outside. That combination is how a click-to-open bug becomes an incident.

  • Copilot Now Remembers Your Users — and Purview Retention Is How You Prove What It Forgot
    Copilot Now Remembers Your Users — and Purview Retention Is How You Prove What It Forgot

    Picture the litigation hold email landing in your inbox. Legal wants to know what Microsoft 365 Copilot “knew” about a departing employee three months ago — the inferred preferences, the project associations, the saved facts that shaped every answer Copilot gave them. You go looking. And there’s nothing to find, because Copilot memory is a living document that overwrites itself as it learns. The version that mattered is gone.

    That gap is what Microsoft is closing. Roadmap item 569612 — “Data Lifecycle Management: Retention for Copilot Memory” — reaches general availability in September 2026, and it turns Copilot’s memory from an ephemeral personalization cache into something you can retain, version, and produce in an investigation. If you’ve rolled out Copilot at any scale, this is not optional housekeeping. It’s a new data class that just became discoverable.

    What Copilot memory actually is, and where it hides

    Copilot memory is the feature that makes Copilot feel less like a goldfish. It has two flavors. There are saved memories — things a user explicitly tells Copilot to remember (“I’m the PMO lead for the Helsinki migration,” “always summarize in bullet points”). And there are inferred details — facts Copilot derives from a user’s chat history to personalize future responses. Together they let Copilot stop asking the same context questions on every prompt.

    Here’s the part that matters for compliance: those memory items don’t live in some opaque AI service. They’re stored as items in a hidden folder in the user’s Exchange Online mailbox — the same substrate model Microsoft already uses for Teams messages and Copilot interaction history. That’s deliberate, and it’s good news, because anything in the mailbox substrate is reachable by Purview’s retention and eDiscovery machinery.

    Until now, though, memory has been managed entirely by the Copilot experience. Active memory changes as the model learns, and the previous state simply disappears. The GA feature adds retention and versioning for inactive memory items: when a memory item is superseded or removed, a retained copy is preserved according to your policy, while active memory keeps being managed by Copilot itself. You get the audit trail without freezing the feature.

    Why this surfaces now

    Memory shipped as a personalization win. Nobody in the Copilot product team was thinking about the poor eDiscovery admin who’d eventually have to explain, under oath, why an AI made a decision. Regulated tenants — financial services, healthcare, legal, public sector — flagged the obvious problem: if Copilot’s behavior is shaped by stored data about a person, that stored data is discoverable, and “we don’t keep it” is not a defensible answer to a regulator. Retention for memory is Microsoft catching the governance story up to a feature it already shipped.

    My read: the interesting word in the feature description is inactive. You are retaining the tombstones, not snapshotting live memory on a schedule. That’s fine for “prove what changed,” weaker for “reconstruct exactly what Copilot believed at 2pm on a Tuesday.” Set expectations with legal accordingly.

    The bigger picture: this is one piece of Purview’s Copilot governance stack

    Don’t treat memory retention in isolation. It slots into a set of Purview capabilities for Copilot that have landed over the past year, and if you’re planning, plan for all of them together:

    • Retention for Copilot interactions (prompts and responses) — already GA, configured as its own location in retention policies. Memory retention is the companion piece.
    • eDiscovery (Premium) for Copilot — Copilot interactions are collectable; memory items become collectable content under the same model once retained.
    • Communication Compliance for Copilot — policy scanning of prompts and responses for risky content.
    • DSPM for AI (Data Security Posture Management for AI, in the Purview portal) — the dashboard that shows you which users are using Copilot, what sensitive data they’re touching, and where your governance gaps are. This is where you should start your Copilot data-risk conversation.
    • Purview Audit for Copilot — interaction events flow to the unified audit log.

    The practical benefit versus the old world is straightforward. Before, Copilot memory was a black box you couldn’t retain, search, or defend. After, it’s a governed data class with a retention timeline you set, a version history for “what changed,” and a production path into eDiscovery. You’re trading an unbounded liability for a bounded, documented one. That’s the whole game in compliance.

    Find out who’s exposed before you write a single policy

    Scope first. Only Copilot-licensed users generate memory, so start by inventorying who actually has the license. This uses the Microsoft.Graph module — install with Install-Module Microsoft.Graph -Scope CurrentUser if you haven’t.

    Connect-MgGraph -Scopes "User.Read.All","Organization.Read.All"
    
    try {
        # Copilot SKU part number; confirm against your tenant's Get-MgSubscribedSku output
        $copilotSku = Get-MgSubscribedSku -All |
            Where-Object { $_.SkuPartNumber -eq 'Microsoft_365_Copilot' }
    
        if (-not $copilotSku) { throw "No Microsoft 365 Copilot SKU found in this tenant." }
    
        # -All handles paging automatically; do NOT roll your own $top loop here
        $licensedUsers = Get-MgUser -All -Property Id,DisplayName,UserPrincipalName,AssignedLicenses |
            Where-Object { $_.AssignedLicenses.SkuId -contains $copilotSku.SkuId }
    
        $licensedUsers |
            Select-Object DisplayName, UserPrincipalName, Id |
            Sort-Object DisplayName |
            Export-Csv .\Copilot-Licensed-Users.csv -NoTypeInformation
    
        Write-Host "$($licensedUsers.Count) Copilot-licensed users exported." -ForegroundColor Green
    }
    catch {
        Write-Warning "License inventory failed: $($_.Exception.Message)"
    }
    finally {
        Disconnect-MgGraph | Out-Null
    }
    

    That CSV is your review set. Everyone on it is generating memory items right now, retained by nothing.

    Now check what retention already exists. Retention compliance policies still live in Security & Compliance PowerShell — Graph doesn’t fully cover retention policy objects yet, so this is the correct modern module for the job (it ships in ExchangeOnlineManagement, not the retired MSOnline/AzureAD modules).

    Connect-IPPSSession -UserPrincipalName [email protected]
    
    try {
        Get-RetentionCompliancePolicy -DistributionDetail |
            Select-Object Name, Enabled, Mode,
                @{N='Locations';E={ ($_.ExchangeLocation.Name) -join '; ' }} |
            Format-Table -AutoSize
    
        # Rules carry the retention duration and action
        Get-RetentionComplianceRule |
            Select-Object Name, Policy, RetentionDuration, RetentionComplianceAction |
            Format-Table -AutoSize
    }
    catch {
        Write-Warning "Could not enumerate retention policies: $($_.Exception.Message)"
    }
    

    Building the policy — dry-run first, always

    The retention location for Copilot memory surfaces in the Purview portal as a Copilot workload alongside interactions. In PowerShell, the exact location parameter for the memory scope is being finalized as the feature reaches GA, so confirm the parameter name in your tenant against the current cmdlet help before you run this for real. What must not change is the discipline: never point a creation cmdlet at the output of a live query and let it rip.

    # SAFE BY DEFAULT: -WhatIf shows what would happen and changes nothing.
    # Remove -WhatIf only after you have reviewed the plan and the scope CSV.
    
    $policyName = "Copilot Memory Retention - 7yr"
    
    try {
        New-RetentionCompliancePolicy `
            -Name $policyName `
            -Comment "Retains inactive Copilot memory items for investigation/compliance." `
            -ExchangeLocation "All" `
            -WhatIf
    
        New-RetentionComplianceRule `
            -Name "$policyName-Rule" `
            -Policy $policyName `
            -RetentionDuration 2555 `      # ~7 years, in days
            -RetentionComplianceAction Keep `
            -WhatIf
    }
    catch {
        Write-Warning "Policy planning failed: $($_.Exception.Message)"
    }
    

    Scope tightly. -ExchangeLocation "All" is a blunt instrument; for a phased rollout, target a reviewed group or an explicit list of the mailboxes from your CSV rather than the entire tenant. And decide Keep versus KeepAndDelete deliberately — retaining memory tombstones forever is its own liability. Match the duration to your existing records schedule, not to a round number that felt safe.

    Where this lives in the portal

    Everything configures in the Microsoft Purview portal (purview.microsoft.com) under Data Lifecycle Management → Policies → Retention policies. Create or edit a policy and you’ll pick the Copilot workload as a location; the memory scope appears there as it rolls out. For the risk picture that should drive your scoping decisions, go to DSPM for AI in the same portal first — it tells you who’s actually using Copilot and against what data.

    What will bite you in six months

    Two things. First, retention makes memory discoverable, which cuts both ways: you’re preserving evidence you’ll be obligated to produce. If legal hasn’t blessed a duration, don’t set one long by reflex. Second, memory retention interacts with mailbox lifecycle. When a user leaves and their mailbox becomes inactive, retained memory items ride along under the same rules as the rest of the substrate — so your leaver process and your Copilot retention policy need to agree on how long that data lives, or you’ll discover a five-year cache of AI-inferred details about ex-employees nobody signed off on.

    Do this before September

    1. Run the license inventory above. Know your exposed population.
    2. Open DSPM for AI and read the Copilot usage/risk report. That’s your scoping input.
    3. Get legal to commit to a retention duration for memory — align it to your existing records schedule.
    4. Build the policy in -WhatIf, scoped to a pilot group, and verify against your reviewed CSV before you go tenant-wide.

    Copilot memory is a genuinely useful feature and a quiet new liability at the same time. September is when you get the controls. Have the policy drafted before then, not after the first eDiscovery request lands.

  • Planner’s New Capacity View Isn’t Free — Here’s the License You’ll Be Buying in October
    Planner's New Capacity View Isn't Free — Here's the License You'll Be Buying in October

    Here’s the part the roadmap card doesn’t say out loud: the Capacity view landing in Planner in October 2026 is a paid feature. It looks like a natural extension of the boards your teams already use for free, sitting one tab over from Grid and Board. But the moment someone clicks it and sees “upgrade to unlock,” you’ll get the ticket. And then you’ll get the second ticket, from a manager who tried it on a trial and now wants it for all 40 people in the department.

    So let’s get ahead of it. This is a genuinely useful feature — resource-levelling has been missing from basic Planner since day one — but it carries a licensing cost that admins need to model now, not scramble for when a director asks why their team can’t see it.

    What Capacity view actually does

    Capacity view (roadmap item 569733, GA October CY2026) puts every assignment on a timeline against the people doing the work. Instead of squinting at a board and mentally tallying how many cards each person is holding, you get a horizontal view: rows for people, bars for their assigned tasks over time. Someone stacked three deep in the same week shows up as an obvious block. Someone with a clear fortnight shows up as white space you can fill.

    If that sounds familiar, it should. This is resource management lifted out of Project for the web and dropped into the Planner app in Teams. The concept isn’t new — Project has done capacity and resource engagement for years. What’s new is that Microsoft is surfacing it inside the Planner experience most of your users already live in, which massively widens the audience that will want it.

    The productivity gain is real and easy to articulate to a budget holder. Before Capacity view, load-balancing across a team was a manual, gut-feel exercise done in someone’s head or a spreadsheet. After it, an overloaded engineer or a stalled sprint is visible at a glance, before the missed deadline rather than after. That’s the pitch. It’s also the trap, because the pitch works so well that demand outstrips whatever you’ve licensed.

    The licensing catch nobody’s flagging

    Basic Planner — the free experience that ships with Microsoft 365 and every Microsoft 365 Group — does not include premium plans, and Capacity view is a premium plan feature. To use it, a user needs a premium Planner license. These are the plans Microsoft rebranded from Project in 2025:

    • Planner Plan 1 (formerly Project Plan 1) — the entry point for premium plans, sprints, goals, and the timeline/schedule views that Capacity view belongs to.
    • Planner Plan 3 (formerly Project Plan 3) — adds the desktop Project client and roadmap-level capabilities.
    • Planner and Project Plan 5 (formerly Project Plan 5) — portfolio, demand management, enterprise resource capacity.

    Here’s what bites you in six months: the person who creates the premium plan needs the license, and depending on how your teams collaborate, contributors interacting with premium features may need one too. Microsoft’s own guidance on premium plan access has shifted more than once, so don’t assume “one licensed owner covers the whole team.” Model it per-user and validate against your actual usage. The renaming from Project to Planner also means your existing Project licenses are the Planner premium licenses — check what you already own before you buy anything.

    Audit what you can actually turn on today

    You have fourteen months. Use the first hour of it to find out where you stand: how many premium seats you own, how many are consumed, and who’s already sitting on a Project/Planner license they’ve forgotten about. Everything below uses the modern Microsoft.Graph module — no AzureAD or MSOnline, both of which are on their way out.

    Connect-MgGraph -Scopes "User.Read.All","Group.Read.All","Tasks.Read.All","Organization.Read.All"
    
    # Premium Planner SKUs are the rebranded Project SKUs.
    # Verify the exact part numbers in YOUR tenant with Get-MgSubscribedSku first —
    # these vary by agreement type (EDU/GCC/commercial).
    $plannerSkuParts = @("PROJECT_P1","PROJECTPROFESSIONAL","PROJECTPREMIUM")
    
    $skus = Get-MgSubscribedSku -All |
        Where-Object { $plannerSkuParts -contains $_.SkuPartNumber }
    
    if (-not $skus) {
        Write-Warning "No premium Planner/Project SKUs found. Confirm part numbers with: Get-MgSubscribedSku -All | Select SkuPartNumber, SkuId"
    }
    
    $skus | Select-Object SkuPartNumber,
        @{n='Enabled';   e={$_.PrepaidUnits.Enabled}},
        ConsumedUnits,
        @{n='Available'; e={$_.PrepaidUnits.Enabled - $_.ConsumedUnits}} |
        Format-Table -AutoSize
    

    That tells you the seat pool. Now find the humans holding those seats, so you know who can use Capacity view on day one and who’ll be raising a ticket:

    $targetSkuIds = $skus.SkuId
    
    # Get-MgUser -All handles pagination automatically — no manual @odata.nextLink loop needed.
    $licensedUsers = Get-MgUser -All `
        -Property Id,DisplayName,UserPrincipalName,AssignedLicenses,AccountEnabled |
        Where-Object {
            ($_.AssignedLicenses.SkuId | Where-Object { $targetSkuIds -contains $_ }).Count -gt 0
        }
    
    $licensedUsers |
        Select-Object DisplayName, UserPrincipalName, AccountEnabled |
        Sort-Object DisplayName |
        Export-Csv .\planner-premium-licensed-users.csv -NoTypeInformation
    
    Write-Host "$($licensedUsers.Count) users hold a premium Planner license."
    

    Watch for disabled accounts still holding a premium seat — that’s reclaimable budget sitting idle, and reclaiming it before renewal is the cheapest win in this whole exercise.

    It’s also worth inventorying the plans themselves, so you know which teams are heavy Planner users and therefore the most likely to demand Capacity view. There’s no single “get all plans” endpoint, so you enumerate through the groups that own them:

    $groups = Get-MgGroup -All `
        -Filter "groupTypes/any(c:c eq 'Unified')" `
        -Property Id,DisplayName
    
    $planInventory = foreach ($g in $groups) {
        try {
            Get-MgGroupPlannerPlan -GroupId $g.Id -All -ErrorAction Stop |
                Select-Object @{n='Group';   e={$g.DisplayName}},
                              @{n='PlanTitle';e={$_.Title}},
                              @{n='PlanId';   e={$_.Id}},
                              @{n='Created';  e={$_.CreatedDateTime}}
        }
        catch {
            Write-Warning "Plan lookup failed for '$($g.DisplayName)': $($_.Exception.Message)"
        }
    }
    
    $planInventory | Sort-Object Group | Export-Csv .\planner-plan-inventory.csv -NoTypeInformation
    

    On a large tenant this loop is slow and will occasionally throw throttling (HTTP 429). The try/catch keeps one bad group from killing the run; for tenants with thousands of groups, add a short Start-Sleep between iterations or batch it.

    Assigning the seats — on reviewed input only

    When the requests come in, resist the urge to pipe a live query straight into a license assignment. Assign from a CSV you’ve actually reviewed with the budget owner. This script defaults to a dry run — it prints what it would do and changes nothing until you explicitly pass -Apply, and it only ever touches the rows in your reviewed file:

    param(
        [string]$InputCsv      = ".\reviewed-capacity-users.csv",  # must contain a UserPrincipalName column
        [string]$SkuPartNumber = "PROJECT_P1",
        [switch]$Apply   # omit this and the script only reports. Nothing changes without -Apply.
    )
    
    $sku = Get-MgSubscribedSku -All | Where-Object SkuPartNumber -eq $SkuPartNumber
    if (-not $sku) { throw "SKU $SkuPartNumber not found in tenant." }
    
    $available = $sku.PrepaidUnits.Enabled - $sku.ConsumedUnits
    $requested = (Import-Csv $InputCsv).Count
    if ($requested -gt $available) {
        Write-Warning "Requesting $requested seats but only $available available. Buy more before applying."
    }
    
    Import-Csv $InputCsv | ForEach-Object {
        $upn = $_.UserPrincipalName
        if ($Apply) {
            Set-MgUserLicense -UserId $upn -AddLicenses @{SkuId = $sku.SkuId} -RemoveLicenses @()
            Write-Host "ASSIGNED $SkuPartNumber -> $upn"
        }
        else {
            Write-Host "[DRY RUN] would assign $SkuPartNumber -> $upn"
        }
    }
    

    Run it once with no switch, eyeball the output, confirm the seat math, then re-run with -Apply. The same rule applies to any reclamation script you write against those disabled accounts — review, then apply.

    Where this lives in the admin center

    Planner has no dedicated admin portal, which surprises people every time. Your controls are spread across a few places:

    • Licensing and seat counts: Microsoft 365 admin center → Billing → Licenses, and Billing → Purchase services for buying more premium Planner seats.
    • App availability and pinning: Teams admin center → Teams apps → Manage apps and Setup policies — this is where you pin the Planner app so users find it, and where you’d block it if you needed to.
    • Tenant-level Planner settings: still Graph/PowerShell territory (iCal publishing, roster creation) — there’s no GUI for most of it.

    The bigger Planner picture you should be planning for

    Capacity view doesn’t arrive in isolation. The Planner app in Teams is now the consolidated home for To Do, Planner, and Project for the web — the old “Tasks by Planner and To Do” name is gone. If your setup policies still reference the old app name, fix that before your users go looking for the new features.

    Two other threads matter for the same admin workflow. First, Copilot in Planner — plan generation, goal breakdown, and task drafting — is itself a premium capability layered on top of both a premium Planner plan and a Copilot license. If you’re modelling budget for Capacity view, model Copilot in the same conversation, because the same power users will want both. Second, premium plan features like sprints and goals ride the exact same license as Capacity view. In other words, one Plan 1 seat unlocks the whole premium tier, so frame the purchase as “premium Planner for this team,” not “the timeline thing one manager asked for.” That reframing usually makes the business case easier, not harder.

    My take

    Capacity view is a good feature landing in the right place. Resource levelling belongs where the work already happens, and Teams is where it happens. The feature isn’t overrated — the surprise is.

    Prioritise like this. Now: run the audit, find idle premium seats on disabled accounts, and reclaim them. Before Q3 2026: identify your two or three heaviest Planner teams and cost out premium seats for them specifically — those are your first adopters and your best pilot. When it goes GA in October: turn it on for the pilot from a reviewed CSV, not a bulk assignment, and let the results build your case for a wider rollout. Do it in that order and Capacity view becomes a planned upgrade with a clear ROI story. Ignore it and it becomes a support queue full of “why can’t I see the timeline” the week it ships.

  • Diving into Primary Refresh Tokens and Authentication Strengths in Microsoft Entra ID

    Microsoft Entra ID is the backbone of modern identity management, powering secure access to cloud and hybrid resources. At its core, the Primary Refresh Token (PRT) makes single sign-on (SSO) smooth and secure across devices and apps. Paired with a range of authentication methods, Entra ID offers flexibility and strength for everyone from new users to seasoned IT pros. This post breaks down the PRT, its role, and the authentication options in Entra ID, with a detailed comparison table and hyperlinked resources to dig deeper. Let’s jump in!

    What’s a Primary Refresh Token (PRT)?

    A PRT is like a secure key stored on your device (think laptop, phone, or tablet) that lets you access apps without constantly re-entering credentials. For the tech-savvy, it’s a device-bound, cryptographically signed token issued by Entra ID, packed with user and device claims. It enables SSO for cloud (via OAuth 2.0/OpenID Connect) and hybrid (via Kerberos/NTLM) environments. Unlocked by methods like a PIN or biometrics, it keeps things secure without exposing sensitive keys.

    PRT Highlights

    • Device Binding: Locked to a specific device for added security.
    • Seamless SSO: No repetitive logins for cloud or on-premises access.
    • Advanced Claims: Supports conditional access policies and session controls with strong authentication.
    • Supported Platforms: Works on Windows, iOS, Android, and macOS (hybrid-joined devices).

    Authentication Strengths in Microsoft Entra ID

    Entra ID supports a variety of authentication methods, grouped by strength: Phishing-resistant MFA, Passwordless MFA, Traditional MFA, and Single-factor. Each method differs in security, user experience, and PRT compatibility. Let’s explore them, from user-friendly options to enterprise-grade solutions.

    Authentication Methods Breakdown

    1. PIN (Windows Hello for Business)
      • What It Is: A device-specific multi-digit code.
      • Why It’s Cool: Feels like a password but tied to your device, making it super secure.
      • Tech Details: Uses cryptographic key pairs in a Trusted Platform Module (TPM) or software container, delivering phishing-resistant, passwordless MFA.
      • PRT Role: Unlocks PRTs for SSO, supports advanced claims like session controls.
    2. Fingerprint (Windows Hello for Business)
      • What It Is: Biometric login via fingerprint scanning.
      • Why It’s Cool: Just touch and go—secure and fast.
      • Tech Details: Device-bound, cryptographic, phishing-resistant MFA.
      • PRT Role: Seamless PRT access, supports hybrid environments and advanced claims.
    3. Facial/Iris Recognition (Windows Hello for Business)
      • What It Is: Biometric authentication using facial or iris scanning.
      • Why It’s Cool: Your face or eyes are your login—no fuss, high security.
      • Tech Details: Cryptographically secure, device-bound, phishing-resistant.
      • PRT Role: Frictionless PRT unlocking, full hybrid support, advanced claims.
    4. FIDO2 Security Key (PIN)
      • What It Is: A hardware key requiring a PIN.
      • Why It’s Cool: Plug in the key, enter a PIN, and you’re in—tough to crack.
      • Tech Details: Uses FIDO2/WebAuthn standards, with private keys on the key, ensuring phishing-resistant MFA.
      • PRT Role: Issues PRTs with advanced claims, supports hybrid access.
    5. FIDO2 Security Key (Biometrics)
      • What It Is: A FIDO2 key with built-in biometric support (e.g., fingerprint).
      • Why It’s Cool: Fingerprint on the key makes it even smoother.
      • Tech Details: Combines FIDO2/WebAuthn with biometrics, device-bound, phishing-resistant.
      • PRT Role: Like PIN-based FIDO2, supports advanced PRT claims and hybrid access.
    6. Password
      • What It Is: Classic username and password.
      • Why It’s Cool: Familiar but needs a second factor for security.
      • Tech Details: Vulnerable to phishing; supports basic PRTs when paired with MFA, no advanced claims.
      • PRT Role: Limited hybrid support, less secure.
    7. One-Time Password (OTP)
      • What It Is: Temporary code via Microsoft Authenticator, SMS, or voice.
      • Why It’s Cool: Get a code on your phone to verify your login.
      • Tech Details: Traditional MFA, not phishing-resistant, prone to interception.
      • PRT Role: Basic PRT issuance, no advanced claims, limited hybrid access.
    8. Microsoft Authenticator (Push Notifications)
      • What It Is: Passwordless login via app push notifications.
      • Why It’s Cool: Tap “Approve” on your phone—quick and easy.
      • Tech Details: Device-bound to the app, supports passwordless MFA but not phishing-resistant.
      • PRT Role: Basic PRTs, limited hybrid support, no advanced claims.
    9. Certificate-based Authentication (CBA)
      • What It Is: Uses X.509 certificates for authentication.
      • Why It’s Cool: A digital certificate on your device or smartcard logs you in.
      • Tech Details: Phishing-resistant with MFA, supports single-factor or passwordless, requires certificate management.
      • PRT Role: Supports advanced PRT claims and hybrid access.
    10. Temporary Access Pass (TAP)
      • What It Is: Time-limited passcode for onboarding or recovery.
      • Why It’s Cool: Temporary code to set up a new device or account.
      • Tech Details: Supports passwordless or single-factor, not device-bound, medium security.
      • PRT Role: Basic PRTs, no advanced claims, limited hybrid support.
    11. Federated Authentication
      • What It Is: Login via external identity providers (e.g., Okta, Ping) using SAML or WS-Federation.
      • Why It’s Cool: Your company’s external system handles your login.
      • Tech Details: Security and PRT support depend on IdP configuration.
      • PRT Role: Varies by IdP, often basic PRTs unless configured for strong authentication.
    12. Smartcard
      • What It Is: Hardware-based authentication with a physical smartcard.
      • Why It’s Cool: Insert a card for high-security login.
      • Tech Details: Cryptographic, phishing-resistant, similar to CBA but requires physical hardware.
      • PRT Role: Supports advanced PRT claims and hybrid access.

    Comparison Table

    Here’s a detailed table comparing the authentication methods, their strengths, and key differences to help you choose the right approach.

    Authentication MethodPhishing-resistant MFAPasswordless MFATraditional MFASingle-factorDevice BindingHybrid Access SupportUser ExperienceSecurity LevelPRT Advanced ClaimsSupporting MechanismProtocols
    PINYesYesNoNoYesYesFrictionlessHighYesWindows Hello for BusinessOAuth 2.0, OpenID Connect, Kerberos/NTLM
    FingerprintYesYesNoNoYesYesFrictionlessHighYesWindows Hello for BusinessOAuth 2.0, OpenID Connect, Kerberos/NTLM
    Facial/Iris RecognitionYesYesNoNoYesYesFrictionlessHighYesWindows Hello for BusinessOAuth 2.0, OpenID Connect, Kerberos/NTLM
    FIDO2 Security Key (PIN)YesYesNoNoYes (Key)YesModerateHighYesFIDO2 Security KeyOAuth 2.0, OpenID Connect, FIDO2/WebAuthn, Kerberos/NTLM
    FIDO2 Security Key (Biometrics)YesYesNoNoYes (Key)YesFrictionlessHighYesFIDO2 Security KeyOAuth 2.0, OpenID Connect, FIDO2/WebAuthn, Kerberos/NTLM
    PasswordNoNoYesYesNoLimitedComplexLowNoPassword + MFAOAuth 2.0, OpenID Connect, Kerberos/NTLM
    One-Time Password (OTP)NoNoYesNoNoLimitedModerateMediumNoMicrosoft Authenticator, SMS, VoiceOAuth 2.0, OpenID Connect
    Microsoft Authenticator (Push)NoYesYesNoYes (App/Device)LimitedFrictionlessMediumNoMicrosoft Authenticator AppOAuth 2.0, OpenID Connect
    Certificate-based Authentication (CBA)YesYesNoYesYes (Device/Key)YesModerateHighYesX.509 CertificatesOAuth 2.0, OpenID Connect, Kerberos/NTLM
    Temporary Access Pass (TAP)NoYesNoYesNoLimitedModerateMediumNoEntra ID Temporary PassOAuth 2.0, OpenID Connect
    Federated AuthenticationDepends on IdPDepends on IdPDepends on IdPDepends on IdPDepends on IdPDepends on IdPVariesVariesDepends on IdPSAML/WS-Federation IdPSAML, WS-Federation, OAuth 2.0, OpenID Connect
    SmartcardYesYesNoYesYes (Card)YesModerateHighYesSmartcard HardwareOAuth 2.0, OpenID Connect, Kerberos/NTLM

    Table Legend

    • Phishing-resistant MFA: Uses cryptographic keys to block phishing (e.g., Windows Hello, FIDO2, CBA, Smartcard).
    • Passwordless MFA: Ditches passwords for ease and security (e.g., Windows Hello, FIDO2, Authenticator Push, CBA, TAP, Smartcard).
    • Traditional MFA: Password plus a second factor (e.g., OTP, Authenticator Push).
    • Single-factor: Least secure, password or certificate-based without MFA.
    • Device Binding: Tied to a device or key, boosting PRT security.
    • Hybrid Access Support: Enables on-premises access via Kerberos/NTLM.
    • User Experience:
      • Frictionless: Minimal effort (e.g., biometrics, push notifications).
      • Moderate: Some input needed (e.g., PIN, OTP, smartcard insertion).
      • Complex: Multiple steps or management (e.g., password + MFA, certificate setup).
    • Security Level:
      • High: Phishing-resistant, cryptographic.
      • Medium: MFA but vulnerable to phishing.
      • Low: Single-factor, attack-prone.
    • PRT Advanced Claims: Supports conditional access and session controls (e.g., Windows Hello, FIDO2, CBA, Smartcard).
    • Protocols:
      • OAuth 2.0/OpenID Connect for cloud SSO and PRT issuance.
      • FIDO2/WebAuthn for FIDO2 keys.
      • Kerberos/NTLM for hybrid access.
      • SAML/WS-Federation for federated authentication.

    Why It Matters

    Whether you’re just getting started with Entra ID or managing a complex enterprise setup, understanding PRTs and authentication methods helps you balance security and usability. Phishing-resistant options like Windows Hello and FIDO2 are gold for high-security needs, while traditional MFA works for less sensitive scenarios. PRTs make SSO a breeze, but their power depends on the authentication method behind them.

    Tips for Success

    • Go Phishing-resistant: Prioritize Windows Hello, FIDO2, or CBA for top-tier security and PRT advanced claims.
    • Enable Hybrid Access: Use hybrid-joined devices for seamless on-premises access.
    • Ditch Passwords: Shift to passwordless methods to cut phishing risks.
    • Leverage Conditional Access: Use PRT advanced claims for policies like location or device compliance.
    • Check Federated Setups: Ensure IdPs support strong authentication for PRTs.

    References and Resources

    This guide gives you the full scoop on PRTs and Entra ID authentication, from user-friendly basics to technical nitty-gritty. Whether you’re setting up secure logins or fine-tuning enterprise policies, these insights will steer you right. Dive into the resources for more details and keep your identity management game strong!

  • Mastering PRT Delayed Renewal in Microsoft Entra ID: Controls, Configurations, and Real-World Scenarios

    In the evolving landscape of identity management, the Primary Refresh Token (PRT) stands as a cornerstone of seamless single sign-on (SSO) in Microsoft Entra ID. As devices increasingly operate in hybrid environments—online, offline, or in hibernation—understanding how to control PRT delayed renewal is essential for security admins and architects. Delayed renewal refers to the postponement of PRT updates during periods of disconnection, allowing cached SSO while balancing risk.

    This technical deep-dive explores PRT mechanics, indirect control mechanisms (since direct timeline tweaks aren’t available), working configuration examples, expanded scenarios, and practical tips. We’ll leverage tables for clarity and draw from official Microsoft documentation to ensure accuracy as of late 2025. Whether you’re enforcing stricter security in a high-risk sector or optimizing for user experience, these insights will help you fine-tune PRT behavior.

    PRT Renewal Mechanics: The Foundation

    A PRT is a device-bound artifact enabling SSO across Entra-integrated apps on platforms like Windows, iOS, macOS, and Android. It’s issued during device registration or join and includes claims for user identity, device compliance, and more.

    Key Timelines

    • Validity Period: 90 days, with continuous renewal during active use.
    • Renewal Interval: Every 4 hours via the CloudAP plugin during Windows sign-in. For apps, the Web Account Manager (WAM) plugin renews PRTs under conditions like silent token requests without a refresh token or when the PRT is invalid (e.g., requiring MFA).
    • Delayed Renewal: If offline (e.g., due to network disconnect or hibernation), renewal pauses until reconnection and a qualifying event (e.g., sign-in or app token request). Cached PRTs remain usable for SSO up to the 90-day limit.
    • Offline Handling: No immediate termination; PRTs support offline SSO, but renewal requires internet for CloudAP or WAM checks.

    These intervals (4 hours, 90 days) are fixed and non-configurable directly, as per Microsoft’s design for consistency. However, policies can indirectly cap effective lifetimes by forcing re-authentication on reconnect.

    Table 1: PRT Renewal Triggers and Conditions

    Trigger TypeDescriptionInterval/ConditionOffline Impact
    CloudAP PluginRenews during Windows sign-in.Every 4 hoursDelayed until reconnect + sign-in
    WAM PluginRenews via app token requests (silent or interactive).On-demand (e.g., invalid PRT)Delayed; cached PRT used until reconnect
    Inactivity ExpiryPRT expires if unused.After 90 daysFull expiry; re-auth required
    Event-BasedPassword change or revocation invalidates PRT.Immediate on detectionCached until reconnect, then invalidated

    Control Mechanisms: Indirect Ways to Influence Delayed Renewal

    While you can’t adjust the 4-hour or 90-day windows, Entra ID offers policy-based levers to enforce re-evaluations on reconnect, effectively shortening offline PRT usability. Below, we detail each mechanism with additional nuances, configuration steps, and working examples.

    1. Sign-in Frequency (SIF) in Conditional Access

    SIF mandates re-authentication intervals, overriding PRT defaults by requiring fresh auth for renewal. It accounts for a 5-minute clock skew to avoid over-prompting.

    • Additional Details: SIF doesn’t evaluate during PRT issuance but impacts app-driven renewals (e.g., via WAM). In offline scenarios, it triggers on reconnect, potentially blocking renewal if unsatisfied.
    • Configuration Example (Entra Admin Center):
    1. Navigate to Entra ID > Security > Conditional Access > New Policy.
    2. Name: “High-Security SIF”.
    3. Users: Select groups (e.g., executives).
    4. Cloud Apps: All or specific (e.g., Exchange Online).
    5. Session > Sign-in Frequency: Set to “1 hour” or “Every time”.
    6. Enable in report-only mode first.
    • PowerShell Working Example (Using Microsoft Graph SDK):
      # Install if needed: Install-Module Microsoft.Graph
      Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess"
      $params = @{
          DisplayName = "SIF Policy - 1 Hour"
          State = "enabledForReportingButNotEnforced"
          Conditions = @{
              Applications = @{ IncludeApplications = "All" }
              Users = @{ IncludeUsers = "All" }
          }
          SessionControls = @{
              SignInFrequency = @{
                  Value = 1
                  Type = "hours"
              }
          }
      }
      New-MgIdentityConditionalAccessPolicy -BodyParameter $params
    • Impact: Reduces offline window; e.g., a 1-hour SIF means re-auth on reconnect after >1 hour offline.

    2. Token Protection

    Binds PRTs cryptographically to devices (via TPM), preventing replay. It validates binding during renewal, invalidating unbound PRTs.

    • Additional Details: Supports Windows 10+ and specific apps (e.g., OneDrive 22.217+). Errors like AADSTS1002 (no device state) or 1006 (unsupported OS) trigger on unbound renewals. In hibernation, TPM failures can invalidate PRTs post-wake.
    • Configuration Example:
    1. Entra Admin Center: Conditional Access > New Policy.
    2. Target: Office 365 apps.
    3. Conditions: Windows platforms.
    4. Session > Require Token Protection: Enable.
    5. Test in report-only; monitor logs for tokenProtectionStatusDetails.
    • Working Log Query Example (Log Analytics):
      SigninLogs
      | where TimeGenerated > ago(7d)
      | where ConditionalAccessPolicies has "Require token protection"
      | summarize Count=count() by tokenProtectionStatusDetails, signInSessionStatusCode
    • Impact: Ensures delayed renewal only succeeds on the bound device; mismatches force re-auth.

    3. Continuous Access Evaluation (CAE)

    CAE enables real-time revocation via events (e.g., account disable) or policies (e.g., IP changes), extending tokens to 28 hours while allowing instant invalidation.

    • Additional Details: Uses claim challenges (401 errors) for revocation. In offline reconnects, CAE checks sync’ed policies; supports apps like Outlook/Teams.
    • Configuration Example:
    1. Entra Admin Center: Conditional Access > Customize CAE.
    2. Enable for IP/location policies.
    3. Define trusted IPs: Add IPv4/IPv6 ranges.
    • Working Scenario Simulation: Use “What If” tool to test a user reconnecting from an untrusted IP—CAE issues challenge, revoking PRT.
    • Impact: Overrides delayed renewal; e.g., if risk detected offline, revocation applies on reconnect.

    4. Device Compliance Policies

    Integrates with Intune; PRTs carry compliance claims, failing renewal if non-compliant on reconnect.

    • Additional Details: Checks OS version, encryption, etc. Non-compliance (e.g., post-hibernation patch miss) blocks renewal.
    • Configuration Example (Intune):
    1. Intune > Devices > Compliance Policies > Create Policy.
    2. Require: Windows 10+, BitLocker enabled.
    3. Link to CA: Require compliant devices.
    • PowerShell Example:
      # Requires Intune Graph access
      $complianceParams = @{ /* JSON for policy */ }
      New-IntuneDeviceCompliancePolicy -BodyParameter $complianceParams
    • Impact: Shortens offline validity by enforcing checks on reconnect.

    5. Administrative Revocation

    Admins revoke PRTs via Graph, invalidating on reconnect.

    • Additional Details: Affects refresh tokens; access tokens expire in ~1 hour. Use with CAE for near-real-time.
    • Working PowerShell Example:
      Connect-MgGraph -Scopes "User.ReadWrite.All"
      $user = Get-MgUser -UserId "[email protected]"
      Revoke-MgUserSignInSession -UserId $user.Id
      Update-MgUser -UserId $user.Id -AccountEnabled $false
    • Impact: Flags PRTs for invalidation; delayed until reconnect.

    6. Password Reset or Account Changes

    Invalidates password-based PRTs; requires re-auth for new issuance.

    • Additional Details: SSPR or admin reset triggers; non-password PRTs (e.g., FIDO2) may persist.
    • Configuration Example: Enable SSPR in Entra; users reset via myaccount.microsoft.com.
    • Impact: Forces renewal failure on reconnect post-change.

    Table 2: Control Mechanisms Comparison

    MechanismConfigurability LevelOffline Renewal ImpactReconnect EnforcementExample Use Case
    SIFHigh (intervals in hours/days)Delays renewal promptRe-auth requiredRisky users needing frequent MFA
    Token ProtectionMedium (enable per app)Binding validationBlocks unboundPreventing token theft
    CAEHigh (events/policies)Real-time revocationClaim challengeLocation-based access control
    Device ComplianceHigh (Intune rules)Compliance checkBlocks non-compliantEnforcing patches post-hibernation
    Admin RevocationManual (per user)Invalidation flagImmediate blockCompromised account response
    Password ResetUser/Admin-initiatedInvalidationRe-auth with new credsPost-breach remediation

    Limitations on Direct Control

    The 4-hour renewal and 90-day inactivity are hardcoded for reliability—no API or policy alters them. Controls are reactive (on reconnect), not proactive offline. TPM failures add uncontrolled invalidation.

    Sample Scenarios with Working Details

    1. High-Security Environment with SIF and Token Protection:
    • Setup: 1-hour SIF + Token Protection for Teams.
    • Scenario: Laptop hibernates for 48 hours. On wake/reconnect, SIF triggers MFA; Token Protection checks binding. If TPM intact, renewal succeeds; else, error 1002 blocks.
    • Outcome: Effective offline limit reduced to ~1 hour post-reconnect.
    1. CAE in Risky Offline Reconnect:
    • Setup: CAE enabled with IP policy (trusted: 192.168.1.0/24).
    • Scenario: User offline in trusted location, then reconnects from untrusted IP. CAE issues 401 challenge; client re-auths, denying if policy violated.
    • Outcome: PRT revoked mid-renewal attempt.
    1. Compliance Failure Post-Hibernation:
    • Setup: Intune policy requires OS build >22621.
    • Scenario: Device hibernates, misses update. On reconnect, compliance check fails; PRT renewal blocked until remediation.
    • Outcome: Forces update, invalidating stale PRT.
    1. Admin Revocation for Terminated Employee:
    • Setup: Run Revoke-MgUserSignInSession.
    • Scenario: Offline device uses cached PRT. On reconnect, invalidation applies; access denied.
    • Outcome: Near-instant post-reconnect block with CAE.

    Practical Considerations

    • Testing: Use report-only mode and sign-in logs (filter for PRT events). Simulate hibernation with powercfg /hibernate on and disconnect.
    • Usability vs. Security: Frequent SIF (e.g., every time) boosts security but may cause 30-second delays on mobile.
    • Monitoring: Query logs for errors like 1003 (unsupported device).
    • Best Practices: Combine mechanisms (e.g., SIF + CAE) for layered defense; migrate to MgGraph PowerShell.

    By mastering these controls, you can transform PRT delayed renewal from a potential vulnerability into a managed asset. Experiment in a lab environment to see the interplay.

    References