113

I'm developing iPhone application, that is based on communication with server, and I want to use Facebook authentication mechanisms.

Basically, I think it should work like this:

  1. In my iPhone app, user logs in to Facebook, using his email and password.
  2. User allows access to his data for related Facebook application.
  3. My iPhone app receives access token, after successful log in.
  4. In further communication with my server, my iPhone application should use the received Facebook access token (for example: in queries).
  5. When my server receives some query from iPhone app, with access token, it should ask Facebook that this token is valid (and for who), and if yes, server should assume that user is authenticated with Facebook.

My question is: how the server should ask Facebook if given access token is valid? I think I should somehow check if the token is valid for my Facebook app.

I've tried many Facebook queries to graph API, that I've found, but nothing worked as I expected. Can you provide me some example?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Marcin
  • 1,823
  • 3
  • 16
  • 18
  • 5
    Unless the user has logged out of the app in FB, you can just send the auth token across to the server (ssl hopefuly). Does a simple query of "/me" via the graph api succeed or fail? – The Mad Gamer Mar 30 '11 at 23:12
  • you will get message in response from facebook that your token is not valid :) – Jean-Luc Godard Jul 11 '11 at 09:34
  • 1
    I'm trying to do something very similar to what you're doing. You never marked this question as answered, did you ever get this working? – tempy Nov 22 '11 at 10:50
  • What happens when the access_token expires ? should we ask user to login again ? i want to understand how to re validate again after token is expired – debianmaster Jun 04 '15 at 22:25
  • @debianmaster it depends on your app architecture. If you consider the case "no FB token - no access to the app", than yes, log out the user. Otherwise, you might consider an "unlink" logic, where user stays logged in, but the info, received from Facebook is detached from his account on the server/client. – Yevhen Dubinin Jan 19 '16 at 09:53

8 Answers8

119

Here's a two step process you can use to validate that a user access token belongs to your App:

1) Generate an App Access token

(https://developers.facebook.com/docs/howtos/login/login-as-app/)

https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID
&client_secret=YOUR_APP_SECRET
&grant_type=client_credentials

2) Debug the User Access token

