http://www.perlmonks.org?node_id=11131443

Bod has asked for the wisdom of the Perl Monks concerning the following question:

As part of connecting to LinkedIn using LWP::Authen::OAuth2, I have decided to write a sub-class of LWP::Authen::OAuth2::ServiceProvider which is designed to be sub-classed for exactly this kind of application. This way, it will hopefully be useful to other people.

However, I need to override a method which has not been designed to be overridden! The LinkedIn API doesn't comply with the OAuth2 spec. The token_type parameter is mandatory but missing. Therefore, I am trying to inject it into the response from LinkedIn by sub-classing the method, adding the missing parameter and then calling the method in the super class. But I am not managing to get the injection to work.

Here is the sub in LWP::Authen::OAuth2::ServiceProvider that I am overridding:

# Attempts to construct tokens, returns the access_token (which may ha +ve a # request token embedded). sub construct_tokens { my ($self, $oauth2, $response) = @_; # The information that I need. my $content = eval {$response->decoded_content}; if (not defined($content)) { $content = ''; } my $data = eval {decode_json($content)}; my $parse_error = $@; my $token_endpoint = $self->token_endpoint(); # Can this have done wrong? Let me list the ways... if ($parse_error) { # "Should not happen", hopefully just network. # Tell the programmer everything. my $status = $response->status_line; return <<"EOT" Token endpoint gave invalid JSON in response. Endpoint: $token_endpoint Status: $status Parse error: $parse_error JSON: $content EOT } elsif ($data->{error}) { # Assume a valid OAuth 2 error message. my $message = "OAuth2 error: $data->{error}"; # Do we have a mythical service provider that gives us more? if ($data->{error_uri}) { # They seem to have a web page with detail. $message .= "\n$data->{error_uri} may say more.\n"; } if ($data->{error_description}) { # Wow! Thank you! $message .= "\n\nDescription: $data->{error_description}\n +"; } return $message; } elsif (not $data->{token_type}) { # Someone failed to follow the spec... return <<"EOT"; Token endpoint missing expected token_type in successful response. Endpoint: $token_endpoint JSON: $content EOT } my $type = $self->access_token_class(lc($data->{token_type})); if ($type !~ /^[\w\:]+\z/) { # We got an error. :-( return $type; } eval {load($type)}; if ($@) { # MAKE THIS FATAL. (Clearly Perl code is simply wrong.) confess("Loading $type for $data->{token_type} gave error: $@" +); } # Try to make an access token. my $access_token = $type->from_ref($data); if (not ref($access_token)) { # This should be an error message of some sort. return $access_token; } else { # WE SURVIVED! EVERYTHING IS GOOD! if ($oauth2->access_token) { $access_token->copy_refresh_from($oauth2->access_token); } return $access_token; } }
The author has commented the point it fails as # Someone failed to follow the spec...!

This is my sub that overrides the above...

sub construct_tokens { my ($self, $oauth2, $response) = @_; my $content = eval {$response->decoded_content}; eval {decode_json($content)}; $response->push_header( 'token_type', 'Bearer' ) unless $@; $self->SUPER::construct_tokens($oauth2, $response); }
I'm trying to set token_type as Bearer so that the rest of the sub in the superclass doesn't complain.

Is there a good way to to inject this parameter or am I approaching this in the wrong way?