Skip to main content
Question

Swift API Example


Forum|alt.badge.img+12

Hi all,

I just wanted to share a example project for anyone interested. This is a pure Swift application for OS X that queries and displays the number of computers enrolled in Casper. It demonstrates how to leverage the API in a Swift environment. I will update the repo with a posting example in the future. This can also be used to easily start an iOS project as well.

Hopefully this is helpful for someone.

https://github.com/jason-tratta/SwiftJSS

15 replies

BrysonTyrrell
Forum|alt.badge.img+19
  • Valued Contributor
  • 85 replies
  • February 25, 2015

Nice work! How are you liking Swift?


Forum|alt.badge.img+12
  • Author
  • Contributor
  • 30 replies
  • February 25, 2015

I'm really digging it. I thought I would stick to Obj-C forever...but it's really winning me over.


Forum|alt.badge.img+1
  • New Contributor
  • 9 replies
  • March 10, 2019

As this was posted in 2015 is there any additional steps to set this up. I have got the app to build in Xcode 10 but it seems to do nothing when entering the credentials. Does this still work if JAMF is on the cloud and what about 2FA.

thanks


boberito
Forum|alt.badge.img+22
  • Jamf Heroes
  • 451 replies
  • March 11, 2019

Still works awesome. I recently built a few apps that interacted with the API.

This would definitely work with Jamf in the cloud. I don't believe Jamf supports 2FA at all but does support kerberos and all that single sign on fun but the API doesn't use that, it uses your username/password.

https://github.com/boberito/swift-things - here's my GitHub. You can see the two little apps I've built and maybe how they're built will help you. You just use a URLSession to interact with the API. In fact Postman (an API app) will write you some Swift code if you want it to.


Forum|alt.badge.img+1
  • New Contributor
  • 9 replies
  • March 12, 2019

Thanks boberito. I will check them out.


Forum|alt.badge.img+1
  • New Contributor
  • 9 replies
  • March 12, 2019

Amazing work really good stuff.


Forum|alt.badge.img+1
  • New Contributor
  • 9 replies
  • March 15, 2019

@boberito

Hi boberito
Thanks again for the example apps you created. I have been playing with them trying to gain an understanding of getting what I need to work. I seem to have fallen at the first hurdle. I am just trying to convert what you did in the SMARTCARD UTILITY to GET data for mobile devices as this is what my current project is working towards. I have changed the URL to mobile devices and most of the settings to point to mobile devices and checked as you suggested with postman and it GETS the data however when i change the setting in your app just to see if I can get results I get an "UNKNOWN ERROR" then the app crashes. My thinking is it could be to do with the extension attributes.

After debugging yours compared to mine its does seem the data it gets in bytes in very low as if it's not getting the data.
Any help or pointers would be very appreciated.

Thanks
Adam


boberito
Forum|alt.badge.img+22
  • Jamf Heroes
  • 451 replies
  • March 17, 2019

@adamnewman Honestly I'd have to see your code. I have no idea. It probably has to do with extension attributes and such.


Forum|alt.badge.img+1
  • New Contributor
  • 9 replies
  • March 17, 2019

@boberito

If you could have a quick look. I just want to see if I can pull mobile devices in. I do think i'm going to have to start from the beginning and build my code from scratch. I'm trying to use yours to get a better understanding of how it works.

See code below with my edits.

import Cocoa

//login class
class jamfInfo { var server: String? var id: String? var name: String? var username: String = "" var password: String = ""
}

struct userSearch: Decodable { let user: listOfUsers

struct listOfUsers: Decodable { let name: String let full_name: String let email: String let phone_number: String let links: listOfmobiledevices

struct listOfmobiledevices: Decodable { let mobiledevices: [mobiledevices]

struct mobiledevices: Decodable { let name: String let id: Int

} } }
}

struct extensionAttribute: Decodable { let mobiledevices: mobiledevicesEA

struct mobiledevicesEA: Decodable { let extension_attributes: [EA]

struct EA: Decodable { let id: Int let name: String let value: String }

}

}

