Using the Graph API with Account Kit

You can use the Account Kit Graph API to retrieve and verify user access tokens, access basic account information, and delete accounts.

Access Tokens

Calls to these APIs use an Access Token for temporary, secure access to Account Kit APIs. The security model is the same as Facebook Access Tokens. There are two types of access tokens to be aware of for Account Kit, user access tokens and app access tokens.

User Access Tokens

User Access Tokens are obtained through the client SDKs on both iOS and Android. After a successful login, or anytime while a session is still active, use the getCurrentAccessToken method to return the user access token.

You can use this token to validate the identity of a user when making server API calls. By using the validation method here on your API server, you can be sure of the identity of the user of your server APIs.

App Access Tokens

App Access Tokens allow you to make server calls on behalf of your application. These are useful for account management operations that a user may not have access to, such as reading a list of all users, and for protecting the initial login request.

App access tokens are the concatenation of your app ID and your app secret. They take the form

AA|<facebook_app_id>|<app_secret>

You should not store your app secret on a mobile device, so these are reserved for server to server calls.

If you need to make server calls from a device, you should use the client secret instead. App access tokens for calls originating from a device therefore take the form AA|<facebook_app_id>|<client_token>.

You can find both the app secret and the client token in the app dashboard for your app, under the Account Kit tab.

App Secret Proof

If you have enabled the Require App Secret setting in your app's dashboards, most calls that accept an account access token as a parameter will now require an additional appsecret_proof parameter to verify that these calls are coming from your own servers.

The app secret proof is a sha256 hash of your access token, using the app secret as the key. Here's what the call looks like in PHP:

$appsecret_proof = hash_hmac('sha256', $access_token, $app_secret); 

You add the result as an appsecret_proof parameter to each call you make. An example using curl:

curl \
  -F 'access_token=<access_token>' \
  -F 'appsecret_proof=<app secret proof>' \
  https://graph.accountkit.com/v1.2/me

Retrieving User Access Tokens with an Authorization Code

If your app is using the authorization code flow, your client application will not receive the User Access Token directly, but will instead receive an Authorization Code. This code is meant to be passed to your server, which will exchange it for a User Access Token. After the token is retrieved, it will continue to reside on the server and may be used to authenticate server-to-server calls.

The exchange of an Authorization Code for a User Access Token is done with an Account Kit API call.

GET https://graph.accountkit.com/v1.2/access_token?grant_type=authorization_code&code=<authorization_code>&access_token=AA|<facebook_app_id>|<app_secret>

The final argument of the URL query string is the App Access Token described above.

If the code is valid and not expired, the Account Kit API will respond with a User Access Token.

{
  "id" : <account_kit_user_id>,
  "access_token" : <account_access_token>,
  "token_refresh_interval_sec" : <refresh_interval>
}

Access Token Validation

When your app makes API calls to your server, validate the user's identity by verifying their access token. The User Access Token is available from each SDK while a user is logged in. Validate a User Access Token by accessing the Account Kit API on the Account ID edge and passing the User Access Token as a parameter.

GET https://graph.accountkit.com/v1.2/me/?access_token=<access_token>

Return type:

This returns the Account ID associated with this User Access Token pair if it's valid. Invalid access tokens will return an error. This response will also include the current associated login info, such as email or phone number.

Account Kit Account IDs are guaranteed not to collide with Facebook User IDs.

{  
   "id":"12345",
   "phone":{  
      "number":"+15551234567"
      "country_prefix": "1",
      "national_number": "5551234567"
   }
}

Logging Out of a Session

You can log specific sessions out, or you can log out all sessions for an account. To log an individual session out, call the following endpoint with the session client access token. This call invalidates the session access token.

https://graph.accountkit.com/v1.2/logout?access_token={user_access_token}

To log out all sessions for your account ID, call the following endpoint with the account ID and app secret. This call invalidates all access tokens for that account.

https://graph.accountkit.com/v1.2/{account_id}/invalidate_all_tokens?access_token={app_secret}

Account Removal

You can delete an account from the database stored on Account Kit servers with a call to the DELETE endpoint.

DELETE https://graph.accountkit.com/v1.2/<account_id>?access_token=AA|<facebook_app_id>|<app_secret>

Fields:

Property Name Description Type

access_token

The App Access Token, required for server to server calls

String

Return type:

{
  "success": true
}

If the operation is unsuccessful, an error will be returned indicating the reason for the failure.

Removing Account Kit From Your App and Retrieving Your User Data

You can remove Account Kit from your app by way of the App Dashboard. After you remove Account Kit, you can activate a Graph API endpoint from which you can retrieve the Account Kit user data for your app. This endpoint is available for 30 days after you remove Account Kit.

To remove Account Kit:

  1. Go to the App Dashboard and select your app.
  2. In the left-hand menu, select Account Kit.
  3. Click the Remove Account Kit button at the bottom left.
  4. In the Are You Sure? dialog, click Yes, Remove Account Kit.
  5. Enter your password, and click Submit.

For 30 days after you remove Account Kit, the Account Kit page for you app displays a button that let's you undo the removal, and it displays a button to activate the endpoint for retrieving your data.

Retrieving Your User Data

If you want to retrieve the Account Kit user data for your app, you need to activate the Graph API endpoint and then call it with your Facebook app ID, Account Kit app secret, and the number of users you want per page of data.

To activate the endpoint for retrieving Account Kit user data:

  1. Go to the Account Kit page for your app in the App Dashboard.
  2. Click the Request Account Kit Data button at the bottom of the page.
  3. Make a note of your Account Kit app secret. You will need it to retrieve your user data from the endpoint.

