----------------------------------- UPDATE 06/11/19 Following a change in Azure, there is a small change in how to assign specific users to the Jamf Connect app. As mentioned below, we need to configure the app as 'Default Client Type = Public'. However when doing so, Azure will hide the 'User and Groups' option in the Enterprise Application. As mentioned/updated in the Jamf Connect Admin Guide you need to temporarily toggle this switch to 'No' in case you want to assign specific users to the Jamf Connect app. Once you have assigned (or changed) your Jamf Connect users, switch it back to 'Yes'.


----------------------------------- UPDATE 16/07/19 In order to get the Admin role working and make some user (who have the admin role assigned according to the manifest, see below), an additional key is now needed in Jamf Connect Login: OIDCAdminAttribute. <key>OIDCAdmin</key> <string>Admin</string> <key>OIDCAdminAttribute</key> <string>roles</string> Starting in Jamf Connect Login 1.2.1, Login will look at the "groups" attribute in the ID token to determine administrative roles, rather than the "roles" attribute as in earlier versions of Jamf Connect Login. It seems that this change was implemented for OneLogin, but it affects Azure as well. Not sure if this will stay like this. To clarify, the CreateAdminUser key only creates the user as Admin upon initial creation: <key>CreateAdminUser</key> <true/> The OIDCAAdmin and Attribute keys forces the account to follow the role you assigned to the user in Azure at each login: <key>OIDCAdmin</key> <string>Admin</string> <key>OIDCAdminAttribute</key> <string>roles</string> If you only have the CreaetAdminUser key set, the user will be demote to standard at the next login. -----------------------------------
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.
Pre-reqs:
- JCL Trial (download it here – when 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:

Give it a name (Jamf Connect Login), set the Application type to ‘native and add the following redirect URL: https://127.0.0.1/jamfconnect
—————————————————————-
UPDATE 13/08/19: New settings for Azure:
—————————————————————-
Set default client type to ‘Public YES’ to allow ROPG/ROPC:

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

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:

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:]"
Sample:
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Standard",
"id": "211b8058-b630-401c-b79f-334a7777f15a",
"isEnabled": true,
"description": "Members of the Standard group.",
"value": "Standard"
},
{
"allowedMemberTypes": [
"User"
],
"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:

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)
- OIDCAdminAttribute (Set it to ‘roles’ according to the update mentioned above)
Notify ScriptPath:
- ScriptPath
*** UPDATED 16th of July 2019***
<?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">
<dict>
<key>OIDCAdmin</key>
<string>Admin</string>
<key>OIDCAdminAttribute</key>
<string>roles</string>
<key>OIDCClientID</key>
<string>9d8eb609-****-****-****-78a92759d3fc</string>
<key>OIDCProvider</key>
<string>Azure</string>
<key>OIDCROPGID</key>
<string>9d8eb609-****-****-****-78a92759d3fc</string>
<key>OIDCRedirectURI</key>
<string>https://127.0.0.1/jamfconnect</string>
<key>ScriptPath</key>
<string>/usr/local/bin/ttgLoginScript.sh</string>
</dict>
</plist>
You will need your Azure Enterprise App ID:

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

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:

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

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.
#!/bin/bash
###
### 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 ]
do
sleep 2
done
### 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!
TTG
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?
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
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 ?
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
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
No, you authenticate through Azure or Okta but use local accounts with Jamf Connect.
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 ?
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.
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)
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!
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
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.
Hi Dennis, is this a clean install / DEP? Or a test machine which was configured before?
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?
I think it had to do with a messed up password policy 🙂
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
Yeah this part is now working.
Thanks.
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?
Yes you will need to install Jamf Connect Login manually and then create a plist in /Library/Preferences. You can create the plist in your preferred code editor, or by writing entries to it via the “sudo defaults write /Library/Preferences/com.jamf.connect.login.plist” command in Terminal https://docs.jamf.com/jamf-connect/1.0.1/login/administrator-guide/Integrating_Jamf_Connect_Login_with_Azure.html
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:
https://www.jamf.com/jamf-nation/discussions/30898/jamf-connect-login-unable-to-load-identity-provider
Appreciate any insight anyone may have.
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.
Thanks
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
I appreciate your post. I have been attempting this deployment to no avail. Jamf Connect executes as it should, but my Notify script is not. There appears to be a default built-in Notify that is running instead of the script I have packaged with Jamf Connect and set in my PLIST> Any thoughts on why that would be happening?
Hi @cwilsonncaa
I’ve seen that before indeed. There is indeed a sample Notify script built into Jamf Connect. The fact that it is pulling that one is probably due to wrong file permissions on your script file.
I presume you deployed to script as part of the custom package you made? If so, what did you use to create the custom package? Did you check the file permissions on the script before building it?
TTG!
First and foremost…Thank you for replying and not just replying; but responding so swiftly. I love your posts and they have been greatly helpful for me.
My Script is called out in my PLIST. I have packaged the Script with the JCL pkg. I have set Permissions for the Script at root:wheel, 755.
Thoughts?
Only think I can think of is permissions which have not been applied correctly or not retained when you created the package or a typo in the path of the script in the plist.
Or any parent folder permission? Where did you drop the script? Do the parent folders have the correct permissions?
What did you use to build the package?
TTG,
The issue was with properly signing the Enrollment Package. Once I got that sorted out, everything began working as it should.
One question I have, are the new Jamf Connect Notify preference keys, the same as the old DEPNotify preference keys (that you know of)?
I was using the starter DEPNotify script with built-in registration fields and would like to do the same with the new Jamf Connect Notify script.
Hey TTG,
Thanks for the great guide, it was clutch for getting this working in our environment. Quick question though – what is the most efficient way to test these install scripts faster? Currently, we have a few machines we just rotate through, but having to reimage each one to do a trial run of tweaks/changes is painfully slow. What do you recommend for us to increase throughput there and let us test the tweaks faster?
James
Hi James,
I would actually advise to use a VM. Even if you are testing out Secure Token behaviour in the mix with Jamf Connect, I’ve got good and consistent result taking a VM snapshot at the very first screen of the setup assistant where you select the country.
Don’t use local apfs snapshots on a physical machine if you are testing Secure Tokens and FileVault as this messes up the tokens. VM snapshots are fine.
https://travellingtechguy.eu/category/virtual-machine/
Hi TTG. So I’m having some problems with the DEPNotify script. Or not really the script, rather the Jamf commands in the script. I can’t see they are run in the /var/log/jamf.log they don’t appear and therefor don’t install my policies they were supposed to trigger.
Funny thing I see is that when DEPNotify is finish running and quits, Setup Assistant will say “Finishing up your Mac” (or whatever the wording is)
Then go to finder and that’s it.
My script is almost an exact copy of yours. I changed the images, and I don’t remove the log in the end, since I wanted to see how it looked. I do also wait for the Jamf binary to appear. But non the less, no triggers are run.
Also, is there a way not only to make Sleep commands, but wait for the actual software to be installed? Since I want to prepare Office, Slack, Chrome and other stuff, it’s difficult to guesstimate the exact time for installation. I guess it also depends on the hardware of the machines.
So you see Notify being launched right? What is the scope and execution frequency of your custom policies? Any activity on the policy in Jamf Gui->Policy->logs ?
Yes it’s being launched.
Scope is all computers and the frequency is ongoing.
There are nothing in the logs in Jamf Gui.
But if I’m waiting 30 seconds putting in my password, the DEPNotify app is halfway through finish.
VM? Catalina by any chance? If yes, try physical machine?
Yes it was and yes it was 🙂 But physical has the same problem.
It’s like the Jamf Binary isn’t functioning and therefor failing the event trigger
Ok, I was actually sitting close to my colleague who you where troubleshooting with (Support). Think we’ll need see if we can replicate.
He said that 🙂
If you want all my files and script, let me know.
Great tutorial.
We have been using DEPNotify.app with a DEPNotify.sh start script.
Only issue I have with how Jamf Connect Notify works over DEPNotify is the DEPNotify.sh is in Jamf and so very easy to edit while this you have to edit your script then repackage and upload. Any workaround to that?
Hi Mat. Thanks. Never tried it, but you could make your packaged script a oneliner calling a custom Jamf Pro trigger which runs a policy that runs the real script? As in the packaged script: “jamf policy -event runNotifyScripy”. And in Jamf Pro a policy with the script and custom trigger “runNotifyScript”…. so you never have to change the packaged script… but like I said, never tried that so not sure how Notify is gonna behave. To he tested…
Just a silly question, how can we achieve above Notify workflow for User Initiated Enrollment ?
Hi, in se there is no difference between automated enrolment and UIE when it comes to Jamf Connect and Notify. With the exception of the fact the account is already created of course but you can use the ‘Migrate’ key to transform the existing local into an iDP linked one. Notify, when enabled acts in the same way as when doing Automated Enrolment. What is your roadblock exactly?