Search code examples
rurlencodehmachmacsha1

Moz API: signed authentication with R


I am trying to access the Moz API with R to get some data but I cannot get the signed authentication right so my requests always get 401 response. I think something is wrong with the signature. Here is my code:

library(rjson)
library(digest)
library(RCurl)

# Construct the url to call the API
api <- 'http://lsapi.seomoz.com/linkscape/url-metrics/'
site <- 'facebook.com'

# that is the cols parameter that I need to get the data required
# there is no issue with it as it works when used with the provided sample call

metrics <- 'Cols=36029458443938976'
ampersand <- '&'

# this is my access id as given by Moz
access_id <- 'member-d8fc642751'

# this gets the current time and adds another 5 minutes as recommended (Unix timestamp format)
expires <- round(as.numeric(as.POSIXct(Sys.time()+300)))

# this concatenates the access id and the expires with a linefeed as explained in the API doc
hash_string <- paste('member-d8fc642751','\n', expires, sep="")

# this hashes the string from above with my secret key with sha1, don't worry this key is not valid anymore
hmac_hash <- hmac('f74fc2f2a8d5337aaa0550bfa3a9bdaf', hash_string, "sha1")

# Encoding with base64
base64_hash <- base64(hmac_hash)

# URL encoding the generated signature
encoded_signature <- URLencode(base64_hash, reserved = TRUE)

# constructing the url for the API call
url <- paste(api, site, '?', metrics, ampersand, 'AccessID=', access_id, ampersand, 'Expires=', expires, ampersand, 'Signature=', encoded_signature, sep="")


# Get data from API (json format)
Moz_json_data <- fromJSON(file=url, method='C')

Here is a comparison:

1. http://lsapi.seomoz.com/linkscape/url-metrics/facebook.com?Cols=36029458443938976&AccessID=member-d8fc642751&Expires=1415381495&Signature=YThmYTI1N2I4MDYzY2QxMGQzNDNjOWVlNmIyYTU1MzgzY2FlOWFiOA%3d%3d
2. http://lsapi.seomoz.com/linkscape/url-metrics/facebook.com?Cols=36029458443938976&AccessID=member-d8fc642751&Expires=1415465853&Signature=vyZmngnjiYy5Ns62LCLRHXgQQ6c%3D

The first one is generated by the code and does not work. The second one is provided as a sample request by Moz and works. As you can see the Signature in the second one much shorter, which makes me think I am generating the wrong signature but I do follow the same steps as outlined in their API doc.

Useful links:

http://apiwiki.moz.com/signed-authentication

http://apiwiki.moz.com/anatomy-of-a-mozscape-api-call

Any help will be greatly appreciated!


Solution

  • If you follow the example PHP code they provide, you'll see that they set raw=TRUE when calling hash_hmac. Thus when they encode the data, they are encoding the bytes of the hash, not the character representation of the bytes of the hash. You need to do this in the R version as well. Compare

    # INCORRECT
    (dd <- hmac('f74fc2f2a8d5337aaa0550bfa3a9bdaf', hash_string, "sha1"))
    # [1] "e521bd74fba9296920efb897a2bc7578d3e8b075"
    base64(dd)
    # [1] "ZTUyMWJkNzRmYmE5Mjk2OTIwZWZiODk3YTJiYzc1NzhkM2U4YjA3NQ=="
    # attr(,"class")
    # [1] "base64"
    

    and

    # CORRECT
    (dd <- hmac('f74fc2f2a8d5337aaa0550bfa3a9bdaf', hash_string, "sha1", raw=TRUE))
    # [1] e5 21 bd 74 fb a9 29 69 20 ef b8 97 a2 bc 75 78 d3 e8 b0 75
    base64(dd)
    # [1] "5SG9dPupKWkg77iXorx1eNPosHU="
    # attr(,"class")
    # [1] "base64"