Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

facebook login without sdk

I want to authenticate a user with Facebook following oauth2 flow.

I want to do this without using the SDK. But I can't understand what are the endpoints for user oauth authentication.

Where can I find them?

Edit. This is in a mobile application. IOS or android.

like image 722
Tiago Veloso Avatar asked Apr 13 '15 19:04

Tiago Veloso


3 Answers

You find this information in the Developer docs:

  • https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.3
  • https://developers.facebook.com/docs/facebook-login/access-tokens#usertokens
like image 54
Tobi Avatar answered Oct 19 '22 05:10

Tobi


Here is my login for Android ( java ).

    APP_ID = "XXXXXXXXXXXXXXXX"
    RAW_REDIRECT_URI = "https://www.facebook.com/connect/login_success.html";

    // UTF8 adress so it can go along the http request
    REDIRECT_URI ="";
    try {
         REDIRECT_URI = URLEncoder.encode(RAW_REDIRECT_URI, "UTF-8");
    } catch (UnsupportedEncodingException e) {
         e.printStackTrace();
    }

    // get the code or token
    TOKEN_REQUEST = "https://www.facebook.com/v3.2/dialog/oauth?client_id="+APP_ID+"&redirect_uri="+REDIRECT_URI+ "&state=\'{st=state123abc,ds=123456789}\'";


    // start WebView
    webView.setWebViewClient(new WebViewClient() {
        // shouldOverride will run each time a new URL is loaded in the webview.
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            // the loaded URL is our redirect URL
            if(url.startsWith(RAW_REDIRECT_URI)) {
                // here you have two choices...
                // - make a call to your private server to get the token from the code (recommended)
                // - make the API requests because you added a response_type=token in the TOKEN_REQUEST (less secure ) 
            }
            return false;
        }
    });


    // javascript doesn't seem to be needed for facebook but for instagram yes.
    webView.getSettings().setJavaScriptEnabled(true);
    webView.loadUrl(TOKEN_REQUEST);
like image 1
oligan Avatar answered Oct 19 '22 06:10

oligan


I know, this post is already a bit old, but I was spitting fire, trying to implement a OAuth login flow, because Facebook adds a hashtag to the redirect URL, which does not reach the server. So I share my solution with you in the hope to prevent you from the same anger.

I used a generic solution, which can be reused for other apps as well. The only thing to do is to add the app ID and app secret in the server side script (below).

First of all you need to call the login page from your app:

"https://www.facebook.com/v11.0/dialog/oauth"
    // The app ID can be found in the dashboard (https://developers.facebook.com/apps)
    + "?client_id=" + yourAppId
    // The redirect url in my case (because it's generic)
    // looks like this: https://example.com/oauthresponse/{app}/facebook
    // don't forget to register it in your app dashboard of Facebook:
    // https://developers.facebook.com/apps
    + "&redirect_uri=" + Uri.encode(yourRedirectUrl)
    + "&response_type=token"
    + "&state=" + antiForgeryCode
    + "&scope=" + yourScopes

Then I added this to the .htaccess:

RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^oauthresponse/(.*)/(.*)(/.*)?$ /oauthresponse.php?app=$1&provider=$2 [L,QSA,NE]

Then this is the oauthresponse.php script:

<?php
// This whole magic is just because facebook is adding a hashtag to the redirect url before the querystring
// the problem is that adding a hashtag with no value makes the querystring beeing interpreted as anchor
// anchors are not sent to servers, only to clients, so what we do is the following:
// We send a javascript, removing the hashtag from the url and redirecting to the new url, 
// so we get the query parameters, which contains the token. Then we use the token to get a long living token.
// After all, we send a redirect header with an app intent url (see createAndroidRedirectUrl()).

