Fixing Java URL Authentication 401 Errors

I came across an issue the other day where my URL with inline authentication tokens was giving me a 401 Unauthorized error.  For the unfamiliar, URL authentication isn’t very heavily used, but it works like this:


That username:password bit is known in Java as the User Info string, and Java handles it differently than web browsers do.

If you enter a URL with an authentication token in most modern browsers, the browser will add a Basic Authentication header to the request, which does all the heavy lifting.  This header just contains a Base64-encoded version of the User Info string.  For some reason Java doesn’t do this, so we have to generate the header ourselves:

URI uri = new URL("http://username:password@protected.domain.example/resource").toURI();

String userInfo = uri.getRawUserInfo();
if(userInfo != null && userInfo.length() > 0)
    userInfo = Base64.getEncoder().encodeToString(userInfo.getBytes());

HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
if(userInfo != null && userInfo.length() > 0)
    connection.setRequestProperty("Authorization", "Basic " + userInfo);

A few notes on the code:

  • Using URL#getUserInfo() or URI#getUserInfo() may result in special characters being incorrectly encoded, but my tests are far from exhaustive.  URI#getRawUserInfo() seems like the safest method.
  • Because of the if statement, it’s fine to leave this in whatever authentication class/method is at work, since if it’s passed a URL without authentication tokens, it will simply ignore it.
  • Many servers will ignore the in-URL tokens and just handle the Basic Authentication header, but it doesn’t hurt to leave the User Info string in.

I recently answered this StackOverflow question regarding the Shopify API, which uses URL authentication in queries.  It’s an issue that comes up once in a blue moon, so I figured sharing it here would be a good idea since it took me forever to figure out what the issue was.

Leave a Reply

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