Created
April 13, 2023 08:52
-
-
Save aperfect/f494220e549112db295d61c5b9b8ac6a to your computer and use it in GitHub Desktop.
CloudKit server-to-server Swift authentication example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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