You retrieve your user data by calling the provided endpoint within 30 days of removing Account Kit.

GET https://graph.accountkit.com/v1.2/<app_id>/accounts/?&access_token=AA|<app_id>|<account_Kit_app_secret>&limit=<items_per_page>
Parameter Description

app_id

The Facebook app ID of your app

account_kit_app_secret

Your Account Kit – specific app secret

items_per_page

The number of users per page for whom data is returned. The range is 1–1000.

The data for each user is returned in the following format.

{
   "data": [
     {
       "id": "<user ID>",
       "phone": {
                "number": "+<phone number>",
                "country_prefix": "<country_dialing_prefix>",
                "national_number": "<region_dialing_code>"
                }
     }
   ],
   "paging": {
             "cursors": {
                        "before": "<cursor_to_previous_page>",
                         "after": "<cursor_to_following_page>"
             },
             "previous": "<URL_for_retrieving_the_previous_page>"
             "next": "<URL_for_retrieving_the_next_page>"
     }
}

The previous URL doesn't appear on the first page of data, and the next URL doesn't appear on the last page.

You can also use the following script to retrieve your data and output it as a comma-separated list. Copy the script to a Python file and call it from the command line. The script prompts you for the following parameters:

  • Your app ID
  • You Account Kit app secret
  • The number of users per page of returned data
  • The file to which to write the data
  • The Account Kit API version number

To get help for the script, enter -h.

import ssl
import json
import urllib2


output_file_name = 'accountkit_export.csv'
url_fmt = 'https://graph.accountkit.com/{version}/{app_id}/accounts/?access_token=AA|{app_id}|{app_secret}&limit={limit}'
header_string = 'ID, Phone, Email'
E_FAILED = 'failed'
E_RETRY = 'retry'

import argparse
def parse_args(parser):
    parser.add_argument('-a', '--appid', type=int, help='Your facebook application id', required=True)
    parser.add_argument('-s', '--appsecret', help='Your application secret', required=True)
    parser.add_argument('-l', '--limit', type=int, default=1000, help='Number of items per the page. Range 1 to 1000')
    parser.add_argument('-f', '--file', default=output_file_name, help='Name of the output file')
    parser.add_argument('-v', '--version', default='v1.2', help='Api version')
    return parser.parse_args()

import re
def verify_params(params):
    error_msg = ''
    if (params.limit < 1 or params.limit > 1000):
        error_msg = 'limit should be in the range 1-1000'
    elif (re.match(r'^v\d+\.\d+$', params.version) == None):
        error_msg = 'double check your api version number'
    return error_msg

def get_url_config(params):

    config = {
        'version':    params.version,
        'app_id':     params.appid,
        'app_secret': params.appsecret,
        'limit':      params.limit
    }
    return config

def get_json_attrs(jdata, *names):
    if (not jdata):
        raise Exception('empty json data')

    val = jdata
    for name in names:
        try:
            val = val[name]
            if (not val):
                return None
        except:
            return None
    return val

def get_request_data_in_csv_format(url):
    try:
        response = urllib2.urlopen(url, context=get_request_data_in_csv_format.gcontext)
    except urllib2.HTTPError as e:
        print 'HTTPError = ' + str(e.code)
        print e.read()
        raise Exception(E_RETRY)
    except urllib2.URLError as e:
        print 'URLError = ' + str(e.reason)
        raise Exception(E_FAILED)
    except Exception as e:
        print e
        raise Exception(E_FAILED)

    try:
        json_resp = json.loads(response.read())
    except Exception as e:
        print e
        raise Exception(E_FAILED)

    try:
        next_url = get_json_attrs(json_resp, 'paging', 'next')
    except Exception as e:
        print e
        raise Exception(E_FAILED)

    data = json_resp['data']
    result = ''
    for ditem in data:
        try:
            acc_id = get_json_attrs(ditem, 'id')
            ph_num = get_json_attrs(ditem, 'phone', 'number');
            email = get_json_attrs(ditem, 'email', 'address');
            result = result + '{},{},{}\n'.format(acc_id, ph_num, email)
        except Exception as e:
            print e
            raise Exception(E_FAILED)

    return {
        'next_url': next_url,
        'csv_data': result
    }

def export_to_file(file, url):
    file.write(header_string + '\n')

    current_url = url
    retry = 0
    while current_url != None:
        try:
            print 'Quering url ' + current_url
            data = get_request_data_in_csv_format(current_url)

        except Exception as e:
            if (e[0] == E_RETRY and retry < 3):
                retry = retry + 1
                print 'retrying: ' + retry + ' with url ' + current_url
            else:
                raise Exception('abort')
        else:
            file.write(data['csv_data'])
            retry = 0
            current_url = data['next_url']

def main():
    parser = argparse.ArgumentParser()
    params = parse_args(parser)
    error_msg = verify_params(params)
    if (error_msg != ''):
        print 'ERROR:' + error_msg
        parser.print_help()
        return

    get_request_data_in_csv_format.gcontext = ssl.create_default_context()

    config = get_url_config(params)
    url = url_fmt.format(**config)
    try:
        file = open(params.file, 'w')
        print 'File opened for Write: ' + params.file
        try:
            export_to_file(file, url)
        except:
            print 'Could not export to a file'
    except:
        print 'Could not open file'
    else:
        print 'File closed'
        file.close();

if __name__ == "__main__":
    main()