top of page

Migrating Jamf Classic API Scripts to Token Authentication

Bearer Authentication and the Jamf Classic API

From the 10.35.0 release notes:

You can now use the Classic API to authenticate using Basic authentication or a Bearer Token retrieved through the /v1/auth/token Jamf Pro API endpoint for enhanced security. For information on Bearer Token authentication, see the Jamf developer resources:

What does this mean?

Up until now, when you have used the Classic API in Jamf, you have either passed the service account username and password like this:

curl -u 'api-user:P@$$w0rd'

or by encoding the username and password into Base64 and using a basic authentication header:

curl -H 'Authorization: Basic UmVtZW1iZXIgdG8gZHJpbmsgeW91ciBPdmFsdGluZSE='

But with this new token system, we start by issuing a POST to the new Jamf Pro API:

authToken=$( \\  
    curl \\    
        --request POST \\    
        --url \\    
        --header 'Authorization: Basic V2hhdCBraW5kIG9mIGdlZWsgZGVjb2RlcyBiYXNlNjQgc2FtcGxlcz8=' \\

But where the Classic API takes XML and can send XML or JSON data, the Jamf Pro API will only accept and return JSON. So our result will look like this:

    "token" : "eyJhbGciOiJIUzI1NiJ9.eyJhdXRoZW50aWNhdGVkLWFwcCI6IkdFTkVSSUMiLCJhdXRoZW50aWNhdGlvbi10eXBlIjoiSlNTIiwiZ3JvdXBzIjpbXSwic3ViamVjdC10eXBlIjoiSlNTX1VTRVJfSUQiLCJ0b2tlbi11dWlkIjoiZTljNWIyM2MtMmY1ZS00NmMyLWEwZjItN2YxYTY3MGI4NTA2IiwibGRhcC1zZXJ2ZXItaWQiOi0xLCJzdWIiOiIyIiwiZXhwIjoxNjQ2NzcwMzk0fQ.yngTs_kJjOI2GS0Dt0GpQfcf08DFWiaPSLOktOp769k",     
    "expires" : "2022-03-08T20:13:14.695Z"  

If this is running in a Jamf Policy script, you can only rely on the tools available on every Mac, and there aren't any built-in tools (that I have found) to process JSON in a shell script (bash, zsh, etc.) on the Mac.

Luckily, this data is relatively small and in a reliable format, so we can get it with awk:

api_token=$(/usr/bin/awk -F \" 'NR==2{print $4}' <<< "$authToken" | /usr/bin/xargs)

That will work with any version of macOS for this particular example, but if you are running macOS 12+, the current version of plutil can extract the token easily:

api_token=$(/usr/bin/plutil -extract token raw -o - - <<< "$authToken")

Rich Trouton, aka Der Flounder, has the following snippet to choose techniques:

if [[ $(/usr/bin/sw_vers -productVersion | awk -F . '{print $1}') -lt 12 ]]; then 	
    api_token=$(/usr/bin/awk -F \" 'NR==2{print $4}' <<< "$authToken" | /usr/bin/xargs)
    api_token=$(/usr/bin/plutil -extract token raw -o - - <<< "$authToken")

Now we can issue our original query with the token instead:

curl -H "Authorization: Bearer ${api_token}"

These tokens are valid for 30 minutes from the time they are issued, but I have yet to come up with a policy-driven script that would need longer than that!

It's also worth noting that the best (and safest) practice would be to invalidate the token at the end of your script. That can be done like this:

curl --request POST --url

Okay. But why should I change when my scripts work?

In the Jamf API documentation, the section marked Classic API Authentication Changes has the following note:

Support for Basic authentication via the Classic API has been deprecated and will be removed at a future time (estimated removal date: August-December 2022).

Depending on the number of scripts you maintain and/or clients you serve, this may require a large number of changes. Better to get started now while we have the choice.

To see my presentation on Token Bearer Authentication with the Jamf Pro API, visit

679 views1 comment

1 Comment

Federico S. Joly
Federico S. Joly
Aug 29, 2022

Very nice post, but for me the parsing bit is not working, at least in OS 12.5.1. Same happened in a OS 13 beta. Haven't tried in an older OS, but by removing the OS version check and sticking to the pre 12 version (awk), that still throws nothing as a token. This other post did the trick for me: Thanks!

bottom of page