// Creates a redirect url that opens an app, according to https://developer.chrome.com/docs/multidevice/android/intents/
function createAndroidRedirectUrl($providr, $application, $query = array())
{
    // You need a scheme, in order for the intent to work, I tested it without and it didn't work...
    $url = "intent://oauthresponse/" . $providr . "#Intent" 
    . ";scheme=ch.aorlinn." . $application 
    . ";package=ch.aorlinn." . $application;
    if(isset($query) && $query != null && count($query))
    {
        foreach($query as $key => $value)
        {
            $url = $url . ";S." . $key . "=" . $value;
        }
    }
    $url = $url . ";end";
    return $url;
}

// Initialize a wait message for the javascript response
$body = "<!DOCTYPE html><html><body><span>Please wait, your beeing redirected...</span><br>";
$requestUri = parse_url($_SERVER['REQUEST_URI']);
$subdomain = explode("/", $requestUri["path"])[2];
$provider = explode("/", $requestUri["path"])[3];
// If this is not a Facebook redirect, add the querystring as extras to the intent, 
// it might contain the token
parse_str($_SERVER['QUERY_STRING'], $redirectExtras);
// Indicates, whether or not to redirect, instead of answering with a body
$isRedirect = true;

// Handle Facebook redirect
if($provider == "facebook")
{
    // Specify the appId and appSecret for this app.
    // You can find it in the app dashboard: https://developers.facebook.com/apps
    if($subdomain == "yourAppName")
    {
        $app_id = "yourAppID";
        $app_secret = "yourSecret";
    }   
    if(isset($app_id) && isset($app_secret))
    {
        $token = $_GET["access_token"];
        if(!isset($token) || strlen($token) <= 0)
        {
            // This parameter is set, when the javascript in the else block did it's magic.
            // It can get here, if the url was called without access_token parameter in the first place.
            // This should only happen, if the page is called from somewhere else than the facebook login page.
            if(isset($_GET["hash_replaced"]) || strlen($_GET["hash_replaced"]) > 0)
            {
                $redirectExtras = array("error" => "hash_replacement");
            }
            else
            {
                // Send a script that sends the user back to the page, but remove the hashtag, 
                // so the whole url is sent to the server and the key might be extracted.
                $isRedirect = false;
                $script = "<script>
                    var loc = window.location.href.replace('#', '');
                    // As the .htaccess already added some parameters, there might be two ? now,
                    // so we split everything by ? and & and build the querystring again.
                    var parts = loc.split(new RegExp('[?&]'));
                    var queryString = '';
                    for(var i = 1; i < parts.length; i++)
                    {
                        queryString = queryString + '&' + parts[i];
                    }
                    window.location.href = parts[0] + '?hash_replaced=true' + queryString;
                    </script>";
                $body = $body . $script;
            }
        }
        else
        {
            // Now request a long living token from Facebook REST API for the application
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, array(
                    "fb_exchange_token" => $token,
                    "client_id" => $app_id,
                    "client_secret" => $app_secret,
                    "grant_type" => "fb_exchange_token"));
            curl_setopt($curl, CURLOPT_URL, "https://graph.facebook.com/v11.0/oauth/access_token");
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
            $result = curl_exec($curl);
            curl_close($curl);
            $json = json_decode($result, true);
            $first_key = array_key_first($json);
            if($first_key == "error")
            {
                $array = $json[$first_key];
                $array["error"] = "long_living_token";
                $json = $array;
            }
            $redirectExtras = $json;
        }
    }
}

// This is only false, when the javascript needs to be sent,
// otherwise send a redirect header response (302) with the app intent.
// Note that it needs to be a redirect header. You cannot use javascript here
// as some browsers (like chrome) do not allow to redirect with javascript
// when no user interaction happened.
if($isRedirect)
{
    $redirectUrl = createAndroidRedirectUrl($provider, $subdomain, $redirectExtras);
    
    header("HTTP/1.1 302 Found");
    header("Location: " . $redirectUrl);        
}
else
{
    $body = $body . "</body></html>";
    echo $body;
}
?>

The above function works with Android, but if you need to use iPhone as well just add a subpath to the response url to indicate the device type and check it, before you create the redirect url.

like image 1
Aorlinn Avatar answered Oct 19 '22 05:10

Aorlinn