Reusing Google OAuth2 Access Tokens in Perl

19.11.2015 with tags development , perl

Recently at work I was asked to move the statistics generated to assist with capacity planning from an internal wiki to a more accessible Google Sites page. To update the embedded spreadsheets and related charts I wanted to use preexisting perl scripts that grabbed the data from various sources.

There’s a nice perl module called Net::Google::Spreadsheets which gets you up and running quickly, but the problems start when you want to:

  1. Use OAuth2 so your password isn’t in a script viewable by anyone else.
  2. Have the ability to use an authentication token without user interaction.

Wherever I looked, all I could find were people that were in the same situation. There didn’t seem to be any documentation on how to create a token nor how it could be promoted to a refresh token and then used at a later point in time.

Poring over what little documentation there was and reading through the module source code I was finally able to work out how to give access to my application. If the previous token had expired then I could ask for a refresh token and repeat this process as necessary. Now I can have access to my spreadsheets without further interaction and update programmatically. It seems so simple now, but hindsight is always 2020.

To initially authorise your application the code snippet fetches a token for the given scope using the client ID and secret obtained from the Google developer console.

#!/usr/bin/perl

use Storable;
use Net::Google::Spreadsheets;
use Net::Google::DataAPI::Auth::OAuth2;
use Term::Prompt;

my $oauth2 = Net::Google::DataAPI::Auth::OAuth2->new(
    client_id => '...',
    client_secret => '...',
    scope => ['http://spreadsheets.google.com/feeds/'],
);

my $url = $oauth2->authorize_url();

print "URL: $url\n";

my $code = prompt('x', 'paste the code: ', '', '');

my $token = $oauth2->get_access_token($code) or die;
my $session = $token->session_freeze;

# save the session which can be restored later
store($session, 'google_spreadsheet.session');

You will need to go to the URL returned from the authorize_url() method to accept the access, then the session token will be saved in the current working directory.

Now you can use the saved session with the token we generated earlier and continue to do so even if the initial token expires.

#!/usr/bin/perl
use strict;
use warnings;
use v5.10;

use Net::Google::Spreadsheets;
use Net::Google::DataAPI::Auth::OAuth2;
use Net::OAuth2::AccessToken;
use Storable;

my $sessionfile="/directory_to_session/google_spreadsheet.session";

my $oauth2 = Net::Google::DataAPI::Auth::OAuth2->new(
    client_id => '...',
    client_secret => '...',
    scope => [ 'http://spreadsheets.google.com/feeds/' ],
);

# deserialise the file so we can thaw the session and reuse the refresh token
my $session = retrieve($sessionfile);

my $restored_token = Net::OAuth2::AccessToken->session_thaw($session,
    auto_refresh => 1,
    profile => $oauth2->oauth2_webserver,
);
$oauth2->access_token($restored_token);

my $service = Net::Google::Spreadsheets->new(
    auth => $oauth2,
);

my $usage_spreadsheet = $service->spreadsheet(
    {
        # key => '... key deprecated in the current API ...', 
        title => 'yourSpreadsheetTitle',
    }
);

Hopefully this will help some others out there.