Skip to content

Instantly share code, notes, and snippets.

@zigorou
Created December 23, 2012 07:21
Show Gist options
  • Save zigorou/4362452 to your computer and use it in GitHub Desktop.
Save zigorou/4362452 to your computer and use it in GitHub Desktop.
Facebook login sample
use strict;
use warnings;
use Config::Pit;
use Data::Section::Simple qw(get_data_section);
use HTTP::Request;
use HTTP::Status qw(:constants);
use Log::Minimal;
use LWP::UserAgent;
use Plack::Builder;
use Plack::Request;
use Plack::Response;
use Plack::Session;
use String::Random qw(random_regex);
use Text::Xslate;
use URI;
use URI::QueryParam;
use URI::Template;
# https://developers.facebook.com/docs/howtos/login/server-side-login/
my $tx = Text::Xslate->new( syntax => "TTerse" );
my $ua = LWP::UserAgent->new;
my $authorize_uri_template = URI::Template->new(
"https://www.facebook.com/dialog/oauth{?client_id,redirect_uri,state}"
);
my $access_token_uri_template = URI::Template->new(
"https://graph.facebook.com/oauth/access_token{?client_id,client_secret,redirect_uri,code}"
);
my $redirect_uri = "http://localhost:5000/";
my $credentials = pit_get("facebook_test", require => +{
id => "Facebook App ID",
secret => "Facebook App Secret",
});
sub render {
my ($res, $section_name, $vars) = @_;
$res->content($tx->render_string(get_data_section($section_name), $vars));
}
my $app = sub {
my $env = shift;
my $req = Plack::Request->new($env);
my $res = Plack::Response->new(
HTTP_OK,
[ "Content-Type" => "text/html" ]
);
if ($req->path_info eq "/favicon.ico") {
$res->code(HTTP_NOT_FOUND);
return $res->finalize;
}
my $session = Plack::Session->new($env);
if ($req->param("code")) {
my $code = $req->param("code");
my $state = $session->get("state") || "";
unless ($state && $state eq $req->param("state")) {
warnf("Invalid state (expect: %s. actual: %s)", $state, $req->param("state"));
render($res, "error.html", +{ error => "Invalid state" });
}
else {
my $access_token_url = $access_token_uri_template->process_to_string(
client_id => $credentials->{id},
client_secret => $credentials->{secret},
code => $code,
redirect_uri => $redirect_uri,
);
infof("Access token url (url: %s)", $access_token_url);
my $request = HTTP::Request->new( GET => $access_token_url );
my $response = $ua->request( $request );
unless ($response->is_success) {
render($res, "error.html", +{ error => $response->status_line });
}
else {
my $query = URI->new("", "http");
$query->query($response->content);
render($res, "view_access_token.html", +{ access_token => $query->query_param("access_token") });
}
}
}
elsif ($req->param("error")) {
render($res, "error.html", +{ error => $req->param("error") });
}
else {
my $state = random_regex(q|[A-Za-z0-9]{24,32}|);
infof("Generated state (state: %s)", $state);
$session->remove("state");
$session->set("state", $state);
my $authorize_url = $authorize_uri_template->process_to_string(
client_id => $credentials->{id},
redirect_uri => $redirect_uri,
state => $state,
);
infof("Authorize url (url: %s)", $authorize_url);
render($res, "login.html", +{ authorize_url => $authorize_url });
}
$res->finalize;
};
builder {
enable "Session";
$app;
};
__DATA__
@@ login.html
<html>
<head>
<title>Login with facebook</title>
</head>
<body>
<a href="[% authorize_url | html %]">Login with facebook</a>
</body>
</html>
@@ error.html
<html>
<head>
<title>Login error</title>
</head>
<body>
<dl>
<dt>error<dt>
<dd>[% error | html %]</dd>
</dl>
</body>
</html>
@@ view_access_token.html
<html>
<head>
<title>Login success</title>
</head>
<body>
<dl>
<dt>access token</dt>
<dd>[% access_token | html %]</dd>
</dl>
<p>
Please execute following commands
</p>
<pre>
lwp-request -m GET -H "Authorization: Bearer [% access_token | html %]" https://graph.facebook.com/me | json_xs -t json-pretty
</pre>
</body>
</html>
@zigorou
Copy link
Author

zigorou commented Dec 23, 2012

Config::Pit で事前に自分で作った AppID, AppSecret を突っ込んでおく必要があります。
あとは LWP, JSON::XS に付属のコマンドがあるとばちーんと Graph API を実行する事が出来ます。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment