Using Facebook Graph API with Perl

読んでおくべきドキュメント

Server Side Loginに関しては、まずはこの3つを読んでおけばよい。

https://developers.facebook.com/docs/concepts/login/login-architecture/
https://developers.facebook.com/docs/howtos/login/server-side-login/
https://developers.facebook.com/docs/reference/dialogs/oauth/

OAuth2のRFCも読んでおく。
Facebookで言うところのServer Side LoginがAuthorization Code Grantに当たる。

     +----------+
     | Resource |
     |   Owner  |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier      +---------------+
     |         -+----(A)-- & Redirection URI ---->|               |
     |  User-   |                                 | Authorization |
     |  Agent  -+----(B)-- User authenticates --->|     Server    |
     |          |                                 |               |
     |         -+----(C)-- Authorization Code ---<|               |
     +-|----|---+                                 +---------------+
       |    |                                         ^      v
      (A)  (C)                                        |      |
       |    |                                         |      |
       ^    v                                         |      |
     +---------+                                      |      |
     |         |>---(D)-- Authorization Code ---------'      |
     |  Client |          & Redirection URI                  |
     |         |                                             |
     |         |<---(E)----- Access Token -------------------'
     +---------+       (w/ Optional Refresh Token)

http://tools.ietf.org/html/rfc6749#section-4.1

Facebook Appをつくる

Facebook App Dashboardにて。 AppDomainとSiteURLはそれぞれlocalhosthttp://localhost/でもOK。つまり、ローカルマシンでFacebook Graph APIを試すことができる。

Access Tokenを取得し、Graph APIを呼び出す

例えばAmon2::Liteを使うと、以下の通り。

#!/usr/env/perl
use strict;
use warnings;
use utf8;

use Amon2::Lite;
use Config::Pit;
use String::Random;
use Furl;

get '/' => sub {
    my $c = shift;

    my $pit   = pit_get("www.facebook.com");
    my $state = String::Random->new->randregex('\w{16}');

    $c->redirect('https://www.facebook.com/dialog/oauth/', +{
        client_id    => $pit->{app_key},
        redirect_uri => 'http://localhost:9000/facebook/callback',
        state        => $state,
    });
};

get '/facebook/callback' => sub {
    my $c = shift;

    # TODO validate $c->req->param('state')

    my $pit = pit_get("www.facebook.com");
    my $uri = URI->new('https://graph.facebook.com/oauth/access_token');
    $uri->query_form( 
        client_id     => $pit->{app_key},
        client_secret => $pit->{app_secret}, 
        code          => $c->req->param('code'), 
        redirect_uri  => 'http://localhost:9000/facebook/callback',
    );

    # get access token
    my $furl = Furl->new(agent => 'Furl', timeout => 1);
    my $res  = $furl->get($uri->as_string);

    if ( $res->status == 200 ) {
        my ($access_token, $expires) = split('&', $res->content);
        $access_token =~ s#^access_token=##;
        $expires      =~ s#^expires=##;

        # Access to Graph API
        my $json = $furl->get("https://graph.facebook.com/me?access_token=$access_token")->content;
        return $c->create_response(200, [ 'Content-Type' => 'application/json' ], $json);
    }

    use Data::Dump qw(dump);
    $c->create_response(500, [ 'Content-Type' => 'text/plain' ], dump $res);
};

__PACKAGE__->to_app();

実際にはstateの検証やsessionへのaccess_token保存なども必要になる。

まとめ

FacebookのServer Side LoginのサンプルをPerlで実装してみた。
OAuth2(Authorization Code Grant)はライブラリ使わなくても実装できるくらいシンプルなプロトコルだなと実感。