The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl
#
# This plack demo shows the logic which your website needs to facilitate
# third-party OAuth2 authorization.

# This code only works when you plack server runs in a single process:
# otherwise you will need to keep the session information in some
# shared store, for instance a database.  That makes life considerable
# harder.

use strict;
use warnings;

use Dancer;
use Net::OAuth2::Client;
use HTML::Entities;

get '/get/:site_id' => sub {
    redirect client(params->{site_id})->authorize;
};

get '/got/:site_id' => sub {
    defined params->{code}
        or return html_page("Error: Missing access code");

    my $site_id      = params->{site_id};
    my $access_token = client($site_id)->get_access_token(params->{code});
    return html_page("Error: " . $access_token->to_string)
        if $access_token->{error};

    my $content = "<h2>Access token retrieved successfully!</h2>\n"
                . '<p>'.encode_entities($access_token->to_string)."</p>\n";

    my $this_site = config->{sites}{$site_id};
    my $response  = $access_token->get($this_site->{protected_resource_url}
                 || $this_site->{protected_resource_path});

    if ($response->is_success) {
        $content .= "<h2>Protected resource retrieved successfully!</h2>\n"
                 .  '<p>'.encode_entities($response->decoded_content).'</p>';
    }
    else {
        $content .= '<p>Error: '. $response->status_line."</p>\n";
    }
    $content =~ s[\n][<br/>\n]g;
    html_page($content);
};

get '/' => sub {
    my $content = '';
    while (my ($k,$v) = each %{config->{sites}}) {
        $content .= qq{<p>$v->{name}: <a href="/get/$k">/get/$k</a></p>\n}
            if $v->{client_id} && $v->{client_secret};
    }
    $content ||= "<p>You haven't configured any sites yet.<br>\n"
               . "Edit your config.yml file!</p>\n";
    html_page($content);
};

dance;

exit 0;

### Helpers

sub html_page($) {
    my $content = shift;
    return <<EOT;
<html>
<head>
    <title>OAuth 2 Test</title>
    <style>
    h1 a {color: black; text-decoration:none}
    </style>
</head>
<body>
<h1><a href="/">OAuth 2 Test</a></h1>
$content
</body>
</html>
EOT
}

sub client($)
{   my $site_id     = shift;
    my $site_config = config->{sites}{$site_id} || {};

    my $redirect    = uri_for("/got/$site_id");
    $redirect       =~ s,/dispatch\.cgi,,;

    Net::OAuth2::Profile::WebServer->new
      ( %$site_config
      , redirect_uri => $redirect
      );
}