Skip to content

Instantly share code, notes, and snippets.

@gideondsouza
Created September 26, 2013 18:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gideondsouza/6718246 to your computer and use it in GitHub Desktop.
Save gideondsouza/6718246 to your computer and use it in GitHub Desktop.
Dancer2::Plugin::Github::Auth
package Dancer2::Plugin::Auth::Github;
use strict;
use warnings FATAL => 'all';
use Carp 'croak';
use Dancer2;
use Dancer2::Plugin;
use Digest::SHA qw(sha256_hex);
use LWP::UserAgent;
use JSON qw(decode_json);
our $VERSION = '0.01';
my $client_id;
my $client_secret;
my $scope = "";
my $github_redirect_url = 'https://github.com/login/oauth/authorize/';
my $github_post_url = 'https://github.com/login/oauth/access_token/';
my $github_auth_failed = '/auth/github/failed';
my $github_auth_success = '/';
my $state_salt = "RandomSalt";
#dancer2 stuff.
#A method to initialize everything
register 'auth_github_init' => sub {
warn "auth github loaded";
my $dsl = shift;
my $config = plugin_setting;
$client_id = $config->{client_id};
$client_secret = $config->{client_secret};
for my $param (qw/client_id client_secret/) {
croak "$param is expected but not found in configuration"
unless $config->{$param};
}
#sthe following configs are optional.
if($config->{scope})
{
$scope = $config->{scope};
}
#these configs have default values.
if($config->{github_auth_failed})
{
$github_auth_failed = $config->{github_auth_failed};
}
if($config->{github_auth_success})
{
$github_auth_success = $config->{github_auth_success};
}
#$dsl->debug 'Loaded config..';
#registers this as a callback url
$dsl->app->add_route(
regexp => '/auth/github/callback',
code => sub {
my $generate_state = sha256_hex($client_id.$client_secret.$state_salt);
my $state_received = $dsl->params->{'state'};
if($state_received eq $generate_state) {
warn("State received correctly.");
my $code = $dsl->params->{'code'};
my $browser = LWP::UserAgent->new;
my $resp = $browser->post($github_post_url,
[
client_id => $client_id,
client_secret => $client_secret,
code => $code,
state => $state_received
]);
die "error while fetching: ", $resp->status_line
unless $resp->is_success;
my %querystr = parse_query_str($resp->decoded_content);
my $acc = $querystr{access_token};
warn "got access token? $acc";
if($acc) {
my $jresp = $browser->get("https://api.github.com/user?access_token=$acc");
my $json = decode_json($jresp->decoded_content);
warn("setting session");
$dsl->session(github_user => $json);
warn Data::Dumper::Dumper($dsl->app->session('github_user'));
$dsl->session(github_access_token => $acc);
#session 'logged_in' => true;
warn("before redirect");
$dsl->redirect($github_auth_success);
return;
}
}
$dsl->redirect($github_auth_failed);
},
method => 'get');
};
#returns the url you need to redirect to to authenticate on github
register 'auth_github_authenticate_url' => sub {
my $generate_state = sha256_hex($client_id.$client_secret.$state_salt);
return "$github_redirect_url?&client_id=$client_id&scope=$scope&state=$generate_state";
};
#helper method to parse query string.
sub parse_query_str {
my $str = shift;
my %in = ();
if (length ($str) > 0){
my $buffer = $str;
my @pairs = split(/&/, $buffer);
foreach my $pair (@pairs){
my ($name, $value) = split(/=/, $pair);
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$in{$name} = $value;
}
}
return %in;
}
register_plugin;
1; # End of Dancer::Plugin::Auth::Github
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment