Jak opravit nefunkční Facebook přihlašování?

Martin Pešout   4. 10. 2011


Facebook patří v současnosti mezi nejrozšířenější sociální síť světa. Spousta moderních eshopů a webových stránek využívá právě jeho služby, aby usnadnila všem návštěvníkům registraci a následné přihlašování. Od 1. října 2011 však dochází k zásadní změně. Facebook se snaží udělat celý proces více bezpečnější. Proto se rozhodl, že od tohoto data bude pro autentizaci uživatelů využívat pouze protokol OAuth verze 2.0. Máte-li problém se stávajícím přihlašováním nebo se teprv chystáte o jeho integraci do systému, pak je tento článek určen přímo pro Vás.

Protokol OAuth 2.0

Cílem protokolu OAuth je usnadnit uživatelům samotné přihlašování. Jak jsem již zmínil v mém článku o OpenID, tak i zde to můžu zopakovat: Pokud požadujete registraci, je trendem poslední doby celý tento proces maximálně zjednodušovat. V dnešní době si nechceme pamatovat desítky hesel. Provozovatelům služby, která OAuth identity poskytuje, dává OAuth možnost sdílet uživatelská data a identity, aniž by uživatelé museli prozrazovat své heslo komukoliv dalšímu.

Starý způsob přihlašování

Pokud stále využíváte starý způsob, je nutné provést změnu v kódu a nově využívat protokolu OAuth 2.0. Starý způsob poznáte např. podle následující ukázky kódu v jazyce PHP.

$url="http://www.facebook.com/login.php?api_key=[YOUR_API_KEY]    
  &connect_display=popup&v=1.0&next=[YOUR_URI]
  &cancel_url=http://www.facebook.com/connect/login_failure.html
  &fbconnect=true&session_key_only=true";

header("location:" . $url);

Pokud přímo odkazujete v aplikaci na knihovnu JavaScript SDK, tak dojde k této změně automaticky a nemusíte se o nic starat v kódu aplikace. Pokud např. využíváte starší verzi knihovny PHP SDK, tak je nutné provést její aktualizaci na novější verzi (od 1. července 2011 tato knihovna podporuje protokol OAuth 2.0).

Jak správně implementovat Facebook přihlašování?

Facebook podporuje 2 odlišné způsoby použití OAuth 2.0. Jedná se o tyto:

  • autentizace na straně serveru - použito při zpracování a generování obsahu na straně serveru
  • autentizace na straně klienta - použitou pouze v situacích, když potřebujeme zavolat služby Graph API na straně klienta (prohlížeče), jako při volání JavaScriptu nebo z nativních mobilních či desktopových aplikací.

Nebudu se zde zabývat druhým způsobem, ale pokud by to někoho z Vás zajímalo detailněji, tak popis tohoto procesu autentizace spolu s několika ukázkami naleznete zde.

Autentizace uživatelů nebo autorizace aplikací jsou obsluhovány stejným způsobem a to pomocí přesměrování na tzv. sérii po sobě jdoucích akcí nazvaných OAuth Dialog. V odkazu musíme předat ID aplikace (client_id parametr), které je vygenerováno při vytváření samotné aplikace pro přihlašování v Developer App. Dále uvedeme URL, na které přesměrujeme zpět po dokončení celého procesu (redirect_uri parametr). Samotné redirect_uri musí obsahovat stejnou doménu jako ta, která byla definována při vytváření aplikace v zmíněném Developer App.

Takže prvně přesměrujeme na podobnou adresu:

https://www.facebook.com/dialog/oauth?
  client_id=YOUR_APP_ID&redirect_uri=YOUR_URL

Pokud je uživatel již přihlášený, budou pouze ověřeny jeho údaje uložené v cookies. Pokud ještě přihlášený není, bude vyzván, aby tuto akci dokončil.

Ukázka Facebook přihlašování

Pokud došlo k úspěšné autentizaci, OAuth Dialog vyzve uživatele, aby autorizoval aplikaci stojící za celým přihlašováním. Tento krok nastane pouze v případě, kdy toto nebylo provedeno už někdy v minulosti.

Povolení Facebook aplikace

Tímto ale získáme pouze přístup k základním informacím, které se týkají vašeho Facebook účtu. Pokud budeme chtít zjišťovat více - např. emailovou adresu, kterou používá váš Facebook účet - je nutné to specifikovat pomocí tzv. scope parametrů. Ty doplníme jako parametry do URL, kterou voláme v rámci našeho OAuth Dialogu. Následující příklad ukazuje, jak získat také přístup k emailové adrese a možnostem číst přízpěvky na zdi uživatele:

https://www.facebook.com/dialog/oauth?
     client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream

Úplný seznam údajů, které je možné číst z profilu uživatele, naleznete zde.

Když uživatel zamítne povolení číst jakékoliv informace z jeho profilu, nedojde k potřebné autorizaci. Samotný OAuth Dialog přesměruje (přes HTTP 302) uživatele na URL uvedenou v redirect_uri parametru a přidá následující chybovou informaci:

http://YOUR_URL?error_reason=user_denied&
     error=access_denied&error_description=The+user+denied+your+request.

Pokud však uživatel povolí číst požadované informace z jeho profilu, bude aplikace autorizována. OAuth Dialog přesměruje (přes HTTP 302) uživatele na URL uvedenou v redirect_uri a přidá nový parametr s autorizačním kódem:

http://YOUR_URL?code=A_CODE_GENERATED_BY_SERVER 

S tímto kódem je možné provést následující krok, autentizaci aplikace a získat tak přístupový token (access token) pro čtení potřebných informací z profilu uživatele.

Aby bylo možné dokončit autentizaci aplikace, musíme předat získaný kód a tajný klíč aplikace do rozhraní Facebook Graph API - https://graph.facebook.com/oauth/access_token. Tajný klíč aplikace získáme z Developer App. Tento údaj by měl by zůstat utajen pro nepověřené lidi. Tzn. že by neměl být předávaný přes URL apod.

https://graph.facebook.com/oauth/access_token?
     client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&
     client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE

Pokud vše proběhne v pořádku, získáme od autorizačního serveru přístupový token pro čtení potřebných informací z profilu uživatele.

Získaný přístupový token

Vrácená informace obsahuje navíc ještě jeden parametr a to číslo v sekundách představující dobu, za kterou dojde k expiraci získaného tokenu (parametr expires viditelný i na předchozím obrázku). Jakmile dojde k expiraci, musíte znovu projít všechny kroky a vygenerovat nový kód a přístupový token. Pokud požadujete, aby doba expirace byla nastavena na nekonečno, je nutné požádat o takzvaný offline přístup (offline_access) k vašemu profilu pomocí zmíněného scope omezení.

Příklad v jazyku PHP

Následující ukázka demonstruje Facebook autentizaci na straně serveru s CSRF ochranou. Ukázkový kód je z jazyka PHP:

$app_id = "YOUR_APP_ID";
$app_secret = "YOUR_APP_SECRET";
$my_url = "YOUR_URL";

session_start();
$code = $_REQUEST["code"];

if(empty($code)) {
  $_SESSION["state"] = md5(uniqid(rand(), TRUE)); //CSRF protection
  $dialog_url = "http://www.facebook.com/dialog/oauth?client_id=" 
    . $app_id . "&redirect_uri=" . urlencode($my_url) . "&state="
    . $_SESSION["state"];
   echo(" top.location.href='" . $dialog_url . "'");
}

if($_REQUEST["state"] == $_SESSION["state"]) {
  $token_url = "https://graph.facebook.com/oauth/access_token?"
    . "client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url)
    . "&client_secret=" . $app_secret . "&code=" . $code;
  $response = file_get_contents($token_url);
  $params = null;
  parse_str($response, $params);

  $graph_url = "https://graph.facebook.com/me?access_token=" 
    . $params["access_token"];

  $user = json_decode(file_get_contents($graph_url));
  echo("Hello " . $user->name);
}
else {
  echo("The state does not match. You may be a victim of CSRF.");
}

Jak implementovat odhlášení?

Pokud se chcete odhlásit z Facebooku je to možné provést přesměrováním na následující URL:

https://www.facebook.com/logout.php?next=YOUR_URL&access_token=ACCESS_TOKEN

Samotné YOUR_URL musí obsahovat stejnou doménu jako ta, která byla definována při vytváření aplikace v zmíněném Developer App.

Zdroje