Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make Apple Sign In Revoke Token POST Request?

How do I structure a swift POST request to satisfy the Sign In With Apple token revocation requirements?

I am not sure what form-data, client_id, client_secret, token, or token_type_hint are supposed to be. I was able to implement Sign in With Apple to create a user, but very lost on the revocation part of this.

I am looking to perform this client-side with Swift, as that would be the most convenient. Firebase may be developing a solution built into their SDK, but not sure if that is a one-size fits all solution for developers using Firebase.

https://developer.apple.com/documentation/sign_in_with_apple/revoke_tokens#url

Edit: source of requirements https://developer.apple.com/support/offering-account-deletion-in-your-app

The following functions live in the same class (ViewModel). The first does my login/registration flow. Some of the code is related to Firebase flows and can be largely ignored, 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). Has anyone had success with this approach/boilerplate?

Testing the token revocation method below with a button tap in my app returns status code 400. I cannot revoke tokens with this method, and I am not sure what else to do.

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 
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()
}

1 Answers

For any one who wants to implement account deletion with flutter , swift or react .

Before you continue reading , take a moment to read the api requirement of two urls you will need to complete the revoking process.

  • https://developer.apple.com/documentation/sign_in_with_apple/revoke_tokens
  • https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens

The link below shows how to do this with iOS(swift) and firebase using firebase functions .And by reading it you can implement a solution with the other SDKs i.e flutter , react-native etc.

Implementing account deletion with apple and firebase

But in an attempt to summarise :-

  1. When you go through the process of setting up Sign In with Apple you will need to create a key in your apple developer account that comes in a file form which can be downloaded and should be download on to your device and looks like "*********.p8" where the * stands for a bunch of numbers and words usually representing the key.This apple refers to as the private associated key.

2.This you will use to create a Jwt using popular libraries of your own choosing .which then becomes the client_secret parameter for apple's api end point .

  1. When you then sign in a user you get an authorisation code(NB:Is the code parameter for token generation endpoint) which you will then make an api call endpoint to generate a token which then become the token parameter for the revoke endpoint .

4.Finally you call the revoke endpoint with the parameters from the above processes .

NB: I believe the solution above is so far the best way assuming that you secure your key on the server side. and unless you have a way of scrambling the key you should not attempt to store this in your project(or app).

like image 199
Agyakwalf Avatar answered Jan 20 '26 18:01

Agyakwalf



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!