Many software developers were flummoxed at the start of the year when it was announced that Discogs would start requiring OAuth authentication for image downloads. At the same time, a new limit of 1000 image downloads per day, per application, was imposed.
As a Premium API user, we at OneMusicAPI were informed of this change in December, and we immediately made plans on how to cope with this change. We knew that, while initially there wouldn't be much change to our operations, given OneMusicAPI simply returned image URLs sourced from Discogs without actually downloading them, our clients would both run out of their image allocation and find it a pain to rewrite their software to authenticate using OAuth.
The result was the image endpoint and a new images plan. By caching Discogs images, we were soon able to serve up way more than the 1000 image limit to each application. Furthermore, we did the tedious OAuth authentication work ourselves.
Since we started counting, in March, we've served almost 400,000 images from our cache. After an initial slow start (as the cache was populating) we now serve between 100,000 and 200,000 images from the cache each month. That's a lot of developer work saved.
If you can't use the OneMusicAPI image cache (and if not I'd like to know why!), though, how do you write the OAuth code to download an image, using Java?
OAuth is a protocol for authorisation. It defines a series of steps and messages between client and server which importantly including the end user's approval. Discogs uses version 1.0a of OAuth.
There are a number of Java libraries that implement the OAuth protocol. The one I use in this tutorial is
oauth-signpost. Go ahead and
download it or point your pom.xml
toward:
<dependency> <groupId>oauth.signpost</groupId> <artifactId>signpost-core</artifactId> <version>1.2.1.2</version> <scope>compile</scope> </dependency>
While that's downloading, a quick overview of the OAuth process. It consists of a number of steps:
OAuthProvider
and OAuthConsumer
OAuthProvider
to retrieve a request tokenOAuthConsumer
OAuthConsumer
to sign subsequent HTTP callsOAuthProvider
and OAuthConsumer
Pretty easy this one. For the former, it's most straightforward to use DefaultOAuthProvider
which
uses a HttpURLConnection
to make the calls to Discogs.
OAuthProvider provider = new DefaultOAuthProvider( "http://api.discogs.com/oauth/request_token", "http://api.discogs.com/oauth/access_token", "http://www.discogs.com/oauth/authorize");
Those URLs are published by Discogs and can be seen in your Discogs applications page. At this
point you should also set the User-Agent
:
provider.setRequestHeader("User-Agent", userAgent);
The reason for this is that Discogs is quite picky about User-Agents. I've had requests rejected before which do not specify one.
Now create the OAuthConsumer
:
OAuthConsumer consumer = new DefaultOAuthConsumer(consumerKey, consumerSecret);
The consumerKey
and consumerSecret
are, again, listed on your
Discogs applications page.
The OAuthProvider
and OAuthConsumer
objects can now be
used to implement the remainder of the OAuth protocol.
OAuthProvider
to retrieve a request tokenThe next step is to retrieve a request token, in the form of a URL:
String verificationUrl = provider.retrieveRequestToken(consumer, OAuth.OUT_OF_BAND);
This URL is used in the next step, to ask the end-user to approve the authentication
The verificationUrl
should now be used to download a page that can be presented to
the user so they can approve the authentication. Once the user does so, a new verification code is
generated.
Note that the user has to be logged in; if they are not, Discogs will forward them to the login page, and following a successful login they will be able to approve the authentication between your app and Discogs.
You must now ask the user to copy and paste the verification code for the next step.
OAuthConsumer
To retrieve the access token, and thus complete the OAuth authentication process, you can do:
provider.retrieveAccessToken(consumer, verificationCode);
Here, verificationCode
is the verification code that the user copy and pasted following their
approval.
OAuthConsumer
to sign subsequent HTTP calls
The consumer
is now ready to sign HTTP calls to Discogs.
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); consumer.sign(conn); conn.setRequestProperty("User-Agent", userAgent);
You can now use the conn
as normal - opening an InputStream
to it,
returning the response code, or however you want to interact.
And, as ever, remember to set the User-Agent
!
These instructions are taking on even more importance following the announcement that,
from 15th August, access to the search API (/database/search
)
will require OAuth authentication. Another reason to use OneMusicAPI ;-)
Thanks to JD Hancock who made the the image above available for sharing.