Deep-dive to Azure AD device join

Deep-dive to Azure AD device join

Devices (endpoints) are a crucial part of Microsoft’s Zero Trust concept. Devices can be Registered, Joined, or Hybrid Joined to Azure AD. Conditional Access uses the device information as one of the decisions criteria to allow or block access to services.

In this blog, I’ll explain what these different registration types are, what happens under-the-hood during the registration, and how to register devices with AADInternals v0.4.6.

What is a device?

Technically, a device is one of the object types in Azure AD. The device object is sometimes called device identity.

Where users are identified based on their credentials, devices are identified by certificates. In other words, a device certificate represents the device registered to Azure AD. These certificates are created during the registration process (this will be explained later).

Join Types

There are three different registration types, which are called Join Types. According to documentation these types are:

Join Type Purpose
Registered Devices that are Azure AD registered are typically personally owned or mobile devices and are signed in with a personal Microsoft account or another local account.
Joined Devices that are Azure AD joined are owned by an organization and are signed in with an Azure AD account belonging to that organization. They exist only in the cloud.
Hybrid Joined Devices that are hybrid Azure AD joined are owned by an organization and are signed in with an Active Directory Domain Services account belonging to that organization. They exist in the cloud and on-premises.

Next, let’s view the documentation to see in detail the differences between these join types!

Azure AD Registered

According to documentation:

The goal of Azure AD registered devices is to provide your users with support for the Bring Your Own Device (BYOD) or mobile device scenarios. In these scenarios, a user can access your organization’s Azure Active Directory controlled resources using a personal device.

Azure AD Registered Description
Definition Registered to Azure AD without requiring organizational account to sign in to the device
Primary audience Applicable to all users with the following criteria:
  • Bring your own device (BYOD)
  • Mobile Devices
Device ownership User or Organization
Operating Systems Windows 10, iOS, Android, and MacOS
Provisioning Windows 10 - Settings
iOS/Android - Company Portal or Microsoft Authentication app
MacOS - Company Portal
Device sign in options
  • End-user local credentials
  • Password
  • Windows Hello
  • PIN
  • Biometrics or Patter for other devices
Key capabilities
  • SSO to cloud resources
  • Conditional Access when enrolled into Intune
  • Conditional Access via App protection policy
  • Enables Phone sign in with Microsoft Authenticator app

Azure AD Joined

According to documentation:

Azure AD join is intended for organizations that want to be cloud-first or cloud-only. Any organization can deploy Azure AD joined devices no matter the size or industry. Azure AD join works even in a hybrid environment, enabling access to both cloud and on-premises apps and resources.

Azure AD Joined Description
Definition Joined only to Azure AD requiring organizational account to sign in to the device
Primary audience Suitable for both cloud-only and hybrid organizations.
Applicable to all users in an organization
Device ownership Organization
Operating Systems
  • All Windows 10 devices except Windows 10 Home
  • Windows Server 2019 Virtual Machines running in Azure (Server core is not supported)
Provisioning
  • Self-service: Windows OOBE or Settings
  • Bulk enrollment
  • Windows Autopilot
Device sign in options Organizational accounts using:
  • Password
  • Windows Hello for Business
  • FIDO2.0 security keys
Device management
  • Mobile Device Management (example: Microsoft Intune)
  • Co-management with Microsoft Intune and Microsoft Endpoint Configuration Manager
Key capabilities
  • SSO to both cloud and on-premises resources
  • Conditional Access through MDM enrollment and MDM compliance evaluation
  • Self-service Password Reset and Windows Hello PIN reset on lock screen
  • Enterprise State Roaming across devices

Azure AD Hybrid Joined

According to documentation:

Typically, organizations with an on-premises footprint rely on imaging methods to provision devices, and they often use Configuration Manager or group policy (GP) to manage them.

If your environment has an on-premises AD footprint and you also want benefit from the capabilities provided by Azure Active Directory, you can implement hybrid Azure AD joined devices. These devices, are devices that are joined to your on-premises Active Directory and registered with your Azure Active Directory.

Azure AD Joined Description
Definition Joined to on-premises AD and Azure AD requiring organizational account to sign in to the device
Primary audience Suitable for hybrid organizations with existing on-premises AD infrastructure.
Applicable to all users in an organization
Device ownership Organization
Operating Systems
  • Windows 10, 8.1, and 7
  • Windows Server 2008/R2, 2012/R2, 2016, and 2019
Provisioning Windows 10, Windows Server 20162019
  • Domain join by IT and autojoin via Azure AD Connect or ADFS config
  • Domain join by Windows Autopilot and autojoin via Azure AD Connect or ADFS config
Windows 8.1, Windows 7, Windows Server 2012 R2, Windows Server 2012, and Windows Server 2008 R2 - Require MSI
Device sign in options Organizational accounts using:
  • Password
  • Windows Hello for Business for Win10
Device management
  • Group Policy
  • Configuration Manager standalone or co-management with Microsoft Intune
Key capabilities
  • SSO to both cloud and on-premises resources
  • Conditional Access through Domain join or through Intune if co-managed
  • Self-service Password Reset and Windows Hello PIN reset on lock screen
  • Enterprise State Roaming across devices

Technical details

Now that we know the purpose of different join types let’s dive into technical details!

Device Object

Device objects are stored to Azure AD. Based on my research, here are the relevant attributes and their values related to different join types.

Note! The attribute names presented here are those exposed by Azure Active Directory Graph API with api-version=1.61-internal query parameter.

objectId

The id of the Azure AD device object.

deviceId

The device id attribute of the Azure AD device object. For Hybrid Joined devices, equals to equals to objectGuid of the on-prem AD device object.

deviceTrustType

Indicates the join type.

Join Type Value
Registered Workplace
Joined AzureAd
Hybrid Joined ServerAd

dirSyncEnabled

Indicates whether the device is synchronised from the on-prem AD or not. True for Hybrid Joined devices.

isManaged

Indicates whether the device is managed or not. Always True for Hybrid Joined devices. For Registered and Joined devices, the attribute needs to be set by device management application or AADInternals Set‑AADIntDeviceCompliant function.

isCompliant

Indicates whether the device is compliant or not. Attribute needs to be set by device management application or AADInternals Set‑AADIntDeviceCompliant function.

reserved1

The userCertificate attribute of the device from the on-prem AD object for Hybrid Joined devices. Public key with a subject name that equals to objectGuid of the on-prem AD device object.

onPremisesSecurityIdentifier

The security identifier (SID) of the on-prem AD device object. Only set for Hybrid Joined devices.

profileType

Always RegisteredDevice for Registered and Joined devices. For Hybrid Joined devices initially empty after synced from on-prem AD, set to registered after the actual join.

deviceSystemMetadata

Metadata about the device registration.

Key Description
CreationTime Time the device object was created.
Example: “2/20/2021 8:52:52 AM”
RegistrationAuthority Always set to “ADRS”
RegistrationAuthTime For Registered and Joined devices, the epoch timestamp when the user who registered/joined the device was authenticated.
Example: “1613810824”
Note: The timestamp comes from user’s access token (nbf claim), which is always 5 minutes earlier than the actual login.
RegistrationAuthMethods For Registered and Joined devices, the list of authentication methods used by the user who registered/joined the device. Can be any combination of “pwd”,“rsa”,“otp”,“fed”,“wia”,“mfa”,“mngcmfa”,“wiaormfa”,“none”. The PRT token created using this device will inherit this value.
Can be changed with AADInternals Set‑AADIntDeviceRegAuthMethods function.

Join process

Now that we know the three different join types let’s dive to process how each of these join types are performed.

Devices with different Join Type as seen in Azure AD portal: Device join types

Register

Registering devices to Azure AD has five steps:

Register flow

  1. Generate Device key and Transport key.

    The registration software (depends on the device) generates two keysets called Device key (dkpub/dkpriv) and Transport key (tkpub/tkpriv). The private keys are stored in the device.

    The Device key is used to identify the device, whereas the Transport key is used to decrypt the session key when requesting the PRT (see this blog for details).

    A certificate signing request (SCR) for “CN=7E980AD9-B86D-4306-9425-9AC066FB014A” (dkpub) is generated with dkpriv.

  2. Request access token for Azure AD Join

    The registration software request access token for appid 1b730954-1685-4b74-9bfd-dac224a7b894 with 01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9 audience.

  3. Return access token
  4. Enroll device

    A http POST request is made to “https[:]//enterpriseregistration.windows.net/EnrollmentServer/device/?api-version=1.0” to register the device to Azure AD:

     1{
     2    "TransportKey":  "UlNBMQAIAAADA[redacted]+Ht0sYG4vPqK1B2wQcnkO4cZhJ2Q==",
     3    "JoinType":  4,
     4    "DeviceDisplayName":  "Registered Device",
     5    "OSVersion":  "C64",
     6    "CertificateRequest":  {
     7                               "Type":  "pkcs10",
     8                               "Data":  "MIICdDCCAVwCAQAwLzE[redacted]n/rOiQamubMpzL1eaEhWLH8v9hkxZic="
     9                           },
    10    "TargetDomain":  "contoso.com",
    11    "DeviceType":  "Commodore",
    12    "Attributes":  {
    13                       "ReuseDevice":  true,
    14                       "ReturnClientSid":  true,
    15                       "SharedDevice":  false
    16                   }
    17}

    The dkpub (row 8) and tkpriv (row 2) are Base64 encoded. The join type (row 3) indicates device registration.

  5. Return device certificate

    The return value contains the signed (dkpub) of the Device key (row 4) and its thumbprint (row 3). The owner of the device is also returned (row 7).

     1{
     2    "Certificate": {
     3        "Thumbprint": "EA9CE04D0FCFB4AB382E253B7F1BC48CBC60010B",
     4        "RawBody": "MIID8jCC[redacted]IE34ylUixWmNVJj39HQ5ky4+0cY6JR1JovPLaCQ"
     5    },
     6    "User": {
     7        "Upn": "AllanD@contoso.com"
     8    },
     9    "MembershipChanges": [{
    10            "LocalSID": "S-1-5-32-544",
    11            "AddSIDs": ["S-1-12-1-4209995732-1115842628-132208791-3473393508", "S-1-12-1-1284395347-1172857899-2838897599-3439875365"]
    12        }
    13    ]
    14}

Join

The process joining devices to Azure AD is identical to registering devices:

Join flow

  1. Generate Device key and Transport key.
  2. Request access token for Azure AD Join
  3. Return access token
  4. Enroll device

    Only difference to the Registration is the JoinType (row 3):
     1{
     2    "TransportKey":  "UlNBMQAIAA[redacted]QkSnl0b8xkWqv5CKfBp8RQ==",
     3    "JoinType":  0,
     4    "DeviceDisplayName":  "Joined Device",
     5    "OSVersion":  "Vic20",
     6    "CertificateRequest":  {
     7                               "Type":  "pkcs10",
     8                               "Data":  "MIICdDCCAVwCAQAwLz[redacted]2003EixNAH3U7ggIXgXBWwtVbs="
     9                           },
    10    "TargetDomain":  "contoso.com",
    11    "DeviceType":  "Commodore",
    12    "Attributes":  {
    13                       "ReuseDevice":  true,
    14                       "ReturnClientSid":  true,
    15                       "SharedDevice":  false
    16                   }
    17}
  5. Return device certificate

Hybrid Join

As mentioned earlier, hybrid joined devices are joined to both on-prem AD and Azure AD. Hybrid Joining is similar to Registering and Joining, but there are some big differences.

First, the device object has to exist in Azure AD before the join can be performed. There are two ways to create the hybrid device object to Azure AD: it can be synced from on-prem AD with Azure AD Connect, or it can be generated via identity federation. With the latter way, the device object is created immediately to Azure AD, whereas the former method creates the object during the next synchronisation cycle.