(https://developers.facebook.com/docs/howtos/login/debugging-access-tokens/)

https://graph.facebook.com/debug_token?
input_token=INPUT_TOKEN
&access_token=ACCESS_TOKEN

Where INPUT_TOKEN is the user access token you want to verify, and ACCESS_TOKEN is your app's token that you got from step 1.

The debug endpoint basically dumps all information about a token, so it'll respond with something like this:

{
    data: {
        app_id: YOUR_APP_ID,
        is_valid: true,
        metadata: {
            sso: "iphone-safari"
        },
        application: YOUR_APP_NAMESPACE,
        user_id: USER_ID,
        issued_at: 1366236791,
        expires_at: 1371420791,
        scopes: [ ]
    }
}

If that token isn't from "your app" then it will return an error response.

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
sebastian the crab
  • 1,331
  • 1
  • 8
  • 7
  • 14
    [According to Facebook](https://developers.facebook.com/docs/facebook-login/access-tokens/), this is the correct way to inspect tokens. However, the first part is optional since you may use your app id and secret instead of an admin or app token. – Brandon Zacharie Dec 27 '13 at 11:41
  • @BrandonZacharie Don't see how you do this, I just tried with app id and secret and gave me error for "input_token parameter required" – Johnny Z Apr 01 '14 at 12:04
  • @JohnnyZ the input token is required. The access token is where the flexibility is. – Brandon Zacharie Apr 03 '14 at 02:17
  • 8
    @BrandonZacharie You are right, I was getting input and access tokens confused. To use app id and secret I passed in this as a parameter with pipe as a delimiter:&access_token=APP_ID|APP_SECRET – Johnny Z Apr 03 '14 at 12:06
  • @JohnnyZ oh my god what a ridiculous parameters format... Why don't the just accept `client_id` and `client_secret`... This breaks all the abstractions in my library... – Kolyunya Nov 19 '14 at 11:49
  • this is the right way to do it, complete and secure – VallaDanger Feb 14 '16 at 00:57
  • 2
    The link above is now https://developers.facebook.com/docs/facebook-login/access-tokens/debugging-and-error-handling – Chris Prince Jun 14 '16 at 21:26
  • Why is that https://graph.facebook.com/debug_token doesn't require the appsecret_proof if you have that turned on? (see https://developers.facebook.com/docs/facebook-login/access-tokens/debugging-and-error-handling) – Chris Prince Jun 15 '16 at 20:10
  • Do you verify the token with every request? The access token has a expiration date, but the user might change the password any time. So I am not sure how I should handle this. So I thought about querying the graph db only in a 10min(?) interval. Therefore i store the timestamp of the last facebook auth token check in my database. If another request knocks on my server I check the timestamp to see if i need to verify the auth token again. So in the worst case the outdated token is still valid for another 10min on my server. Is that a good approach? – user2494129 Sep 02 '16 at 10:52
  • I added the one request solution answer below, vote if you like it :) – Kamoris Dec 01 '16 at 14:26
115

Update: this answer seems insecure since it doesn't validate the token first as belonging to your app, see the comments, original answer as follows:

I assume that you already have the access token in hand. In such a case the simplest way to validate an access token is to issue the following request

https://graph.facebook.com/me?fields=id&access_token=@accesstoken

Here replace @accesstoken with the access token you have. I will breakdown the url and will explain each.

We are issuing a graph api request here which will return the Facebook User Id of the owner of the access token as a JSON string. The keyword 'me' represents the currently logged in user or the owner of the access token. For this request access token is a mandatory parameter.

If the provided access token is not valid or expired Facebook will just return an error message of some sort.

For a valid access token the result will somehow look like this

{
   "id": "ID_VALUE"
}
David Ortiz
  • 997
  • 1
  • 14
  • 22
Robin
  • 2,339
  • 1
  • 15
  • 11
  • 14
    Wouldn't that request succeed if that user provided an access_token which belongs to a different app? – Yuriy Nemtsov Nov 11 '11 at 19:39
  • 2
    Any valid user access token can be used (no matter which app it belongs to) – Robin Nov 12 '11 at 04:19
  • 12
    @Xiquid this post is not the solution to the problem since it does not validate if the access token belongs to your application. – Kolyunya Nov 19 '14 at 09:52
  • 1
    @RobinJome Should this verification be done for every request that needs to user to be logged in ? What I mean is : You want to load a page that is available only to logged in user, so you call your server to get a page using a `userID` and its `token` and than the server **must** call facebook to validate the token for that ID ? – RPDeshaies Apr 14 '15 at 11:33
  • 12
    I don't understand why this answer has the most votes! It's OBVIOUSLY not the right solution. Actually, the correct approach is what "sebastian the crab" suggested. The debug_token endpoint is used to query information about the token itself and this way you can verify that the token belongs to a specific user ID for a specific app ID! – Alex Ntousias Jun 01 '15 at 13:25
  • 4
    Yeah, this answer is not correct. If you verify the access token this way, someone can get an access token from a different application and use it to authenticate with yours. – Jonathan Oct 16 '15 at 19:26
  • 1
    Do not use this answer, it is not correct. This way you cannot check if access token belongs to your app developers.facebook.com/docs/facebook-login/security – nikis Feb 12 '16 at 10:44
  • this is just one part of the solution, you should also debug the token received in orden to validate that it was issued for you app using one of your clients (ej: android), that will ensure that the user has been logged in by facebook and also granted your app access to the data it asked for. – VallaDanger Feb 14 '16 at 00:56
  • 1
    **This solution is wrong**. This is critical since it creates a huge security breach in the process. OP asked about "check if the token is valid for my Facebook app". So please consider adding a big disclaimer on your answer about the security flaw. – Pierre May 08 '16 at 14:03
  • This solution is non-secure, if you want one request and secure method to verify user token look below at my answer. – Kamoris Dec 01 '16 at 14:24
  • I don't understand the security risk. The id returned is app-scoped. So if a malicious client sends you an access token from a different app, it wont match any id stored in your server db. – Vedant Agarwala Apr 10 '17 at 11:12
  • @vedant1811 if you're using this to, for instance, create a login with a user's credentials from facebook, you can't know if the user actually logged into *your app* before passing you their access token...it could be from logging into some other app that has different permissions, etc...also for followers if you use curl to test this and get ""An active access token must be used" try putting quotes around the url. – rogerdpack Apr 11 '17 at 19:30
  • @rogerdpack. Let's say a user does that. He cannot impersonate anyone else on my app. All he can do is mess up his own account, and maybe create a few server errors. – Vedant Agarwala Apr 11 '17 at 23:50
  • @vedant1811 some people use access tokens for other things like creating accounts, etc. If s/he steals access tokens or re-uses the from some other app it might enable some fraudulent purposes, as it were...but to each his own. Signing off... – rogerdpack Apr 12 '17 at 01:19
  • Isnt it the case that the userid is apid specific, that means each user will have a unique userid for one appid, you wont be able to identify yourself with an userid that belongs to another appid/ – user2412555 Sep 28 '17 at 19:38
11

Another solution would be to use https://graph.facebook.com/app/?access_token=[user_access_token] as described by Get application id from user access token (or verify the source application for a token).

This appears to be an undocumented feature, but returns JSON containing the id of the app the token was generated for. If the token wasn't for your app, it returns a 400.

Community
  • 1
  • 1
6

In the latest version of facebook (2.2) you can do it this way:

https://developers.facebook.com/docs/graph-api/reference/v2.2/debug_token

Sample output:

{
    "data": {
        "app_id": "THE APP ID", 
        "application": "APP NAME", 
        "expires_at": 1427245200, 
        "is_valid": true, 
        "scopes": [
        "public_profile", 
        "basic_info", 
        "read_stream", 
        "email", 
        "publish_actions", 
        "read_friendlists", 
        "user_birthday", 
        "user_hometown", 
        "user_location", 
        "user_likes", 
        "user_photos", 
        "user_videos", 
        "user_friends", 
        "user_posts"
        ], 
        "user_id": "THE USER ID"
    }
}
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • Does this mean that you'll have to call this fb endpoint on each request? Isn't there a beter way? – Jdruwe Oct 08 '15 at 18:50
  • This works but it requires the access token. Access token can be generated using 'sebastian the crab' answer or we can simply use appid|appsecret. Fore more Info https://developers.facebook.com/docs/facebook-login/access-tokens#apptokens – krishnan Aug 10 '16 at 07:29
  • Here's an example use of this: http://stackoverflow.com/a/16947027/32453 – rogerdpack Apr 11 '17 at 20:40
2
private function facebookRequestMe($access_token)
{
    include_once "facebook.php";

    $facebook = new Facebook(array(
        "appId" => "your_application_id",
        "secret" => "your_application_secret"
    ));
    $facebook->setAccessToken($access_token);
    return $facebook->api("/me", "GET");
}

You can download the Facebook SDK for PHP from GitHub.

Baptiste Costa
  • 1,044
  • 1
  • 12
  • 24
2

If a user has passed you a Facebook UID that they claim is theirs and you want to check if it's legit, this is a Python function that will verify it against their access token (an implementation of Robin Jome's answer):

def verify_facebook_id(id, access_token):
    import requests
    import simplejson
    params = {'fields': 'id', 'access_token': access_token}
    text = requests.get("https://graph.facebook.com/me", params=params).text
    json = simplejson.loads(text)
    response_id = json["id"]
    return response_id == id
Andrew Magee
  • 6,506
  • 4
  • 35
  • 58
1

This is the only secure method to verify user token using just one request:

https://graph.facebook.com/debug_token?input_token={token-to-inspect}&access_token={app_id}|{app_secret}

Note that a sign "|" in the above URL isn't used as OR but as separator and must be there after fill the other fields.

The response will be JSON looking like that:

{
    data: {
        app_id: {app_id},
        application: {app_name},
        expires_at: {some_number},
        is_valid: {true|false}
        scopes: {array_of_permissions},
        user_id: {user_id}
    }
}

Reference: https://developers.facebook.com/docs/facebook-login/access-tokens/#apptokens (above method is mentioned at the bottom of this section)

Kamoris
  • 495
  • 3
  • 10
-1

Along with an access token Facebook also sends an "expires_in" parameter, which is an offset value. Use that to compute for when the access token will expire as an NSDate. Then when you need to do a request compare the current date with the expiration date.

Also try to inspect the status codes and response strings Facebook sends back.

jcm
  • 1,781
  • 1
  • 15
  • 27