Dancer-Plugin-Auth-Google

 view release on metacpan or  search on metacpan

lib/Dancer/Plugin/Auth/Google.pm  view on Meta::CPAN

    $scope            = $config->{scope}            || 'profile';
    $callback_success = $config->{callback_success} || '/';
    $callback_fail    = $config->{callback_fail}    || '/fail';
    $access_type      = $config->{access_type}      || 'online';
    $legacy_gplus     = $config->{legacy_gplus}     || 0;

    foreach my $param ( qw(client_id client_secret callback_url) ) {
        Carp::croak "'$param' is expected but not found in configuration"
            unless $config->{$param};
    }

    debug "new google with $client_id, $client_secret, $callback_url";
    $furl = Furl->new(
        agent    => "Dancer-Plugin-Auth-Google/$VERSION",
        timeout  => 5,
        ssl_opts => {
            SSL_verify_mode => SSL_VERIFY_NONE(),
        },
    );

    return 1;
};

register 'auth_google_authenticate_url' => sub {
    Carp::croak 'auth_google_init() must be called first'
        unless defined $callback_url;

    my $uri = URI->new('https://accounts.google.com/o/oauth2/v2/auth');
    $uri->query_form(
        client_id     => $client_id,
        redirect_uri  => $callback_url,
        scope         => $scope,
        access_type   => $access_type,
        response_type => 'code',
    );

    debug "google auth uri: $uri";
    return $uri;
};

get '/auth/google/callback' => sub {
    debug 'in google auth callback';

    return redirect $callback_fail if params->{'error'};

    my $code = params->{'code'};
    return redirect $callback_fail unless $code;

    my $res = $furl->post(
        'https://www.googleapis.com/oauth2/v4/token',
        [ 'Content-Type' => 'application/x-www-form-urlencoded' ],
        {
            code          => $code,
            client_id     => $client_id,
            client_secret => $client_secret,
            redirect_uri  => $callback_url,
            grant_type    => 'authorization_code',
        }
    );

    my ($data, $error) = _parse_response( $res->decoded_content );
    if (ref $data && !$error) {
        # Google tells us to ignore any unrecognized fields
        # included in the response (like their "id_token").
        $data = {
            access_token  => $data->{access_token},
            expires_in    => $data->{expires_in},
            token_type    => $data->{token_type},
            refresh_token => $data->{refresh_token},
        };
    }
    else {
        return send_error('google auth: ' . (defined $error ? $error : 'unknown error'));
    }

    $res = $furl->get(
        'https://www.googleapis.com/oauth2/v2/userinfo',
        [ 'Authorization' => 'Bearer ' . $data->{access_token} ],
    );

    my $user;
    ($user, $error)  = _parse_response( $res->decoded_content );
    return send_error("google auth: $error") if $error;

    if (exists $user->{verified_email}) {
        # we stringify our JSON::Bool data as some session
        # backends might have trouble storing objects.
        $user->{verified_email} = "$user->{verified_email}";
    }
    $user = _convert_to_legacy_gplus_format($user) if $legacy_gplus;

    session 'google_user' => { %$data, %$user };
    redirect $callback_success;
};

sub _convert_to_legacy_gplus_format {
    my ($user) = @_;

    return {
        kind        => "plus#person",
        displayName => $user->{name},
        name => {
            givenName => $user->{given_name},
            familyName => $user->{family_name},
        },
        language   => $user->{locale},
        isPlusUser => ($user->{link} && index($user->{link},'http') == 0 ? 1 : 0),
        url        => $user->{link},
        gender     => $user->{gender},
        image => {
            url => $user->{picture},
            isDefault => 0,
        },
        domain         => $user->{hd},
        emails         => [ { type => "account", value => $user->{email} } ],
        etag           => undef,
        verified       => $user->{verified_email},
        circledByCount => undef,
        id             => $user->{id},
        objectType     => "person",
    };
}

sub _parse_response {
    my ($response) = @_;
    my ($data, $error);

    try {
        $data = from_json($response);
    } catch {
        if ($response =~ /timeout/) {
            $error = "google auth: timeout ($response)";
        }
        else {
            $error = "google auth: error parsing JSON ($_)";
        }
    };
    return ($data, $error);
}

register_plugin;
__END__



( run in 1.586 second using v1.01-cache-2.11-cpan-817d5f8af8b )