[PHP] Facebook APIのOauthのエラー解決「URLを読み込めません」「Can’t Load URL」

by codechord. 0 Comments

  • このエントリーをはてなブックマークに追加
  • このエントリーをはてなブックマークに追加

FacebookのAPIを使おうとOauth周りの処理に公式のPHP SDKのライブラリ(v5系)を利用している前提での話です。
(※2016年冬期の記事です。)
https://github.com/facebook/php-graph-sdk

本SDKライブラリを利用して、Facebook APIでOauth認証しようとする際、特定のサーバの環境下で、正式にApp登録をしているにもかかわらず、
下記のようなエラーがでる時があります。すごくはまりましたので、メモとして残します。(自分の場合はさくらのレンタルサーバでした。)

エラー内容

Facebookの認証画面に遷移して、認証を許可し、コールバックのページに戻るタイミングで、次のようなエラーがでて失敗してしまいます。

Can't Load URL: The domain of this URL isn't included in the app's domains.

URLを読み込めません: このURLのドメインはアプリのドメインに含まれていません。このURLを読み込むには、アプリ設定のアプリドメインにすべてのドメインとサブドメインを追加してください。

アプリ設定についての具体的な操作説明は端折りますが、とにかくドメイン設定やコールバックのURLが間違っていたら話になりませんので、まずはアプリ設定をみなおしましょう。アプリ登録については、こちらの記事が参考になります。
FacebookとSNS連携!SDKを使わずにOAuth2でアクセストークン取得する/PHP | サイト構築日記

設定はまちがっていないなら、ライブラリか自分のコードを疑う

ここまでできていて、設定が100%間違っていない!という状況でも、認証プロセスで上記のエラーが出る場合があります。公式が出してるSDKライブラリを利用しているのだから、マニュアルの通りして動かなければ、アプリの設定の間違いしかないと思いこんでいました。
結果的には、特定のサーバの環境下で、サンプルコードの通りした場合に生じてしまう症状のようです。

では、サンプルコードを見てみましょう。
アクセストークンを取得する処理は、公式(v5.4)のReadme記載のサンプルコードをそっくりそのまま拝借します。(これが動きませんでした。)

// https://github.com/facebook/php-graph-sdk/blob/5.4/docs/examples/facebook_login.md

$fb = new Facebook\Facebook([
  'app_id' => '{app-id}',
  'app_secret' => '{app-secret}',
  'default_graph_version' => 'v2.6',
  ]);

$helper = $fb->getRedirectLoginHelper();

try {
  $accessToken = $helper->getAccessToken(); // ★この処理でエラー
} catch(Facebook\Exceptions\FacebookResponseException $e) {
  // When Graph returns an error
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
  // When validation fails or other local issues
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}

if (! isset($accessToken)) {
  if ($helper->getError()) {
    header('HTTP/1.0 401 Unauthorized');
    echo "Error: " . $helper->getError() . "\n";
    echo "Error Code: " . $helper->getErrorCode() . "\n";
    echo "Error Reason: " . $helper->getErrorReason() . "\n";
    echo "Error Description: " . $helper->getErrorDescription() . "\n";
  } else {
    header('HTTP/1.0 400 Bad Request');
    echo 'Bad request';
  }
  exit;
}

// Logged in
echo '</pre>
<h3>Access Token</h3>
<pre>
';
var_dump($accessToken->getValue());

このサンプルのアクセストークンを取得する処理見る限り、引数を何も渡さないもの(渡してはいけないもの)だと、勝手に思いこんでしまっていたのですが、実は引数を渡すことができ、次のように、引数にコールバックのURLを指定してあげると解決します。


  //元のサンプル
  $accessToken = $helper->getAccessToken();

  //改良サンプル
  $accessToken = $helper->getAccessToken(
  	"https://mydomain.com/path-to-callback"
  );

原因探求

SDKの実装がどうなっているかというと、次のような感じ。
コールバックのURLを引数にいれることができ、
引数が渡されなかった場合は、自動的に、コールバックのURLを取得してくれるような実装みたい。

// facebook/graph-sdk/src/Facebook/Helpers/FacebookRedirectLoginHelper.php
class FacebookRedirectLoginHelper{
    public function getAccessToken($redirectUrl = null){
    	....
    	// CSRF対策の処理
    	....
    	// コールバック先のリダイレクトURLを取得する処理
        $redirectUrl = $redirectUrl ?: $this->urlDetectionHandler->getCurrentUrl();
    	// アクセストークンを取得し返す処理
    	....
    }
}

// facebook/graph-sdk/src/Facebook/Url/FacebookUrlDetectionHandler.php
class FacebookUrlDetectionHandler implements UrlDetectionInterface
{
    public function getCurrentUrl()
    {
        return $this->getHttpScheme() . '://' . $this->getHostName() . $this->getServerVar('REQUEST_URI');
    }

    protected function getHostName()
    {
        // Check for proxy first
        $header = $this->getHeader('X_FORWARDED_HOST');
        if ($header && $this->isValidForwardedHost($header)) {
            $elements = explode(',', $header);
            $host = $elements[count($elements) - 1];
        } elseif (!$host = $this->getHeader('HOST')) {
            if (!$host = $this->getServerVar('SERVER_NAME')) {
                $host = $this->getServerVar('SERVER_ADDR');
            }
        }
        .....
    }
}

プロキシだったり、サーバの環境変数とかとってきてるようで、その値と自分がFacebookアプリの登録時に設定したコールバックのURLにとが一致していないと、うまく動作しないという感じ。ふむふむ。

まとめ

Readme読んでハマったら、自分を疑うのと同時に、実装を読む癖つけないといけないですね!
ちなみに、Stackoverflowのコメントで見つけた解決策でした。
日本語のエラーメッセージだと、検索結果が減るので、外来のライブラリは日本語対応はしないでほしい・・・

というわkで、PHPでFacebook APIのOauth認証にはまったらコールバック指定すると解決するかもね。

$accessToken = $helper->getAccessToken(
    "https://example.com/path-to-callback"
);

以上、phpstorm便利!バンザイ!

参考


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>