Second, the device is joined by the system, not the user. The authentication method used during the joining depends on how the device object is created to Azure AD:

  • For the Azure AD Connect synchronisation, the authentication is performed by signing a part of the enrollment request with the private key of the computer’s machine certificate. Azure AD can verify the computer’s identity by validating the signature with the public key of the machine certificate. The public key is saved in Azure AD in the reserved1 attribute of the device object.

  • For the identity federation, the authentication is performed by requesting a SAML token from AD FS and requesting an access token from Azure AD with that SAML token. The resulting access token is then used for the enrollment request.

Let’s start with the Azure AD Connect synchronisation flow:

Hybrid flow 1

  1. Generate Machine certificate
  2. Set the value of userCertificate attribute of the device’s on-prem AD object to match the public key of the Machine certificate.
  3. Synchronise the device object to Azure AD.
    The Device Id attribute of the device’s Azure AD object is set to ObjectGuid of the device’s on-prem AD object.
  4. Generate Device key and Transport key.
  5. Enroll device

    The http POST request is a bit different than with Register and Join:
     1{
     2    "ServerAdJoinData":  {
     3                             "DeviceType":  "Windows",
     4                             "TransportKey":  "UlNBMQAIAAA[redacted]eXG2wVZ/D6/VtQZCgxrq0uOEdGvJ+Gwwez6GQ==",
     5                             "TargetDomainId":  "5694aa9c-04e1-4df1-9d37-5d64d0915d42",
     6                             "OSVersion":  "Vista",
     7                             "TargetDomain":  "",
     8                             "ClientIdentity":  {
     9                                                    "Sid":  "S-1-5-21-181028512-47807049-227815571-9284.2021-02-20 08:57:42Z",
    10                                                    "Type":  "sha256signed",
    11                                                    "SignedBlob":  "mt4lVuVcnAsc[redacted]pYAr+d8LJZyfNan6MeXvk+2SU40BGkfdw=="
    12                                                },
    13                             "SourceDomainController":  "dc.contoso.com",
    14                             "DeviceDisplayName":  "Hybrid Joined Device 2"
    15                         },
    16    "CertificateRequest":  {
    17                               "Type":  "pkcs10",
    18                               "Data":  "MIICdDCCAVwCAQAwL[redacted]ctccQcPO0wwtq0dKUk/+V8aKw4i4TNznHeZ3DY="
    19                           },
    20    "Attributes":  {
    21                       "ReuseDevice":  true,
    22                       "ReturnClientSid":  true,
    23                       "SharedDevice":  false
    24                   },
    25    "JoinType":  6
    26}
    The join type (row 25) indicates Hybrid Join. Also, the SID of the device is sent (row 9), and it must match the onPremisesSecurityIdentifier of the device’s Azure AD object.

    The enrollment request is authorised by calculating a SHA256 hash from “<SID>.<timestamp>” (row 9) and signing the hash with the private key of the Machine certificate. The signature (row 11) is sent with the enrollment request.
  6. Return device certificate

Identity federation flow:

Hybrid flow 2

  1. Generate Machine certificate
  2. Set the public key of the Machine certificate to the userCertificate attribute of the device’s on-prem AD object.
  3. Request SAML token.
    The computer requests a SAML token from the AD FS server.
  4. Return SAML token.

    The token includes the name (row 15) and SID (row 27) of the device and its on-prem AD GUID in Base64 encoded format (rows 9,18, 24, and 35). The account type is always DJ (row 21).
     1<saml:Assertion MajorVersion="1" MinorVersion="1" AssertionID="_b2db43d0-2f96-479e-a31f-e8225326fdbb" Issuer="http://e5.myo365.site/adfs/services/trust/" IssueInstant="2021-02-21T15:13:15.505Z" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">
     2	<saml:Conditions NotBefore="2021-02-21T15:13:15.505Z" NotOnOrAfter="2021-02-21T16:13:15.505Z">
     3		<saml:AudienceRestrictionCondition>
     4			<saml:Audience>urn:federation:MicrosoftOnline</saml:Audience>
     5		</saml:AudienceRestrictionCondition>
     6	</saml:Conditions>
     7	<saml:AttributeStatement>
     8		<saml:Subject>
     9			<saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">UUEMXKriXkOYeql655jERA==</saml:NameIdentifier>
    10			<saml:SubjectConfirmation>
    11				<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
    12			</saml:SubjectConfirmation>
    13		</saml:Subject>
    14		<saml:Attribute AttributeName="UPN" AttributeNamespace="http://schemas.xmlsoap.org/claims">
    15			<saml:AttributeValue>DESKTOP-4A5AE8$@company.com</saml:AttributeValue>
    16		</saml:Attribute>
    17		<saml:Attribute AttributeName="ImmutableID" AttributeNamespace="http://schemas.microsoft.com/LiveID/Federation/2008/05">
    18			<saml:AttributeValue>UUEMXKriXkOYeql655jERA==</saml:AttributeValue>
    19		</saml:Attribute>
    20		<saml:Attribute AttributeName="accounttype" AttributeNamespace="http://schemas.microsoft.com/ws/2012/01">
    21			<saml:AttributeValue>DJ</saml:AttributeValue>
    22		</saml:Attribute>
    23		<saml:Attribute AttributeName="onpremobjectguid" AttributeNamespace="http://schemas.microsoft.com/identity/claims">
    24			<saml:AttributeValue>UUEMXKriXkOYeql655jERA==</saml:AttributeValue>
    25		</saml:Attribute>
    26		<saml:Attribute AttributeName="primarysid" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims">
    27			<saml:AttributeValue>S-1-5-21-126850608-2097551590-1142751551-1260</saml:AttributeValue>
    28		</saml:Attribute>
    29		<saml:Attribute AttributeName="insidecorporatenetwork" AttributeNamespace="http://schemas.microsoft.com/ws/2012/01" a:OriginalIssuer="CLIENT CONTEXT" xmlns:a="http://schemas.xmlsoap.org/ws/2009/09/identity/claims">
    30			<saml:AttributeValue>true</saml:AttributeValue>
    31		</saml:Attribute>
    32	</saml:AttributeStatement>
    33	<saml:AuthenticationStatement AuthenticationMethod="urn:federation:authentication:windows" AuthenticationInstant="2021-02-21T15:13:15.505Z">
    34		<saml:Subject>
    35			<saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">UUEMXKriXkOYeql655jERA==</saml:NameIdentifier>
    36			<saml:SubjectConfirmation>
    37				<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
    38			</saml:SubjectConfirmation>
    39		</saml:Subject>
    40		<saml:SubjectLocality IPAddress="" DNSAddress=""/>
    41	</saml:AuthenticationStatement>
    42	<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    43		<SignedInfo>
    44			<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    45			<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
    46			<Reference URI="#_b2db43d0-2f96-479e-a31f-e8225326fdbb">
    47				<Transforms>
    48					<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
    49					<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    50				</Transforms>
    51				<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
    52				<DigestValue>tLyWWYmqHM5OqQoULGhxtO0iFiHu2uqg/nmS0orxfG4=</DigestValue>
    53			</Reference>
    54		</SignedInfo>
    55		<SignatureValue>Ook5qUQYD[redacted]/39yd2WVc3ZbN5asVD6a3kU25ZqCY3A==</SignatureValue>
    56		<KeyInfo>
    57			<X509Data>
    58				<X509Certificate>MIIC7jCCA[redacted]SV4JYS3wGstXeMw5qx++5fw==</X509Certificate>
    59			</X509Data>
    60		</KeyInfo>
    61	</Signature>
    62</saml:Assertion>
  5. Request access token for Azure AD Join
    Requests an access token using the SAML token.
  6. Return access token
    The returned access token looks like a normal user token, but there are some differences.

    The token contains account type (row 7), which is always “DJ”. It also contains the on-prem AD object id (row 16) and SID (row 17) of the device.

    The idp (row 13) and unique_name (row 23) attributes contains what seems to be the issuer uri of the AD FS. However, this is not the case, as the domain part of the uri is the domain of the device, not FQDN of the AD FS service.

     1{
     2    "aud": "01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9",
     3    "iss": "https://sts.windows.net/8c63b77b-19de-4b04-a8b2-ae8bb19a00fe/",
     4    "iat": 1613920183,
     5    "nbf": 1613920183,
     6    "exp": 1613924083,
     7    "account_type": "DJ",
     8    "acr": "1",
     9    "aio": "AXQAi/8TAAAASTiNcttgcax[redacted]o27/TRsgA==",
    10    "amr": ["wia"],
    11    "appid": "1b730954-1685-4b74-9bfd-dac224a7b894",
    12    "appidacr": "0",
    13    "idp": "http://company.com/adfs/services/trust/",
    14    "in_corp": "true",
    15    "ipaddr": "13.122.32.15",
    16    "on_prem_id": "5c0c4151-e2aa-435e-987a-a97ae798c444",
    17    "primary_sid": "S-1-5-21-1768792239-781667213-1105014165-9071",
    18    "rh": "0.AAAAnKqUVuEE8U2dN11k0JFdQlQJcxuFFnRLm_3awiSnuJR5AIE.",
    19    "scp": "policy_management",
    20    "sub": "6vWJbn3QWCXJShfSB3c2MbRKe5YPYZ01e3nLFlWiUFk",
    21    "tenant_region_scope": "EU",
    22    "tid": "8c63b77b-19de-4b04-a8b2-ae8bb19a00fe",
    23    "unique_name": "http://company.com/adfs/services/trust/#",
    24    "uti": "fjp57QEVuEGDuKTRzjQkAA",
    25    "ver": "1.0",
    26    "xms_sptype": "0"
    27}
  7. Generate Device key and Transport key.
  8. Enroll device
  9. Return device certificate

Conditional Access

Devices are a crucial part of Microsoft’s Zero Trust concept:

Zero Trust

In practice, implementing Zero Trust requires Azure AD Conditional Access (CA), which is included in Azure AD Premium P1. Among other things, with CA, we can allow or deny access based on the device information.

According to documentation, we can require the device to be managed. Managed devices are devices that are either Hybrid Joined or marked as compliant.

The Hybrid Joined devices are assumed to be managed by Configuration Manager and/or GPOs. Other devices can be marked compliant by Mobile Device Management (MDM) system, such as Intune. However, as I described in an earlier blog post, the device compliance can be “faked”, depending on the compliance requirements. The compliance can also be set by AADInternals Set‑AADIntDeviceCompliant function.

Single-Sign-On

As mentioned earlier, devices registered or joined to Azure AD allows single-sign-on (SSO) for Azure AD. The SSO is implemented by Primary Refresh Tokens (PRTs), which can be created with the device and transport certificates. The process and details of creating PRTs are described in an earlier blog post.

One important detail related to PRTs is the authentication method used when the device was registered or joined to Azure AD. If the user was authenticated with MFA, also the access tokens fetched using the PRT will have the MFA claim set. This will satisfy MFA requirement of CA policies. Administrators can change the methods after the registration with AADInternals Set‑AADIntDeviceRegAuthMethods function.

Joining devices with AADInternals

AADInternals can register, join, and hybrid join devices to Azure AD with Join‑AADIntDeviceToAzureAD function. Let’s see how to do this in action!

Registering devices

Registering devices to Azure AD is supported in AADInternals version v0.4.6 and later.

To register a device, obtain an access token and provide Register as JoinType:

# Get access token for Azure AD Join and save to cache
Get-AADIntAccessTokenForAADJoin -SaveToCache

# Register a new device to Azure AD
Join-AADIntDeviceToAzureAD -DeviceName "My Registered Device" -JoinType Register
Output:

Device successfully registered to Azure AD:
  DisplayName:     "My Registered Device"
  DeviceId:        77b7781f-9531-44f0-bae2-ad45b995880a
  Cert thumbprint: 00D8F218928A63D466091BA6847CE5A701A75218
  Cert file name : "77b7781f-9531-44f0-bae2-ad45b995880a.pfx"
Local SID:
  S-1-5-32-544
Additional SIDs:
  S-1-12-1-4209995732-1115842628-132208791-3473393508
  S-1-12-1-1284395347-1172857899-2838897599-3439875365

Joining devices

The JoinType defaults to Join, so joining a device is easy:

# Get access token for Azure AD Join and save to cache
Get-AADIntAccessTokenForAADJoin -SaveToCache

# Register a new device to Azure AD
Join-AADIntDeviceToAzureAD -DeviceName "My Joined Device"
Output:

Device successfully registered to Azure AD:
  DisplayName:     "My Joined Device"
  DeviceId:        bbe84457-2c93-4857-a7e4-0573fdcfd229
  Cert thumbprint: 6AFA62FEF611EBC1DFDA72B0221C986B77CF7597
  Cert file name : "bbe84457-2c93-4857-a7e4-0573fdcfd229.pfx"
Local SID:
  S-1-5-32-544
Additional SIDs:
  S-1-12-1-4209995732-1115842628-132208791-3473393508
  S-1-12-1-1284395347-1172857899-2838897599-3439875365
  S-1-12-1-1372034668-1267036473-87356082-2200290463

Hybrid joining devices

As explained earlier, hybrid join requires that a device object exists in Azure AD. Moreover, we now know that there are two ways to create those device objects to Azure AD.

Hybrid joining to synced device - option 1

Let’s start by creating a device object to on-prem AD, syncing it to Azure AD, and hybrid joining it.

The following script creates a computer object to on-prem AD (rows 1-5), gets its GUID (rows 6-7), creates a self-signed certificate for it using AADInternals (row 8), and finally, sets the public key of the certificate to the userCertificate attribute of the computer object (row 9).

1$ComputerName = "DESKTOP-1234"
2$ComputerOU =   "OU=Computers,DC=company,DC=com"
3$CloudDomain =  "company.com"
4
5New-ADComputer -Name $ComputerName -SAMAccountName $ComputerName -DisplayName $ComputerName -Path $ComputerOU -Enabled $true
6$ComputerObject = Get-ADComputer $ComputerName 
7$ComputerGuid = $ComputerObject.ObjectGUID
8New-AADIntCertificate -SubjectName "CN=$ComputerGuid" -Export
9Set-ADObject $ComputerGuid -Add @{"userCertificate" = [byte[]](get-content ".\CN=$ComputerGuid.cer" -Encoding byte)}

As the output shows, the generated certificate is also exported to a file:

Certificate successfully exported:
  CN=09d302c1-8160-430a-a9b1-a699ae696b31.pfx
  CN=09d302c1-8160-430a-a9b1-a699ae696b31.cer

The script created a new computer object to the Active Directory:

Computer added to AD

Next, run the following cmdlet to start the sync:

Start-ADSyncSyncCycle

After the sync, the device appears in Azure AD:

Computer added to Azure AD

Now we can continue the script we started earlier. First, we need to get the tenant id (row 10). By using the generated certificate and providing the name and SID of the computer, we can hybrid join the device (row 11):

10$TenantId = Get-AADIntTenantID -Domain $CloudDomain
11Join-AADIntDeviceToAzureAD -PfxFileName ".\CN=$ComputerGuid.pfx" -DeviceName $ComputerObject.Name -SID $ComputerObject.SID -TenantId $TenantId
Device successfully registered to Azure AD:
  DisplayName:     "DESKTOP-1234"
  DeviceId:        09d302c1-8160-430a-a9b1-a699ae696b31
  Cert thumbprint: 99EE3264242568BDDB3D0800C064F9D369B051E8
  Cert file name : "09d302c1-8160-430a-a9b1-a699ae696b31.pfx"

Now the computer is successfully hybrid joined to Azure AD:

Computer Hybrid Joined to Azure AD

Hybrid joining to synced device - option 2

It is also possible to create device objects directly to Azure AD with AADInternals using Join‑AADIntOnPremDeviceToAzureAD function. The function uses the same API Azure AD Connect is using, so Global Admin or Directory Synchronization Accounts role is required.

If SID, DeviceId, or certificate are not provided, the function will generate them.

# Get access token and save to cache
Get-AADIntAccessTokenForAADGraph -SaveToCache 

# Create a device object to Azure AD
Join-AADIntOnPremDeviceToAzureAD -DeviceName "DESKTOP-5678"
Device successfully created:
  Device Name:     "DESKTOP-5678"
  Device ID:       663cb1d1-bd4b-412f-a673-14f04ea55622
  Device SID:      S-1-5-21-378725881-735212363-822861820-5928
  Cloud Anchor:    Device_d7bf50e4-9538-43e9-b1ed-d20f8fd60064
  Source Anchor:   0bE8Zku9L0GmcxTwTqVWIg==
  Cert thumbprint: DF40352AD440EF8A4BECC27347A4FA9D35677188
  Cert file name:  "663cb1d1-bd4b-412f-a673-14f04ea55622-user.pfx"

We can now use the generated certificate and other information to hybrid join the device:

# Get the tenant id
$TenantId = Get-AADIntTenantID -Domain company.com
# Hybrid join the device
Join-AADIntDeviceToAzureAD -DeviceName "DESKTOP-5678" -SID "S-1-5-21-378725881-735212363-822861820-5928" -TenantId $TenantId -PfxFileName .\663cb1d1-bd4b-412f-a673-14f04ea55622-user.pfx

Device successfully registered to Azure AD:
  DisplayName:     "DESKTOP-5678"
  DeviceId:        663cb1d1-bd4b-412f-a673-14f04ea55622
  Cert thumbprint: BCDFF1388B845A2CEF4D0C9F4C08DD68CC130B41
  Cert file name : "663cb1d1-bd4b-412f-a673-14f04ea55622.pfx"

Hybrid joining by federation

To hybrid join a device with federation, a SAML token is needed. To create the SAML token, we need to have the token signing certificate and the issuer uri of the identity provider.

Note: AD FS certificate export functionality was heavily refactored in v0.4.7. See the blog for details.

Easies way to get the certificate is to export it from AD FS with AADInternals:

# Export AD FS token signing and encryption certificates
Export-AADIntADFSCertificates

To get the issuer uri, run the following cmdlet on AD FS server:

# Get AD FS issuer uri
$issuer = (Get-AdfsProperties).Identifier.OriginalString

To create a SAML token for the device:

# Create a new SAML token
$saml = New-AADIntSAMLToken -UserName "DESKTOP-9999" -DeviceGUID (New-Guid) -Issuer $issuer -PfxFileName .\ADFS_signing.pfx

Now we have all we need to hybrid join the device:

# Get an access token for the device with the SAML token
Get-AADIntAccessTokenForAADJoin -SAMLToken $saml -Device -SaveToCache

# Hybrid join the device
Join-AADIntDeviceToAzureAD -DeviceName "DESKTOP-9999"

Device successfully registered to Azure AD:
  DisplayName:     "DESKTOP-9999"
  DeviceId:        0810056c-d2d5-4c1b-bc17-2f2fbedd6ca3
  Cert thumbprint: 3022FF7937C0766CE3DB0AD45C9413FB68A05EE3
  Cert file name : "0810056c-d2d5-4c1b-bc17-2f2fbedd6ca3.pfx"
Local SID:
  S-1-5-32-544
Additional SIDs:
  S-1-12-1-3240472016-1160587922-3614255014-3410032901
  S-1-12-1-2566832563-1141717763-392342924-578657198

Summary

In this blog post, I explained what happens under-the-hood when devices are joined to Azure AD. Although there are three different join types, all device certificates are technically identical.

Next question would be how to exploit what we’ve have learned? Well, that is another story soon to be told :wink:

References

Dr Nestori Syynimaa (@DrAzureAD) avatar
About Dr Nestori Syynimaa (@DrAzureAD)
Dr Syynimaa works as Principal Identity Security Researcher at Microsoft Security Research.
Before his security researcher career, Dr Syynimaa worked as a CIO, consultant, trainer, and university lecturer for over 20 years. He is a regular speaker in scientific and professional conferences related to Microsoft 365 and Entra ID (Azure AD) security.

Before joining Microsoft, Dr Syynimaa was Microsoft MVP in security category and Microsoft Most Valuable Security Researcher (MVR).