Setting basic authentication credentials in WWW::M

2019-08-05 14:43发布

问题:

I'm having trouble using basic authentication in WWW::Mechanize. I'm trying to connect to the Streak API, the documentation for which states:

Streak uses HTTP Basic Auth to sign each request with your API key. Simply set the username of the request to the API key. The password field is ignored. All requests must be made over HTTPS as HTTP requests will be ignored.

Here's a sample request:

curl https://www.streak.com/api/v1/pipelines -u YOUR_API_KEY:

I can successfully access the API using curl in this fashion. However, I'm not able to authenticate successfully using WWW::Mechanize. Here's what I've got:

#!perl

use warnings;
use strict;
use feature 'say';

use WWW::Mechanize;

my $api = 'https://www.streak.com/api/v1/';

my $mech = WWW::Mechanize->new( autocheck => 0 ); # don't die on errors

$mech->credentials('my API key here', '');

$mech->get($api . 'pipelines');

say $mech->response->status_line;
say $mech->res->request->as_string;

Running me that code gets:

401 Unauthorized
GET https://www.streak.com/api/v1/pipelines
Accept-Encoding: gzip
User-Agent: WWW-Mechanize/1.83

The authentication isn't even being attempted. Can anyone suggest why that may be the case, and what I could do to fix it? This code is running in Strawberry Perl 5.24.0.1, if that may have anything to do with it.

[Edited to include suggestion from simbabque of examining request object.]

回答1:

I found the problem.

Following the technique in this post on Perl Maven ("How to find out the URL and realm?"), it turns out that the API doesn't send a challenge for credentials, specifying a realm, when you try connecting to it. It just gives you an error message stating that basic authentication is required. LWP::UserAgent doesn't know to do anything else at that point.

So, I copied the authentication header from the successful curl request that simbabque suggested examining, and manually set that on the user-agent object:

$ua->default_header('Authorization' => 'Basic [Base64-encoded string here]');

Now it works. Happy times.