In a previous post I talked about the three ways to setup Windows 10 devices for work with Azure AD. I later covered in detail how Azure AD Join and auto-registration to Azure AD of Windows 10 domain joined devices work, and in an extra post I explained how Windows Hello for Business (a.k.a. Microsoft Passport for Work) works. In this post I will cover how Single Sign-On (SSO) works once devices are registered with Azure AD for domain joined, Azure AD joined or personal registered devices via Add Work or School Account.
SSO in Windows 10 works for the following types of applications:
- Azure AD connected applications, including Office 365, SaaS apps, applications published through the Azure AD application proxy and LOB custom applications integrating with Azure AD.
- Windows Integrated authentication apps and services.
- AD FS applications when using AD FS in Windows Server 2016.
The Primary Refresh Token
SSO relies on special tokens obtained for each of the types of applications above. These are in turn used to obtain access tokens to specific applications. In the traditional Windows Integrated authentication case using Kerberos, this token is a Kerberos TGT (ticket-granting ticket). For Azure AD and AD FS applications we call this a Primary Refresh Token (PRT). This is a JSON Web Token containing claims about both the user and the device.
The PRT is initially obtained during Windows Logon (user sign-in/unlock) in a similar way the Kerberos TGT is obtained. This is true for both Azure AD joined and domain joined devices. In personal devices registered with Azure AD, the PRT is initially obtained upon Add Work or School Account (in a personal device the account to unlock the device is not the work account but a consumer account e.g. hotmail.com, live.com, outlook.com, etc.).
The PRT is needed for SSO. Without it, the user will be prompted for credentials when accessing applications every time. Please also note that the PRT contains information about the device. This means that if you have any device-based conditional access policy set on an application, without the PRT, access will be denied.
The PRT has a validity of 90 days with a 14 day sliding window. If the PRT is constantly used for obtaining tokens to access applications it will be valid for the full 90 days. After 90 days it expires and a new PRT needs to be obtained. If the PRT has not been used in a period of 14 days, the PRT expires and a new one needs to be obtained. Conditions that force expiration of the PRT outside of these conditions include events like user’s password change/reset.
For domain joined and Azure AD joined devices, renewal of the PRT is attempted every 4 hours. This means that the first sign-in/unlock, 4 hours after the PRT was obtained, a new PRT is attempted to be obtained.
Now, there is a caveat for domain joined devices. Attempting to get a new PRT only happens if the device has a line of sight to a DC (for a Kerberos full network logon which triggers also the Azure AD logon). This is a behavior we want to change and hope to make for the next update of Windows. This would mean that even if the user goes off the corporate network, the PRT can be updated. The implication of this behavior today, is that a domain joined device needs to come into the corporate network (either physically or via VPN) at least once every 14 days.
Domain joined/Azure AD joined devices and SSO
The following step-by-step shows how the PRT is obtained and how it is used for SSO. The diagram shows the flow in parallel to the long standing Windows Integrated authentication flow for reference and comparison.
(1) User enter credentials in the Window Logon UI
In the Windows Logon UI the user enters credentials to sign-in/unlock the device. The credentials are obtained by a Credential Provider. If using username and password the Credential Provider for username and password is used, if using Windows Hello for Business (PIN or bio-gesture), the Credential Provider for PIN, fingerprint or face recognition is used.
(2) Credentials are passed to the Cloud AP Azure AD plug-in for authentication
The Credential Provider gets the credentials to WinLogon which will call LsaLogonUser() API with the user credentials (to learn about the authentication architecture in Windows see Credentials Processes in Windows Authentication). The credentials get to a new component in Windows 10 called the Cloud Authentication Provider (Cloud AP). This is a plug-in based component running inside the LSASS (Local Security Authority Subsystem) process with one plug-in being the Azure AD Cloud AP plug-in. For simplicity in the diagram these two are shown as one Cloud AP box.
The plug-in will authenticate the user against Azure AD and AD FS (if Windows Server 2016) to obtain the PRT. The plug-in will know about the Azure AD tenant and the presence of the AD FS by the information cached during device registration time. I explain this at the end of step #2 in the post Azure AD Join: what happens behind the scenes? when the information from the ID Token is obtained and cached just before performing registration (the explanation applies to both to domain joined devices registered with Azure AD and Azure AD joined devices).
(3) Authentication of user and device to get PRT from Azure AD (and AD FS if federated and version of Windows Server 2016)
Depending on what credentials are used the plug-in will obtain the PRT via distinct calls to Azure AD and AD FS.
PRT based in username and password
To obtain the Azure AD PRT using username and password, the plug-in will send the credentials directly to Azure AD (in a non-federated configuration) or to AD FS (if federated). In the federated case, the plug-in will send the credentials to the following WS-trust end-point in AD FS to obtain a SAML token that is then sent to Azure AD.
Note: This post has been updated to reflect that the end-point used is the usernamemixed and not the windowstransport as it was previously stated.
Azure AD will authenticate the user with the credentials obtained (non-federated) or with verifying the SAML token obtained from AD FS (federated). After authentication Azure AD will build a PRT with both user and device claims and will return it to Windows.
PRT based in the Windows Hello for Business credential
To obtain the Azure AD PRT using the Windows Hello for Business credential, the plug-in will send a message to Azure AD to which it will respond with a nonce. The plug-in will respond with the nonce signed with the Windows Hello for Business credential key.
Azure AD will authenticate the user by checking the signature based on the public key that it registered at credential provisioning as explained in the post Azure AD and Microsoft Passport for Work in Windows 10 (please note that Windows Hello for Business is the new name for Microsoft Passport for Work). The PRT will contain information about the user and the device as well, however a difference with the PRT obtained using username and password is that this one will contain a “strong authentication” claim.
Regardless of how the PRT was obtained, a session key is included in the response which is encrypted to the Kstk (one of the keys provisioned during device registration as explained in step #4 in the post Azure AD Join: what happens behind the scenes?).
The session key is decrypted by the plug-in and imported to the TPM using the Kstk. Upon re-authentication the PRT is sent over to Azure AD signed using a derived version of the previously imported session key stored in the TPM which Azure AD can verify. This way we are bounding the PRT to the physical device reducing the risk of PRT theft.
(4) Cache of the PRT for the Web Account Manager to access it during app authentication
Once the PRT is obtained it is cached in the Local Security Authority (LSA). It is accessible by the Web Account Manager which is also a plug-in based component that provides an API for applications to get tokens from a given Identity Provider (IdP). It can access the PRT through the Cloud AP (who has access to the PRT) which checks for a particular application identifier for the Web Account Manager. There is a plug-in for the Web Account Manager that implements the logic to obtain tokens from Azure AD and AD FS (if AD FS in Windows Server 2016).
You can see whether a PRT was obtained after sign-in/unlock by checking the output of the following command.
Under the ‘User State’ section check the value for AzureAdPrt which must be YES.
A value of NO will indicate that no PRT was obtained. The user won’t have SSO and will be blocked from accessing service applications that are protected using device-based conditional access policy.
A note on troubleshooting
To troubleshoot why the PRT is not obtained can be a topic for a full post, however one test you can do is to check whether that same user can authenticate to Office 365, say via browser to SharePoint Online, from a domain joined computer without being prompted for credentials. If the UPN suffix of users in Active Directory on-premises don’t route to the verified domain (alternate login ID) please make sure you have the appropriate issuance transform rule(s) in AD FS for the ImmutableID claim.
One other reason that I have seen PRT not being obtained, is when the device has a bad transport key (Kstk). I have seen this in devices that have been registered in a very early version of Windows (which upgraded to 1607 eventually). As the PRT is protected using a key in the TPM this could be a reason why the PRT is not obtained at all. One remediation for this case is to reset the TPM and let the device register again.
(5, 6 and 7) Application requests access token to Web Account Manager for a given application service
When a client application connects to a service application that relies in Azure AD for authentication (for example the Outlook app connecting to Office 365 Exchange Online) the application will request a token to the Web Account Manager using its API.
The Web Account Manager calls the Azure AD plug-in which in turn uses the PRT to obtain an access token for the service application in question (5).
There are two interfaces in particular that are important to note. One that permits an application get a token silently, which will use the PRT to obtain an access token silently if it can. If it can’t, it will return a code to the caller application telling it that UI interaction is required. This could happen for multiple reasons including the PRT has expired or when MFA authentication for the user is required, etc. Once the caller application receives this code, it will be able to call a separate API that will display a web control for the user to interact.
WebAuthenticationCoreManager.GetTokenSilentlyAsync(...) // Silent API WebAuthenticationCoreManager.RequestTokenAsync(...) // User interaction API
IWebAuthenticationCoreManagerStatics::GetTokenSilentlyAsync(...) // Silent API IWebAuthenticationCoreManagerInterop::RequestTokenForWindowAsync(...) // UI API
After returning the access token to the application (6), the client application will use the access token to get access to the service application (7).
When the user accesses a service application via Microsoft Edge or Internet Explorer the application will redirect the browser to the Azure AD authentication URL. At this point, the request is intercepted via URLMON and the PRT gets included in the request. After authentications succeeds, Azure AD sends back a cookie that will contain SSO information for future requests. Please note that support for Google Chrome is available since the Creators update of Windows 10 (version 1703) via the Windows 10 Accounts Google Chrome extension.
Note: This post has been updated to state the support for Google Chrome in Windows 10.
Remember that registering your domain joined computers with Azure AD (i.e. becoming Hybrid Azure AD joined) will give you instant benefits and it is likely you have everything you need to do it. Also, if you are thinking in deploying Azure AD joined devices you will start enjoying some additional benefits that come with it.
Please let me know you thoughts and stay tuned for other posts related to device-based conditional access and other related topics.
See you soon,
Jairo Cadena (Twitter: @JairoC_AzureAD)