class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {

@IBOutlet var userInfo: NSTextField! @IBOutlet var tableView: NSTableView! @IBOutlet var JamfPassword: NSSecureTextField! @IBOutlet var jamfUser: NSTextField! @IBOutlet var userNameField: NSTextFieldCell! @IBOutlet var toggleButton: NSButtonCell!

var listOfmobiledevices = [String]() var listOfmobiledevicesIDs = [Int]() var listOfEAs = [String]()

var prefs = jamfInfo()

override func prepare(for segue: NSStoryboardSegue, sender: Any?) { let second = segue.destinationController as! PrefController readPlist() prefs.username = jamfUser.stringValue prefs.password = JamfPassword.stringValue second.representedObject = prefs listOfmobiledevices.removeAll() tableView.reloadData()

}

override func viewDidLoad() { super.viewDidLoad()

readPlist() if prefs.server != nil { let keychainVar = try? keychainlogin(server: prefs.server!) if keychainVar != nil { prefs.username = keychainVar!.KCUsername prefs.password = keychainVar!.KCPassword jamfUser.stringValue = prefs.username JamfPassword.stringValue = prefs.password } }

toggleButton.isEnabled = false // Do any additional setup after loading the view. }

@IBAction func preferencesMenuItemSelected(_ sender: Any) { self.performSegue(withIdentifier: "prefSegue", sender: self) }

@IBAction func doSomething(_ sender: Any) { readPlist() getTableView() }

func numberOfRows(in tableView: NSTableView) -> Int { return listOfmobiledevices.count }

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {

guard let vw = tableView.makeView(withIdentifier: tableColumn!.identifier, owner: self) as? NSTableCellView else { return nil }

if tableColumn?.title == "Computer List" { vw.textField?.stringValue = listOfmobiledevices[row]

} else { var eaOutput: Data? readPlist() eaOutput = getJamfData(url: "(prefs.server!)JSSResource/mobiledevices/id/(listOfmobiledevicesIDs[row])/subset/ExtensionAttributes").jamfDataOutput

let EAdecoder = JSONDecoder() let EADetails = try! EAdecoder.decode(extensionAttribute.self, from: eaOutput!)

for EAs in EADetails.mobiledevices.extension_attributes { if EAs.id == Int(prefs.id!) { vw.textField?.stringValue = EAs.value listOfEAs.insert(EAs.value, at: 0) break; } else { vw.textField?.stringValue = "" listOfEAs.insert("", at: 0) } }

} return vw }

func tableViewSelectionDidChange(_ notification: Notification) {

if tableView.selectedRow != -1 { toggleButton.isEnabled = true } else { toggleButton.isEnabled = false }

}

func getJamfData(url: String) -> (jamfDataOutput: Data, jamfResponse: Int) { let loginData = "(jamfUser.stringValue):(JamfPassword.stringValue)".data(using: String.Encoding.utf8) let base64LoginString = loginData!.base64EncodedString() let headers = ["Accept": "application/json", "Authorization": "Basic (String(describing: base64LoginString))"]

let request = NSMutableURLRequest(url: NSURL(string: url)! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "GET" request.allHTTPHeaderFields = headers

var dataReturn: Data? var ResponseCode: HTTPURLResponse?

let dispatchGroup = DispatchGroup() dispatchGroup.enter()

let session = URLSession.shared

let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if let APIdata = data { dataReturn = APIdata ResponseCode = response as? HTTPURLResponse

} dispatchGroup.leave() }) dataTask.resume() dispatchGroup.wait() if dataReturn == nil { dataReturn = "".data(using: String.Encoding.utf8)

} var ResponseStatusCode: Int if ResponseCode == nil { ResponseStatusCode = 1 } else { ResponseStatusCode = (ResponseCode?.statusCode)! } return(dataReturn!, ResponseStatusCode)

}

@IBAction func toggle(_ sender: Any) { readPlist() guard tableView.selectedRow != -1 else { return } var action: String = ""

if listOfEAs[tableView.selectedRow] != "Enabled" { action = "Enabled" } else { action = "Disabled" } var xmldata: String

let requestURL = "(prefs.server!)JSSResource/mobiledevices/id/(listOfmobiledevicesIDs[tableView.selectedRow])"

xmldata = "<?xml version="1.0" encoding="UTF-8" standalone="no"?><mobiledevices><extension_attributes><extension_attribute><id>" prefs.id! "</id><name>" prefs.name! "</name><type>String</type><value>" action "</value></extension_attribute></extension_attributes></mobiledevice>"

let loginData = "(jamfUser.stringValue):(JamfPassword.stringValue)".data(using: String.Encoding.utf8) let base64LoginString = loginData!.base64EncodedString() let postData = NSData(data: xmldata.data(using: String.Encoding.utf8)!) let headers = ["Content-Type": "text/xml", "Authorization": "Basic (String(describing: base64LoginString))"] let request = NSMutableURLRequest(url: NSURL(string: requestURL)! as URL,cachePolicy: .useProtocolCachePolicy,timeoutInterval: 10.0) request.httpMethod = "PUT" request.allHTTPHeaderFields = headers request.httpBody = postData as Data

let dispatchGroup = DispatchGroup() dispatchGroup.enter()

let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in

dispatchGroup.leave() } )

