Skip to content

Instantly share code, notes, and snippets.

@aperfect
Created April 13, 2023 08:52
Show Gist options
  • Save aperfect/f494220e549112db295d61c5b9b8ac6a to your computer and use it in GitHub Desktop.
Save aperfect/f494220e549112db295d61c5b9b8ac6a to your computer and use it in GitHub Desktop.
CloudKit server-to-server Swift authentication example
// Swift example for Apple CloudKit server-to-server token authentication
// See: https://developer.apple.com/library/archive/documentation/DataManagement/Conceptual/CloudKitWebServicesReference/SettingUpWebServices.html#//apple_ref/doc/uid/TP40015240-CH24-SW6
import Foundation
import CryptoKit
import Network
// Set up your body JSON
let body = ["": ""]
let bodyData = try! JSONSerialization.data(withJSONObject: body)
// hash then base64-encode the body
let bodyHash = SHA256.hash(data: bodyData)
let body64 = Data(bodyHash).base64EncodedString()
// set up ISO8601 date string, at UTC
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
let date = dateFormatter.string(from: Date())
// endpoint path you want to query
let path = "/database/1/iCloud.SceneMapper/development/public/zones/list"
// create the concatenated date, encoded body and subpath
let message = date + ":" + body64 + ":" + path
// Your private key (as generated following the Apple docs above)
let keyPem =
"""
-----BEGIN EC PRIVATE KEY-----
YOUR KEY HERE
-----END EC PRIVATE KEY-----
"""
// Set up the key and get ECDSA signature
let privateKey = try? P256.Signing.PrivateKey(pemRepresentation: keyPem)
let sign = try? privateKey?.signature(for: SHA256.hash(data: message.data(using: .utf8)!))
//let sign = try? privateKey?.signature(for: message.data(using: .utf8)!)
let signatureBase64 = sign!.derRepresentation.base64EncodedString()
// Your server-to-server key from the CloudKit dashboard
let keyID = "your_key_here"
// Set up the full URI
let url = URL(string: "https://api.apple-cloudkit.com" + path)!
var request = URLRequest(url: url)
// Set CloudKit-required headers
request.setValue(keyID, forHTTPHeaderField: "X-Apple-CloudKit-Request-KeyID")
request.setValue(date, forHTTPHeaderField: "X-Apple-CloudKit-Request-ISO8601Date")
request.setValue(signatureBase64, forHTTPHeaderField: "X-Apple-CloudKit-Request-SignatureV1")
// Request method
request.httpMethod = "POST"
// Our original body data for the request
request.httpBody = bodyData
// Create the request
let session = URLSession.shared
let task = session.dataTask(with: request) { (data, response, error) in
if let error {
print(error)
} else if let data {
let json = try! JSONSerialization.jsonObject(with: data)
print(json)
} else {
// Handle uncaught error
}
}
task.resume()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment