UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

How to figure out the Sign In With Apple Token Revocation requirements after June 30th?

Forums > iOS

Hey everyone!

I have been investigating the upcoming June 30th requirements from Apple regarding apps that offer account creation with Apple Auth (they now require deletion, and part of that requirement is revoking tokens). Revoking tokens, to my knowledge, removes the Apple ID association to the app. So when you go back to the app and create a new account, you will actually be prompted as though you are a brand new user again (instead of using your old associated Apple ID credentials which were bound to the app in your settings).

I am not very confident in my solution, I have an attempted solution, but the status code always returns 200 no matter what my input is. I havn't been able to test this thoroughly and am hoping to get some feedback or critique on my approach.

I have posted the question here, as well: https://stackoverflow.com/questions/72399534/how-to-make-apple-sign-in-revoke-token-post-request

The update from Apple: https://developer.apple.com/news/?id=12m75xbj

The following functions live in the same class (ViewModel). The first does my login/registration flow. Some of it is a bit custom, but you can see I grab the token string and nonce for client_secret. The second function resembles the POST request for token revocation (which gets called from a delete account function not shown). I did not include my delete account function as it doesn't add value to the problem. The first function is used to assign the two values to app storage, and the second function would be called from my delete account method to perform the POST request.

public func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
    // Sign in using Firebase Auth
    if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
        guard let nonce = currentNonce else {
            print("Invalid state: A login callback was received, but no login request was sent.")
            return
        }

        // JWT
        guard let appleIDToken = appleIDCredential.identityToken else {
            print("Unable to fetch identity token")
            return
        }

        guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
            print("Unable to serialize token string from data")
            return
        }

        let credential = OAuthProvider.credential(withProviderID: "apple.com", idToken: idTokenString, rawNonce: nonce)
        Auth.auth().signIn(with: credential) { result, error in
            if error != nil {
                print(error!.localizedDescription)
                return
            }
            else { // successful auth, we can now check if its a login or a registration
                guard let user = Auth.auth().currentUser else {
                    print("No user was found.")
                    return
                }
                let db = Firestore.firestore()
                let docRef = db.collection("Users").document(("\(user.uid)"))
                docRef.getDocument{ (document, error) in
                    if let document = document, document.exists {
                        // User is just logging in, their db store exists
                        print("Successful Apple login.")

                        // Token revocation requirements
                        self.clientSecret = nonce
                        self.appleToken = idTokenString

                        if (self.isDeletingAccount == true) {
                            print("Is deleting account.")
                            self.isReauthenticated = true
                        }
                        self.isLogged = true
                    }
                    else { // document does not exist! we are registering a new user
                        db.collection("Users").document("\(user.uid)").setData([
                            "name": "\(appleIDCredential.fullName?.givenName ?? "")"
                        ])
                        print("Successful Apple registration.")

                        self.clientSecret = nonce
                        self.appleToken = idTokenString

                        self.isLogged = true
                    }
                }
            }
        }
    }
}

// POST request to revoke user's Apple token from Barfix app
func appleAuthTokenRevoke(completion: (([String: Any]?, Error?) -> Void)? = nil) {

    let paramString: [String : Any] = [
        "client_id": Bundle.main.bundleIdentifier!, //"com.MyCompany.Name",
        "client_secret": self.clientSecret,
        "token": self.appleToken,
        "token_type_hint": "access_token"
    ]

    let url = URL(string: "https://appleid.apple.com/auth/revoke")!

    var request = URLRequest(url: url)
    request.httpMethod = "POST"

    do {
        request.httpBody = try JSONSerialization.data(withJSONObject: paramString, options: .prettyPrinted)
    }
    catch let error {
        print(error.localizedDescription)
        completion?(nil, error)
    }

    request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

    let task =  URLSession.shared.dataTask(with: request as URLRequest)  { (data, response, error) in
        guard let response = response as? HTTPURLResponse, error == nil else {
            print("error", error ?? URLError(.badServerResponse))
            return
        }

        guard (200 ... 299) ~= response.statusCode else {
            print("statusCode should be 2xx, but is \(response.statusCode)")
            print("response = \(response)")
            return
        }

        if let error = error {
            print(error)
        }
        else {
            print("deleted accont")
        }
    }
    task.resume()
}

3      

Hi! have you make this deletion thing works?? i´m on the same situation, completely newby with swiftui and need to deliver an app with this feature running to publish in the appStore

4      

@germanRosso

Apologies for late reply.

The following solution assumes you are able to run some server-side code. In this case, it is with the Firebase functions feature which containerizes the JS module displayed in this github readme.

https://github.com/jooyoungho/apple-token-revoke-in-firebase

This is the template I followed to successfully implement everything.

3      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.