dataTask.resume()

dispatchGroup.wait()

getTableView() toggleButton.isEnabled = true

}

func errorOccured(typeOfError: String){ let alert = NSAlert() alert.messageText = "Error" alert.informativeText = typeOfError alert.runModal() }

func getTableView(){ listOfmobiledevices.removeAll() tableView.reloadData()

let myData = getJamfData(url: "(prefs.server!)JSSResource/users/name/(userNameField.stringValue)")

let decoder = JSONDecoder() do { switch myData.jamfResponse { case 401: errorOccured(typeOfError: "Login Incorrect.") case 400: errorOccured(typeOfError: "Bad Request: You sent a request that this server could not understand.") case 404: errorOccured(typeOfError: "User not found.") case 1: errorOccured(typeOfError: "Could not connect to Server") case 200: let userdetails = try decoder.decode(userSearch.self, from: myData.jamfDataOutput)

let userInfoString = """ (userdetails.user.full_name) (userdetails.user.email) (userdetails.user.phone_number) """ let emailStringLength = userdetails.user.email.count + 1 let attributedString = NSMutableAttributedString(string: userInfoString) attributedString.addAttribute(.link, value: "mailto: (userdetails.user.email)", range: NSRange(location: userdetails.user.full_name.count, length: emailStringLength ))

userInfo.attributedStringValue = attributedString

for entries in userdetails.user.links.mobiledevices { listOfmobiledevicesIDs.insert(entries.id as Int, at: 0) listOfmobiledevices.insert(entries.name as String, at: 0) tableView.insertRows(at: IndexSet(integer: 0)) } default: errorOccured(typeOfError: "A connection error occured. Sorry") //NSApplication.shared.terminate(self) }

} catch { errorOccured(typeOfError: "Unknown error occured. Sorry") //NSApplication.shared.terminate(self) } }

func keychainlogin(server: String) throws -> (KCUsername: String, KCPassword: String) { let query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, kSecAttrServer as String: server, kSecMatchLimit as String: kSecMatchLimitOne, kSecReturnAttributes as String: true, kSecReturnData as String: true]

var item: CFTypeRef? let status = SecItemCopyMatching(query as CFDictionary, &item) guard status != errSecItemNotFound else { throw KeychainError.noPassword } guard status == errSecSuccess else { throw KeychainError.unhandledError(status: status) }

guard let existingItem = item as? [String : Any], let passwordData = existingItem[kSecValueData as String] as? Data, let keychainpassword = String(data: passwordData, encoding: String.Encoding.utf8), let keychainaccount = existingItem[kSecAttrAccount as String] as? String else { throw KeychainError.unexpectedPasswordData }

return(keychainaccount, keychainpassword) }

func readPlist(){

prefs.server = UserDefaults.standard.string(forKey: "jss_URL") ?? "" prefs.name = UserDefaults.standard.string(forKey: "EA_NAME") ?? "" prefs.id = UserDefaults.standard.string(forKey: "EA_ID") ?? ""

}
}


boberito
Forum|alt.badge.img+22
  • Jamf Heroes
  • 451 replies
  • March 17, 2019

You may wanna edit your post so it's posted more like code or quoted. The >_ will let you post scripts/code


Forum|alt.badge.img+1
  • New Contributor
  • 9 replies
  • March 17, 2019
1import Cocoa
2
3//login class
4class jamfInfo {
5 var server: String?
6 var id: String?
7 var name: String?
8 var username: String = ""
9 var password: String = ""
10}
11
12struct userSearch: Decodable {
13 let user: listOfUsers
14
15 struct listOfUsers: Decodable {
16 let name: String
17 let full_name: String
18 let email: String
19 let phone_number: String
20 let links: listOfmobiledevices
21
22 struct listOfmobiledevices: Decodable {
23 let mobiledevices: [mobiledevices]
24
25 struct mobiledevices: Decodable {
26 let name: String
27 let id: Int
28
29 }
30 }
31 }
32}
33
34struct extensionAttribute: Decodable {
35 let mobiledevices: mobiledevicesEA
36
37 struct mobiledevicesEA: Decodable {
38 let extension_attributes: [EA]
39
40 struct EA: Decodable {
41 let id: Int
42 let name: String
43 let value: String
44 }
45
46 }
47
48}
49
50class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
51
52 @IBOutlet var userInfo: NSTextField!
53 @IBOutlet var tableView: NSTableView!
54 @IBOutlet var JamfPassword: NSSecureTextField!
55 @IBOutlet var jamfUser: NSTextField!
56 @IBOutlet var userNameField: NSTextFieldCell!
57 @IBOutlet var toggleButton: NSButtonCell!
58
59 var listOfmobiledevices = [String]()
60 var listOfmobiledevicesIDs = [Int]()
61 var listOfEAs = [String]()
62
63 var prefs = jamfInfo()
64
65 override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
66 let second = segue.destinationController as! PrefController
67 readPlist()
68 prefs.username = jamfUser.stringValue
69 prefs.password = JamfPassword.stringValue
70 second.representedObject = prefs
71 listOfmobiledevices.removeAll()
72 tableView.reloadData()
73
74
75 }
76
77 override func viewDidLoad() {
78 super.viewDidLoad()
79
80 readPlist()
81 if prefs.server != nil {
82 let keychainVar = try? keychainlogin(server: prefs.server!)
83 if keychainVar != nil {
84 prefs.username = keychainVar!.KCUsername
85 prefs.password = keychainVar!.KCPassword
86 jamfUser.stringValue = prefs.username
87 JamfPassword.stringValue = prefs.password
88 }
89 }
90
91 toggleButton.isEnabled = false
92 // Do any additional setup after loading the view.
93 }
94
95 @IBAction func preferencesMenuItemSelected(_ sender: Any) {
96 self.performSegue(withIdentifier: "prefSegue", sender: self)
97 }
98
99 @IBAction func doSomething(_ sender: Any) {
100 readPlist()
101 getTableView()
102 }
103
104 func numberOfRows(in tableView: NSTableView) -> Int {
105 return listOfmobiledevices.count
106 }
107
108 func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
109
110 guard let vw = tableView.makeView(withIdentifier: tableColumn!.identifier, owner: self) as? NSTableCellView else { return nil }
111
112 if tableColumn?.title == "Computer List" {
113 vw.textField?.stringValue = listOfmobiledevices[row]
114
115 } else {
116 var eaOutput: Data?
117 readPlist()
118 eaOutput = getJamfData(url: "(prefs.server!)JSSResource/mobiledevices/id/(listOfmobiledevicesIDs[row])/subset/ExtensionAttributes").jamfDataOutput
119
120 let EAdecoder = JSONDecoder()
121 let EADetails = try! EAdecoder.decode(extensionAttribute.self, from: eaOutput!)
122
123 for EAs in EADetails.mobiledevices.extension_attributes {
124 if EAs.id == Int(prefs.id!) {
125 vw.textField?.stringValue = EAs.value
126 listOfEAs.insert(EAs.value, at: 0)
127 break;
128 } else {
129 vw.textField?.stringValue = ""
130 listOfEAs.insert("", at: 0)
131 }
132 }
133
134 }
135 return vw
136 }
137
138
139 func tableViewSelectionDidChange(_ notification: Notification) {
140
141 if tableView.selectedRow != -1 {
142 toggleButton.isEnabled = true
143 } else {
144 toggleButton.isEnabled = false
145 }
146
147 }
148
149 func getJamfData(url: String) -> (jamfDataOutput: Data, jamfResponse: Int) {
150 let loginData = "(jamfUser.stringValue):(JamfPassword.stringValue)".data(using: String.Encoding.utf8)
151 let base64LoginString = loginData!.base64EncodedString()
152 let headers = ["Accept": "application/json",
153 "Authorization": "Basic (String(describing: base64LoginString))"]
154
155 let request = NSMutableURLRequest(url: NSURL(string: url)! as URL,
156 cachePolicy: .useProtocolCachePolicy,
157 timeoutInterval: 10.0)
158 request.httpMethod = "GET"
159 request.allHTTPHeaderFields = headers
160
161
162 var dataReturn: Data?
163 var ResponseCode: HTTPURLResponse?
164
165
166 let dispatchGroup = DispatchGroup()
167 dispatchGroup.enter()
168
169 let session = URLSession.shared
170
171 let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
172 if let APIdata = data {
173 dataReturn = APIdata
174 ResponseCode = response as? HTTPURLResponse
175
176 }
177 dispatchGroup.leave()
178 })
179 dataTask.resume()
180 dispatchGroup.wait()
181 if dataReturn == nil {
182 dataReturn = "".data(using: String.Encoding.utf8)
183
184 }
185 var ResponseStatusCode: Int
186 if ResponseCode == nil {
187 ResponseStatusCode = 1
188 } else {
189 ResponseStatusCode = (ResponseCode?.statusCode)!
190 }
191 return(dataReturn!, ResponseStatusCode)
192
193 }
194
195 @IBAction func toggle(_ sender: Any) {
196 readPlist()
197 guard tableView.selectedRow != -1 else { return }
198 var action: String = ""
199
200 if listOfEAs[tableView.selectedRow] != "Enabled" {
201 action = "Enabled"
202 } else {
203 action = "Disabled"
204 }
205 var xmldata: String
206
207 let requestURL = "(prefs.server!)JSSResource/mobiledevices/id/(listOfmobiledevicesIDs[tableView.selectedRow])"
208
209 xmldata = "<?xml version="1.0" encoding="UTF-8" standalone="no"?><mobiledevices><extension_attributes><extension_attribute><id>" + prefs.id! + "</id><name>" + prefs.name! + "</name><type>String</type><value>" + action + "</value></extension_attribute></extension_attributes></mobiledevice>"
210
211 let loginData = "(jamfUser.stringValue):(JamfPassword.stringValue)".data(using: String.Encoding.utf8)
212 let base64LoginString = loginData!.base64EncodedString()
213 let postData = NSData(data: xmldata.data(using: String.Encoding.utf8)!)
214 let headers = ["Content-Type": "text/xml", "Authorization": "Basic (String(describing: base64LoginString))"]
215 let request = NSMutableURLRequest(url: NSURL(string: requestURL)! as URL,cachePolicy: .useProtocolCachePolicy,timeoutInterval: 10.0)
216 request.httpMethod = "PUT"
217 request.allHTTPHeaderFields = headers
218 request.httpBody = postData as Data
219
220 let dispatchGroup = DispatchGroup()
221 dispatchGroup.enter()
222
223 let session = URLSession.shared
224 let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
225
226 dispatchGroup.leave()
227 }
228 )
229
230 dataTask.resume()
231
232 dispatchGroup.wait()
233
234
235 getTableView()
236 toggleButton.isEnabled = true
237
238 }
239
240 func errorOccured(typeOfError: String){
241 let alert = NSAlert()
242 alert.messageText = "Error"
243 alert.informativeText = typeOfError
244 alert.runModal()
245 }
246
247 func getTableView(){
248 listOfmobiledevices.removeAll()
249 tableView.reloadData()
250
251 let myData = getJamfData(url: "(prefs.server!)JSSResource/users/name/(userNameField.stringValue)")
252
253
254 let decoder = JSONDecoder()
255 do {
256 switch myData.jamfResponse {
257 case 401:
258 errorOccured(typeOfError: "Login Incorrect.")
259 case 400:
260 errorOccured(typeOfError: "Bad Request: You sent a request that this server could not understand.")
261 case 404:
262 errorOccured(typeOfError: "User not found.")
263 case 1:
264 errorOccured(typeOfError: "Could not connect to Server")
265 case 200:
266 let userdetails = try decoder.decode(userSearch.self, from: myData.jamfDataOutput)
267
268 let userInfoString = """
269 (userdetails.user.full_name)
270 (userdetails.user.email)
271 (userdetails.user.phone_number)
272 """
273 let emailStringLength = userdetails.user.email.count + 1
274 let attributedString = NSMutableAttributedString(string: userInfoString)
275 attributedString.addAttribute(.link, value: "mailto: (userdetails.user.email)", range: NSRange(location: userdetails.user.full_name.count, length: emailStringLength ))
276
277 userInfo.attributedStringValue = attributedString
278
279 for entries in userdetails.user.links.mobiledevices {
280 listOfmobiledevicesIDs.insert(entries.id as Int, at: 0)
281 listOfmobiledevices.insert(entries.name as String, at: 0)
282 tableView.insertRows(at: IndexSet(integer: 0))
283 }
284 default:
285 errorOccured(typeOfError: "A connection error occured. Sorry")
286 //NSApplication.shared.terminate(self)
287 }
288
289 } catch {
290 errorOccured(typeOfError: "Unknown error occured. Sorry")
291 //NSApplication.shared.terminate(self)
292 }
293 }
294
295 func keychainlogin(server: String) throws -> (KCUsername: String, KCPassword: String) {
296 let query: [String: Any] = [kSecClass as String: kSecClassInternetPassword,
297 kSecAttrServer as String: server,
298 kSecMatchLimit as String: kSecMatchLimitOne,
299 kSecReturnAttributes as String: true,
300 kSecReturnData as String: true]
301
302 var item: CFTypeRef?
303 let status = SecItemCopyMatching(query as CFDictionary, &item)
304 guard status != errSecItemNotFound else { throw KeychainError.noPassword }
305 guard status == errSecSuccess else { throw KeychainError.unhandledError(status: status) }
306
307 guard let existingItem = item as? [String : Any],
308 let passwordData = existingItem[kSecValueData as String] as? Data,
309 let keychainpassword = String(data: passwordData, encoding: String.Encoding.utf8),
310 let keychainaccount = existingItem[kSecAttrAccount as String] as? String
311 else {
312 throw KeychainError.unexpectedPasswordData
313 }
314
315 return(keychainaccount, keychainpassword)
316 }
317
318 func readPlist(){
319
320 prefs.server = UserDefaults.standard.string(forKey: "jss_URL") ?? ""
321 prefs.name = UserDefaults.standard.string(forKey: "EA_NAME") ?? ""
322 prefs.id = UserDefaults.standard.string(forKey: "EA_ID") ?? ""
323
324 }
325}

boberito
Forum|alt.badge.img+22
  • Jamf Heroes
  • 451 replies
  • March 18, 2019

Without running it against your Jamf server and everything it's hard to tell. But it sounds like you're potentially receiving some error from the request. So that's why you see data get returned, just a very small amount.


Forum|alt.badge.img+4
  • Contributor
  • 11 replies
  • April 18, 2020

Forum|alt.badge.img+5
  • Contributor
  • 31 replies
  • April 1, 2021

@adamnewman I was wondering if you completed your project and/or if it's available on Github anywhere? I'm grappling with something similar and it looks like your project would answer a few questions.


Forum|alt.badge.img+5
  • Contributor
  • 32 replies
  • June 17, 2021

Any chances someone could update this with working code? Those git links are dead and the ones I've been able to find are written in old Swift 2 or 3 code which no longer works. I can use PHP to access the API no worries but when using Swift, I just keep getting

CredStore - performQuery - Error copying matching creds. Error=-25300, query={ class = inet; "m_Limit" = "m_LimitAll"; ptcl = htps; "r_Attributes" = 1; sdmn = "Restful JSS Access -- Please supply your credentials"; srvr = "<URLREMOVED>"; sync = syna; }

even though I'm sending the Basic Auth in the HTTP headers.


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings