Python urllib2, basic HTTP authentication, and

Posted on

Question :

Python urllib2, basic HTTP authentication, and

I’m playing around, trying to write some code to use the
APIs to shorten a URL.

After reading, I tried:

   TRIM_API_URL = ''
   auth_handler = urllib2.HTTPBasicAuthHandler()
   opener = urllib2.build_opener(auth_handler)
   response = urllib2.urlopen('%s/trim_simple?url=%s'
                              % (TRIM_API_URL, url_to_trim))
   url =

response.code is 200 (I think it should be 202). url is valid, but
the basic HTTP authentication doesn’t seem to have worked, because the
shortened URL isn’t in my list of URLs (at

After reading
I also tried:

   TRIM_API_URL = ''
   password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
   password_mgr.add_password(None, TRIM_API_URL, USERNAME, PASSWORD)
   auth_handler = urllib2.HTTPBasicAuthHandler(password_mgr)
   opener = urllib2.build_opener(auth_handler)
   response = urllib2.urlopen('http://%s/trim_simple?url=%s'
                              % (TRIM_API_URL, url_to_trim))
   url =

But I get the same results. (response.code is 200 and url is valid,
but not recorded in my account at

If I use query string parameters instead of basic HTTP authentication,
like this:

   TRIM_API_URL = ''
   response = urllib2.urlopen('%s/trim_simple?url=%s&username=%s&password=%s'
                              % (TRIM_API_URL,
   url =

…then not only is url valid but it’s recorded in my account.
(Though response.code is still 200.)

There must be something wrong with my code though (and not’s API), because

$ curl -u yacitus:xxxx


{"trimpath":"hfhb","reference":"nH45bftZDWOX0QpVojeDbOvPDnaRaJ","trimmed":"11/03/2009","destination":"","trim_path":"hfhb","domain":"","url":"","visits":0,"status":{"result":"OK","code":"200","message":" URL Added."},"date_time":"2009-03-11T10:15:35-04:00"}

…and the URL does appear in my list of URLs on

And if I run:

$ curl -u yacitus:xxxx

…again, I get:

{"trimpath":"hfhb","reference":"nH45bftZDWOX0QpVojeDbOvPDnaRaJ","trimmed":"11/03/2009","destination":"","trim_path":"hfhb","domain":"","url":"","visits":0,"status":{"result":"OK","code":"201","message":" URL Already Created [yacitus]."},"date_time":"2009-03-11T10:15:35-04:00"}

Note code is 201, and message is “ URL Already Created [yacitus].”

I must not be doing the basic HTTP authentication correctly (in either attempt). Can you spot my problem? Perhaps I should look and see what’s being sent over the wire? I’ve never done that before. Are there Python APIs I can use (perhaps in pdb)? Or is there another tool (preferably for Mac OS X) I can use?

Answer #1:

This seems to work really well (taken from another thread)

import urllib2, base64

request = urllib2.Request("")
base64string = base64.encodestring('%s:%s' % (username, password)).replace('n', '')
request.add_header("Authorization", "Basic %s" % base64string)   
result = urllib2.urlopen(request)
Answered By: Ben Keating

Answer #2:

Really cheap solution:


(which you may decide is not suitable for a number of reasons, like security of the url)

Github API example:

>>> import urllib, json
>>> result = urllib.urlopen('')
>>> r = json.load(result.fp)
>>> result.close()
Answered By: Ali Afshar

Answer #3:

Take a look at this SO post answer and also look at this basic authentication tutorial from the urllib2 missing manual.

In order for urllib2 basic authentication to work, the http response must contain HTTP code 401 Unauthorized and a key "WWW-Authenticate" with the value "Basic" otherwise, Python won’t send your login info, and you will need to either use Requests, or urllib.urlopen(url) with your login in the url, or add a the header like in @Flowpoke’s answer.

You can view your error by putting your urlopen in a try block:

except urllib2.HTTPError, e:
    print e.headers
    print e.headers.has_key('WWW-Authenticate')
Answered By: Mark Mikofski

Answer #4:

The recommended way is to use requests module:

#!/usr/bin/env python
import requests # $ python -m pip install requests
####from pip._vendor import requests # bundled with python

url = ''
user, password = 'user', 'passwd'

r = requests.get(url, auth=(user, password)) # send auth unconditionally
r.raise_for_status() # raise an exception if the authentication fails

Here’s a single source Python 2/3 compatible urllib2-based variant:

#!/usr/bin/env python
import base64
    from urllib.request import Request, urlopen
except ImportError: # Python 2
    from urllib2 import Request, urlopen

credentials = '{user}:{password}'.format(**vars()).encode()
urlopen(Request(url, headers={'Authorization': # send auth unconditionally
    b'Basic ' + base64.b64encode(credentials)})).close()

Python 3.5+ introduces HTTPPasswordMgrWithPriorAuth() that allows: eliminate unnecessary 401 response handling, or to unconditionally send credentials on the first request in order to communicate with servers that return a 404 response instead of a 401 if the Authorization header is not sent..

#!/usr/bin/env python3
import urllib.request as urllib2

password_manager = urllib2.HTTPPasswordMgrWithPriorAuth()
password_manager.add_password(None, url, user, password,
                              is_authenticated=True) # to handle 404 variant
auth_manager = urllib2.HTTPBasicAuthHandler(password_manager)
opener = urllib2.build_opener(auth_manager)

It is easy to replace HTTPBasicAuthHandler() with ProxyBasicAuthHandler() if necessary in this case.

Answered By: jfs

Answer #5:

I would suggest that the current solution is to use my package urllib2_prior_auth which solves this pretty nicely (I work on inclusion to the standard lib.

Answered By: mcepl

Answer #6:

Same solutions as Python urllib2 Basic Auth Problem apply.

see; you can subclass urllib2.HTTPBasicAuthHandler to add the Authorization header to each request that matches the known url.

class PreemptiveBasicAuthHandler(urllib2.HTTPBasicAuthHandler):
    '''Preemptive basic auth.

    Instead of waiting for a 403 to then retry with the credentials,
    send the credentials if the url is handled by the password manager.
    Note: please use realm=None when calling add_password.'''
    def http_request(self, req):
        url = req.get_full_url()
        realm = None
        # this is very similar to the code from retry_http_basic_auth()
        # but returns a request object.
        user, pw = self.passwd.find_user_password(realm, url)
        if pw:
            raw = "%s:%s" % (user, pw)
            auth = 'Basic %s' % base64.b64encode(raw).strip()
            req.add_unredirected_header(self.auth_header, auth)
        return req

    https_request = http_request
Answered By: dnozay

Answer #7:

Try python-request or python-grab

Answered By: Andrew G

Leave a Reply

Your email address will not be published. Required fields are marked *