Jamf Connect Login with Azure

There we go! Jamf launched Jamf Connect Login and Jamf Connect Verify with Azure integration: Jamf Connect Azure

Also, Nomad Pro has been rebranded to Jamf Connect Sync (Okta only).

My goal is to do a couple of blog post on the above products, but combining them in one big post would make this post a bit too long. Hence, let’s start with Jamf Connect Login and Azure integration. And this will already be one of those longer posts… ☕️☕️☕️

In one of my previous post I discussed Nomad Login+ Okta. This is now part of Jamf Connect, as depending the configuration the tool can be used for both Okta as Azure. I do have Jamf Connect Login with Okta on my ‘blog to-do list’ in order to go through the changes and discuss how to deploy it.

I’ll also leave Jamf Connect Verify for another time as it requires an additional installation (not included in the Jamf Connect installer).

Jamf Connect Notify (previously DEPNotify) is however part of Jamf Connect, so let’s do that today as well.

So the goal for today’s post:

  • Deploy Jamf Connect
  • Integrate it with Azure
  • Launch Notify during the Jamf Connect Login process.

Cool, lets take it out for a spin! Just be aware, while the product is awesome (really I love it!), the configuration does require some precision work!

To reduce my typing, I’ll refer to Jamf Connect Login as ‘JCL’ and Jamf Connect Notify as ‘JCN’ as from now.


  • JCL Trial (download it herewhen purchasing JCL you will need to deploy a license file as well).
  • Microsoft Azure account with Azure Active Directory
  • Native ‘Jamf Connect Login’ app in Azure (to be created)
  • Some coffee, Red Bull or any other preferred caffeinated substance

Deploy Jamf Connect Login with Azure Integration: Admin Guide

"Jamf Connect Login provides support for Microsoft Azure AD (Active Directory) and can be used to replace the standard macOS loginwindow with Azure Loginwindow. With Azure Loginwindow, you can do the following:

Authenticate via a native app in Azure 
Use multi-factor authentication (MFA) and support conditional access 
Enable Azure AD and Azure DFS (Directory Federation Services) 
Create a local account on a macOS computer"

Lets first start with the Azure side of the deployment. Before we can deploy JCL to our Macs, we need to configure some stuff in Azure. First, you’ll need to create a “native” app:

Go to Azure Active Directory -> App Registrations and create a new app.

Give it a name (Jamf Connect Login), set the Application type to ‘native and add the following redirect URL:

By default, all users in the Azure Directory can authenticate to the app, but if you want to limit access you can specifically assign users to it.:

Go to Azure Active Directory – Enterprise Applications – Jamf Connect Login and click on the number under ‘Total Users”. Next you can assign users to the app to restrict usage. However, see below, you might want to define some user roles first.
Note: You can also hide the Jamf Connect Login app from the users portal. As the purpose of this native app is authentication on the macOS LoginWindow, there is no need for the users to see it in their Azure user portal:
Go the properties of the app and set ‘Visible to users” to ‘No’

Now, one of the best features in JCL is the possibility to create local Standard versus Admin account on the Mac, based on the role you assign them in the Azure app. I don’t know what you think, but I love this feature! To do this, we need to create some roles in the Azure app manifest.

So let’s go back to Azure Active Directory – App registrations – Manifest. You need to add some code to the manifest to define the app roles.

I only created two: Standard and Admin. Just copy-paste the code below and change the “id”. The “id” is just a random UUID which you can easily create in macOS terminal by running:

uuidgen | tr "[:upper:]" "[:lower:]"


  "appRoles": [
      "allowedMemberTypes": [
      "displayName": "Standard",
      "id": "211b8058-b630-401c-b79f-334a7777f15a",
      "isEnabled": true,
      "description": "Members of the Standard group.",
      "value": "Standard"
      "allowedMemberTypes": [
      "displayName": "Admin",
      "id": "44bf4a1e-b28e-47e1-aa8d-2d5d2063f7bf",
      "isEnabled": true,
      "description": "Members of the Admin group.",
      "value": "Admin"

Next, go back to Azure Active Directory -> Enterprise applications -> Jamf Connect Login. Now you can assign users and define if JCL will create a Standard or Admin user on the Mac for them:

I created a user called ‘Standard’ which I assigned the Standard role, and TTG the Admin role.
Note: We'll see below how to tell JCL which role is considered to be Admins, but another way to create admin accounts through JCL is by setting the 'CreateAdmin' key in the preferences. This will however create Admin accounts for ALL users.
Note: If you are using Jamf Connect Login with automated MDM enrollment (formerly DEP), remove this application from any conditional access controls. The user will be signing into the system before conditional access can be instantiated.

So, that’s all for the Azure configuration. Lets now have a look at how to deploy JCL and configure the settings. First we need to create a configuration profile. You could also configure it via a script and the ‘defaults write’ command, but then this script needs to be deployed as part of the install package (see below). Deploying it via a Jamf Pro @Enrolment policy will not work as we need to be sure that this script runs before the user hits the LoginWindow… (and we have no control over that).

I’ll go with a config profile here. If you look at the Admin Guide, you will see that you need to create the profile and sign it before you upload it to Jamf Pro. Pretty sure that this is the best practice, but whether I’m lazy or just stubborn, I’ll leave that to you. I’m just going with a normal PLIST with basic settings and upload it as a custom preference. Hence I don’t have to sign it. It works, but nevertheless, I would advice to follow the official workflow and make a signed profile.

First of all here is my basic PLIST. For now I’m just adding the 4 mandatory keys, defining the Admin user role and specifying the path to my Notify (JCN) script. More about that below.

4 mandatory keys:

  • OIDCClientID (Azure App ID)
  • OIDCProvider (Set it to Azure – can be set to Okta as well)
  • OIDCROPGID (Azure App ID)
  • OIDCRedirectURI

Admin user role:

  • OIDCAdmin (Set it to the Admin role you created in the Azure Manifest)

Notify ScriptPath:

  • ScriptPath
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">

You will need your Azure Enterprise App ID:

Upload it to Jamf Pro as a Custom Setting in a configuration profile:

Again, a signed profile following the instructions of the admin guide is preferred, also due to the location where these setting will be written in the Library. But yet again, stubborn as I am, this works well for testing.

At this point, you could just upload the official JCL installer to your Cloud distribution point and deploy it via a prestage enrollment package. For prestage enrollments packages to work, it needs to be a signed package and deployed via a Cloud Distribution point. The official Jamf JCL installer is correctly signed of course.

However, as you have seen, I added a key to configure Notify (JCN) to the JCL PLIST as well. So I need to deploy the script, images and other items which I’m using in the Notify process as well. Hence we need to repackage the JCL installer, and add what we need for or Notify process to work.

As I did not want to touch the official installer I created my own package as follows. First Jamf Composer:

As you can see above, I’m deploying the official JCL installer (renamed) to the /tmp folder, and my Notify script (see below) and images to /usr/local/bin and /usr/local/images. In my demo, I’m quickly deploying Chrome and Firefox and throwing some dummy status bars in JCN. Hence the additional images/icons.

Note: Make sure the permissions of all your folders, and especially your Notify script are set correctly: root/wheel 755.

Next, I’m adding a post install script to run the official installer from the /tmp folder and enable JCN:

Don’t forget to add /usr/local/bin to the authchanger command… I did not think of that and waisted time troubleshooting miles away from the issue… ‘why is Notify not launching’ 🙂
Note: The Notify mechanism is not included in the loginwindow application by default. You can use the authchanger to enable both the Notify mechanism and RunScript mechanisms. The admin guide mentions the command to enable JCN ('authchanger -reset -OIDC -preAuth JamfConnectLogin:RunScript,privileged JamfConnectLogin:Notify'), but don't forget to specify the path:
#Enable Notify
/usr/local/bin/authchanger -reset -OIDC -preAuth JamfConnectLogin:RunScript,privileged JamfConnectLogin:Notify

I build this as a pkg but before signing it with my Developer Certificate, I’m passing this pkg through Munkipkg. Just to make sure everything is repackaged as it should be, as you might run against some issues when trying to sign the package or when deploying it through a prestage.

You could off course package everything manually in Munkipkg, but I like the drag and drop of Composer.

In Munkipkg I import my Composer pkg, and repackage it again. Just define the path to your pkg and give the project a name (ttgJC). Munkipkg will unpack your pkg and write all files in a folder (named to the project name) in the working directory:

$ munkipkg --import /path-to-pkg/ttgJC.pkg ttgJC

Next I repackaged it again with Munkipkg. Just run Munkipkg with the project name:

$ munkipkg ttgJC
Munkipkg will build the package again in the ‘build’ folder of the project.

The final step is signing the package, as otherwise our custom package will not run during the prestage process. For instance with a Developer Certificate:

$ productsign --sign 'Developer ID Installer: Travelling Tech Guy (3********S)' '/path-to-your-munkiproject/build/ttgJC.pkg' '/destination-path-signed-pkg/ttgJCSigned.pkg'

Done! Upload this signed package to your Cloud Distribution Point, add it to a prestage, skip account creation and there we go! Jamf Connect Login with account creation based on Azure and Notify deploying anything you want before the end user even reaches the Desktop! MAGIC!

Just for the record, here is my sample Notify script. Apart from deploying Chrome and Firefox, I also added a safety net to make sure the Jamf Binary is installed before it calls custom triggers from Jamf Pro. When testing in VM’s it happens that the installation of the Jamf Binary via MDM has some delay, but it might be a good safety net for real deployments as well.


### Do it!

echo "STARTING RUN" >> /tmp/output.txt

# Set a main image
# Image can be up to 660x105 it will scale up or down proportionally to fit

echo "Command: Image: /usr/local/images/TTG.png" >> /var/tmp/depnotify.log

# Set the Main Title at the top of the window

echo "Command: MainTitle: Welcome to your new Mac!" >> /var/tmp/depnotify.log

# Set the Body Text

echo "Command: MainText: We are setting up a few things for you automatically.\\nJust grab a coffee! It won't take long!." >> /var/tmp/depnotify.log

echo "Status: Preparing new machine" >> /var/tmp/depnotify.log 

echo "Command: Determinate: 5" >> /var/tmp/depnotify.log
sleep 3
echo "Status: Checking some Magic for you..." >> /var/tmp/depnotify.log 

#adding a safety net here to make sure the Jamf Binary is present. Just in case there is some delay on the installation via MDM

while [ ! -f /usr/local/bin/jamf ]
  sleep 2

### Jamf Triggers

sleep 3
echo "Command: Image: /usr/local/images/Chrome.png" >> /var/tmp/depnotify.log
echo "Status: Installing Google Chrome" >> /var/tmp/depnotify.log 

/usr/local/bin/jamf policy -event installChrome

sleep 3
echo "Command: Image: /usr/local/images/Firefox.png" >> /var/tmp/depnotify.log
echo "Status: Installing Firefox" >> /var/tmp/depnotify.log 

/usr/local/bin/jamf policy -event installFirefox

sleep 3
echo "Command: Image: /usr/local/images/Pirate.png" >> /var/tmp/depnotify.log
echo "Status: Doing more fancy stuff... you don't want to know..." >> /var/tmp/depnotify.log

### AD Bind? Nah, who needs an AD bind nowadays... we'll just skip that.

sleep 5
echo "Command: Image: /usr/local/images/TTG.png" >> /var/tmp/depnotify.log
echo "Status: Almost done!" >> /var/tmp/depnotify.log 

### Clean Up

sleep 3
echo "Command: Quit" >> /var/tmp/depnotify.log

sleep 1
rm -rf /var/tmp/depnotify.log

That’s it! I hope this covers all you need to do a basic deployment of Jamf Connect Login with Azure and Notify enabled.

I might do another more advanced tutorial later, but have a look at the additional keys you can set in the configuration profile here.

Also coming up next, Jamf Connect Verify, Jamf Connect Sync, ….

Let me know if you have any comments, remarks or questions!


Print Friendly, PDF & Email

24 thoughts on “Jamf Connect Login with Azure”

  1. Thank you so much for this information!! Got me going in the right direction! I would like understand process of signing the Plist file before upload. How do you sign it? What tools do you use?

    1. You’ll need a signing certificate such as an Apple Dev cert for instance in your keychain, after that you can sign it via Terminal:

      /usr/bin/security cms -S -N “certificate common name with private key in keychain” -i /path/to/unsigned/profile -o /path/to/new/signed/profile

  2. Thanks for this guide – your blogs just seems to match my work path or different topics

    Regarding the user access, default we allow users to have admin access. So should I still create an admin user UUID and assign to all users or is that not needed if we only default have admin access ?

    1. Hi Peder! No need to differentiate admin users if the goal is that everyone is admin anyway. You can just use the key “CreateAdmjn” to make everyone an admin

  3. Forgot.
    If I want users to authenticate direct to azure on login – as I understand it will create a network account on the mac, right ? . Actually been fighting to get all these different account types to dissapear so only working with local accounts and Nomad sync. But guess, the idea behind jamf connect is to use network account

  4. Hi,

    Is the process diferent if I want to change jamf connect for already installed mac´s(Guess the above is made for new installation macs). So when they login they use azure with my own login

    BTW: Can you describe with few words Jamf Connect Verify must be used for ? Cannot quite see the reason why using this ?

    1. The install process is the same if the Macs are already deployed, with the option to demobilize users if previously used as mobile accounts. Jamf Connect Verify is the app you need to deploy if you want to keep the local password in sync with Azure once the accounts is created. When the Azure password changes, it will inform the user to sync the local password for instance.

      1. Thanks for the info.

        I am trying to set up some testing. We are running nomad (free) where I also demobilize accounts, as we used to AD join macs and it works fine. So as I understand Jamf connect do actually exact the same as nomad (free) version, so I don´t see any real advantage of using jamf connect right here and now (in the future maybe if new services etc is build in through azure)

        1. Indeed, Jamf Connect is only for when you have Azure or Okta. With on-premise AD, Nomad is what you need, in it’s free and open source indeed!

          1. Hi,
            Thanks for the input
            We are having also Azure together with AD (that sync to azure). So until we go all on azure I can understand that there is no need to go for Jamf connect. With jamf Connect would there be any options to build in group memberships on Mac´s. So I having a admin group in Azure this group can be applied also to Macs

  5. Trying to set it up using this guide.
    But after entering my AzureAD user/pass and MFA it wants me to enter password again and it fails.

    The error:
    Network password not valid for local accounts.

    And then you are stuck, because no local account is created.
    Password complies with all password policies.

  6. I used it before for testing DEP.
    But i erased the disk and reinstalled MacOS Mojave on it, will this should make it a clean install right?

    1. Hi Dennis, so it works now?

      If so, yes it must have been a stuck password policy. Interesting because I happen to had the same situation last week, but fixed it by running: pwpolicy -clearaccountpolicies

  7. Thanks for this article. I still have some questions.

    I got the Jamf Connect file from from Jamf for testing. Do I need the plist also for a local installation without Jamf Pro? If yes, how can I create it?

  8. Hey there. Thanks for the awesome guide. I’m having a little trouble. I have a ticket open with jamf and we haven’t gotten anywhere yet. Maybe another set of eyes or ears would help. What’s happening is i’m getting this screen that says “Unable to load identity provider”. I’m able to ping the machine and it’s IP so i believe it’s on the network. I’ve also had someone else try my exact plist file and they get a login for my Azure app so that means that side is setup correctly. Any other ideas what i might be running into? I’m using the stock JCL package as a pre-enrollment package and a policy that adds my plist. I can set it’s getting the profile and the package but it always gets stuck at that error like it can’t see Azure or something. I have tried authchanger -reset -OIDC and still the same error. it’s the exact same error as in this page:


    Appreciate any insight anyone may have.

  9. Thanks for this TTG, Is there a way that we can prevent the DEP notify from running again for the same user – everytime the user logs in DEP notify appears. Not sure if this is just for me or if i forgot something.


    1. Hi Clayton! Yes, that’s expected. You need to disable Notify by running the authchanger again and set it back to authchanger -reset -OIDC without the preauth part. You can do this at the end of your Notify script

Leave a Reply

Your email address will not be published. Required fields are marked *