Facebook Data Deletion Request Callback
Tags: facebook, deletion, callback, rails
Published: 2021-02-10 20:27:40

### **INTRODUCTION:**

In order to provide user more control over data and to protect data privacy norms, facebook gives option to remove all data consumed by the apps and integrations. A common use case scenario is When a user authenticates with Facebook to use application's services, his profile details are stored by the app. User can send a request to your app to delete his facebook consumed data afterwards.

You can check more about it [here](https://developers.facebook.com/docs/development/create-an-app/app-dashboard/data-deletion-callback/)

### **Why is it necessary?**

As a developer we need to implement a Data Deletion Request callback url to get our app passed for Facebook compliance when user request to delete his/her data. This is mandatory as per new data privacy policy, GDPR. Also we can't submit our app for Review and switch to Live mode without implementing it


### **Implement the Callback URL:**

We have to make a POST web API endpoint on our server, where we'll receive requests from Facebook. Our endpoint must be **HTTPS** enabled and preserve the functionality to parse signed request token sent by Facebook and take further actions to delete user's data.

### **Actual Code in Rails:**

```
  def facebook_user_deletion
    signed_request = params['signed_request']
    data = parse_fb_signed_request(signed_request)

    # Do data deletion stuff then
    user = User.find_by(uid: data['user_id'])
    user.destroy

    # Return tracking url and code to Facebook
    data = { url: "#{ENV['APP_HOST_URL']}/deletion_status?id=del_#{user.id}", confirmation_code: "del_#{user.id}" }

    respond_to do |format|
      format.json { render :json => data }
    end
  end

  def parse_fb_signed_request(signed_request)
    encoded_sig, payload = signed_request.split('.', 2)
    secret = ENV['FACEBOOK_SECRET_ID']

    # Decode the data
    decoded_sig = Base64.urlsafe_decode64(encoded_sig)
    data = JSON.load(Base64.urlsafe_decode64(payload))

    # Create the HMAC signature
    expected_sig = OpenSSL::HMAC.digest("SHA256", secret, payload)

    if decoded_sig != expected_sig
      puts 'Bad Signed JSON signature!'
      return nil
    end

    data
  end
```

### **EXPLANATION:**

Our `facebook_user_deletion` method is the endpoint where request is received. Firstly we are getting signed_request token from the params hash and passing it to our `parse_fb_signed_request` method as a parameter which will parse it and return user's data JSON object like this:

```
{
   "algorithm": "HMAC-SHA256",
   "expires": 1291840400,
   "issued_at": 1291836800,
   "user_id": "218471"
}
 ```
In this object user_id is our relevant field which we are using to find the user and destroy it.

After that we are returning a JSON response object to Facebook, which has url and confirmation code key-value pairs. Basically this url exists on our server in the form of a webpage where user can check status of his request by using his own confirmation code.

> I am using some interpolation inside values to dynamically inject user ids. Also ENV['APP_HOST_URL'] is an environment variable which holds my app's default host url.

In `parse_fb_signed_request` method we split the token into two parts with reference to dot(.) to obtain encoded signature and payload. 
Then we get app's facebook secret id which will be used to construct the expected signature

For decoding signature and payload I've used `Base64.urlsafe_decode64` method, afterwards decoded payload 
is loaded into JSON object and stored in `data` variable

You can learn more about Base64 and JSON.load methods here:
> [Base64](https://ruby-doc.org/stdlib-2.6.3/libdoc/base64/rdoc/Base64.html)
> [JSON.load](https://apidock.com/ruby/JSON/load)

After that we are creating an HMAC signature using SHA256 algorithm, app's secret and payload object. Finally an `If` conditional block confirms the signature by comparing the decoded and newly created signature, thus returning `nil` object when block fails otherwise it returns data

### **Add API endpoint as Callback in Facebook Project App:**
Go to [App Dashboard](https://developers.facebook.com/apps/) > Products > Facebook Login > Settings > Data Deletion Requests

### **Testing your Callback:**
1. Log in to your app with Facebook Login.
2. Go to [app settings](https://www.facebook.com/settings?tab=applications)
3. Remove your app.
4. In the Removed section, click on your app.
5. Request data deletion from the app card.