Authentication

Securing your requests

Creating your digital signature

The Radioplayer Partner API (WRAPI) contains unique metadata on radio stations and their broadcasts. To protect this data, the Radioplayer metadata service will only respond to signed HTTPS requests.

To make these signed HTTPS requests, you will need credentials that we supply.

Obtaining your credentials

A signed HTTPS request to the metadata service requires two keys:

  • An API key uniquely identifying the licensee, and
  • A private key used to encrypt the request, shared only between you and Radioplayer.

We issue these keys to you once you are approved for a Radioplayer developer account. These keys are then used to verify the identity of the author of the requests to the Radioplayer metadata service.

Connecting to Radioplayer's data

You can use your two keys to digitally "sign" your requests.

Whenever you issue a request to Radioplayer's metadata service, you programmatically create this digital signature.

For instance, here the digital signature is created using today's date and time and the Node.js



  let date = new Date ();
  let toSign = `date: ${date}`;
  let parsedKey = sshpk.parsePrivateKey(privateKey);
  // privateKey refers to the ascii representation of your private key file

This is the "signature", which will be decrypted on the other side to prove the sender is who they say they are. This is possible because only you and Radioplayer have access to the private key.

Decrypting the digital signature

Upon receipt, the Radioplayer Partner API (WRAPI) unpacks the signature, decrypting it using the private key it shares with you.

With the date and private key in hand, it uses the private key to look up the public key, or API key, associated with that private key and checks that they also match.

With a valid date information, to prevent duplication or cloning, the Radioplayer Partner API (WRAPI) verifies that the signed request is coming from the right person, and responds to the request:

If any of the required conditions are not met, the Radioplayer Partner API (WRAPI) returns a 403 error.

Issuing signed HTTPS requests in Node.js

For instance, this code in Javascript uses the http and http-signature npm packages as well as the keys to place a digital signature:



  var apiKey = "XXXXXXXX-XXXXXXXXXXXX-XXXXXX";
  var key = fs.readFileSync([~/] + apiKey + '.pem','ascii')
  var options = {     host: //[..etc]   }
  var request = https.request(options, function(obj) {
    var chunks = [];
    obj.on('data', function (chunk) { chunks.push(chunk);});
    obj.on('end', function () {// process data: JSON.parse(chunks)});
  });

You can now safely make requests to the service.

Issuing signed HTTPS requests in Java

You can also create signed HTTPS requests in Java. To do so, you will need to install the following dependencies (to download the POM file, click here).

These are:

GroupLibraryVersion
net.adamcin.httpsighttpsig-api1.3.1
net.adamcin.httpsighttpsig-bouncycastle0.6.0
net.adamcin.httpsighttpsig-ssh-jce1.3.1
org.bouncycastlebcpkix-fips1.0.3
org.apache.httpcomponentshttpclient4.5.3

With the dependencies downloaded and installed, you can create the following simple signed request.

Here the private key is loaded in as a string, keyId, and the PEM file created and loaded in:



  final String keyId = "your-key-id";
  File pemFile = new File( getClass().getResource(keyId +".pem").getFile())
  Key k = PEMHelper.readKey(pemFile, new char[]{ '' });

Here a new signer is generated:

Signer signer = new Signer(k, new UserFingerprintKeyId(keyId));

The key is rotated and signed with the SHA-256 algorithm:



  Challenge challenge = new Challenge("",
          Constants.DEFAULT_HEADERS,
          Arrays.asList( new Algorithm[] {Algorithm.RSA_SHA256} )
          );
  signer.rotateKeys(challenge);

Part of the signature is the date and time of the request. Here we create a date formatter which will format dates accordingly in the format required by RFC 1123:


 DateFormat df = new SimpleDateFormat(RequestContent.DATE_FORMAT_RFC1123);
  df.setTimeZone(TimeZone.getTimeZone("GMT"));

You now have the ingredients for your signature, so you can build your request, put the date into the header and sign it:



 RequestContent.Builder requestContentBuilder = new  RequestContent.Builder();   	
 requestContentBuilder.addHeader("date", df.format(new Date()));
 RequestContent requestContent = requestContentBuilder.build();
 Authorization auth = signer.sign(requestContent);
 String sig = new StringBuilder().append("Signature keyId=")
  .append("\"")
  .append(keyId)
  .append("\"")
  .append(",algorithm=\"rsa-sha256\",signature=\"")
  .append(auth.getSignature()).append("\"").toString();

In this request, the details of a single radio station - Fun Kids - are requested from the Radioplayer metadata service:



  HttpGet request = new HttpGet("https://api.radioplayer.org/v2/stations/8261004");

The signed header is added and the request sent:



  request.addHeader("date", df.format(requestContent.getDateGMT()));
  request.addHeader("Authorization", sig);
  HttpClient client = HttpClientBuilder.create().build();

  HttpResponse r = client.execute();

The response is then read back.



r.getEntity().getContent().transferTo(System.out);

Writing an authentication script

You can also create bash scripts that once run will create a signed HTTPS request, using the openssl package


 now=$(date -u "+%a, %d %h %Y %H:%M:%S GMT")sig=$(echo "date:" $now | tr -d '' | 
 openssl dgst -sha256 -sign "~your-user.pem" | 
 openssl enc -e -a | tr -d '') curl -sS "http://api.radioplayer.org/stations/826101""$@" \
 -H "date: $now" \
 -H "Authorization: Signature keyId="58ad7ede2dee2770cb89a1cf",algorithm="rsa-sha256",signature="$sig""

Here the signed request, including its date and time, is dynamically created when the request is sent.

Managing connection errors

It may be that connections fail or are refused when you try to submit a signed HTTPS request, or that signed responses from Radioplayer may not be getting through to you.

There could be a number of reasons for this:

  • The API key or private key may contain an error and thus fail to authenticate – you will receive a 403 error.
  • Your Radioplayer developer trial may have finished
  • Your query may be invalid or badly formed, in which case you will receive a 400 error.
  • You may have exceeded your quota of data for the month (if this is the case, you should have had an automatically generated email warning you that your quota was over 80%) – if this is the case, you will receive a 429 error

Radioplayer supplies a list of error codes you can refer to if you have had problems connecting to the Radioplayer metadata service, which you can find in the API documentation.