Authenticating OAuth2.0 with R using httr

Viewed 92

I'm trying to create authenticate into the Letterboxd API using R and the httr package. The Letterboxd docs give instructions, but I am not sure how to put everything together into a URL.

I know the url is:

url <- "https://api.letterboxd.com/api/v0/auth/token"

And then they want my username and password, presumably as JSON, but what I'll write as a named list since I'm doing this in R:

login_info <- list(
  grant_type = "password",
  username = "myemail@gmail.com",
  password = "extremelysecurepassword"
)

I've tried various calls, using GET(), oauth2.0_token(), oauth_endpoint() functions from the httr package.

I feel like I have all the necessary information and am circling around a solution, but I can't quite nail it.

The docs contain this information:

When generating or refreshing an access token, make a form request to the /auth/token endpoint with Content-Type: application/x-www-form-urlencoded and Accept: application/json headers

(Full text is linked to above)

And I'm not sure how to add that information; in working with APIs through R, I'm used to just sending URLs with UTM parameters, but the inputs they want don't work here using ? and &.

I'm aware of this related post, but it looks like it relies on having a secret token already. And I don't seem to be able to generate a secret token inside of the GUI of Letterboxd.com, which is again what I'm used to doing with authentication. I think I need to feed it those sources of information above in login_info to the url, but I don't quite know how to connect the dots.

How do I authenticate to the Letterboxd API using R?

1 Answers

This runs for me but I get a 401 Unauthorized since you correctly did not supply valid credentials. It looks like there is a python library for this API https://github.com/swizzlevixen/letterboxd if you need hints how to make subsequent requests.

sign_request() is mimicking python library's api.py#L295-L304

sign_request <- function(apisecret, url, method, body = "") {

  signing_bytes <- as.raw(c(charToRaw(method), 0, charToRaw(url), 0, charToRaw(body)))

  # https://stackoverflow.com/a/31209556/8996878
  # https://stackoverflow.com/q/54606193/8996878

  digest::hmac(key = apisecret, object = signing_bytes, algo = "sha256", serialize = FALSE)
}

url <- "https://api.letterboxd.com/api/v0/auth/token"

login_info <- list(
  grant_type = "password",
  username = "myemail@gmail.com",
  password = "extremelysecurepassword"
)

apikey <- "mytopsecretapikey"
apisecret <- "YOUR_API_SECRET"
method <- "POST"

params <- list(
  apikey = apikey,
  nonce = uuid::UUIDgenerate(),
  timestamp = round(as.numeric(Sys.time()))
)

# now we need to sign the request
body <- paste(names(login_info), login_info, sep = "=", collapse = "&")
body <- URLencode(body)
body <- gsub("@","%40", body) # something URLencode doesn't do but post does

destination <- httr::parse_url(url)
destination$query <- params
post_url_with_params <- httr::build_url(destination)

signature <- sign_request(apikey, post_url_with_params, method, body)

token_request <- httr::POST(url, httr::add_headers(
  "Accept" = "application/json",
  "Authorization" = paste0("Signature ", signature)
),
query = params,
body = login_info, encode = "form", httr::verbose()
)

token_body <- httr::content(token_request, type = "application/json")

# look for the value of"access_token"


Related