using twitter api with golang

Asked

Viewed 108 times

0

I am trying to make this request "oauth/request_token" on twitter using go.

// GET PARAMS TO REQUEST
t := time.Now().Format("20060102150405")
values := make(url.Values)
values.Add("oauth_nonce", auth.ANonce)
values.Add("oauth_callback", auth.Path)
values.Add("oauth_signature_method", "HMAC-SHA1")
values.Add("oauth_timestamp", t)
values.Add("oauth_consumer_key", auth.ClientID)

// GET SIGNATURE
baseString := fmt.Sprintf("POST&%s&%s", auth.Path, values.Encode())
key := fmt.Sprintf("%s&", auth.SecretID)

// GENERATE HASH
mac := hmac.New(sha1.New, []byte(key))
mac.Write([]byte(baseString))
signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))

// MAKE THE REQUEST
values.Add("oauth_version", "1.0")
values.Add("oauth_signature", signature)
client := urlfetch.Client(ctx)
req, err := http.NewRequest("POST", auth.RequestToken, nil)
if err != nil {
    return fmt.Errorf("getOAuthToken Request Error: %v", err)
}
// SET HEADER
req.Header.Set("Authorization", fmt.Sprintf("OAuth oauth_nonce=\"%s\", oauth_callback=\"%s\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"%s\", oauth_consumer_key=\"%s\", oauth_signature=\"%s\", oauth_version=\"1.0\"", auth.ANonce, auth.Path, t, auth.ClientID, signature))
res, err := client.Do(req)
if err != nil {
    return fmt.Errorf("getOAuthToken Client Error: %v", err)
}
defer res.Body.Close()

The problem is that I’m getting this error:

{"errors":[{"code":215,"message":"Bad Authentication data."}]}

What would be the problem with my code ?

1 answer

0


Your code has a diversity of problems! The first is that you’re using t with an incorrect format. The expected format for oauth_timestamp is timestamp in seconds. See the difference:

//erro #1
t := time.Now().Format("20060102150405")
fmt.Println("time: ", t)

//correto #1
t_ := fmt.Sprintf("%d", time.Now().Unix())
fmt.Println("time: ", t_)

See on the playground: https://play.golang.org/p/L74MzEHkVwS

Another error is that you are not following the steps for constructing the parameter collection. In the documentation it says:

The process to build the string [for Collecting Parameters] is very specific:

  1. Percent Every key and value that will be Signed.
  2. Sort the list of Parameters alphabetically 1 by encoded key [2].
  3. For each key/value pair:
  4. Append the encoded key to the output string.
  5. Append the "=" Character to the output string.
  6. Append the encoded value to the output string.
  7. If there are more key/value pairs remaining, append a ?&' Character to the output string.

Note some important points in this step:

  1. You must do the Find in key and value;
  2. You must order the key

This means that instead of you using one url.Values() you should have done something like:

values := make(map[string]string)
values["oauth_nonce"] = auth.ANonce
values["oauth_callback"] = auth.Path
values["oauth_signature_method"] = "HMAC-SHA1"
values["oauth_timestamp"] = t
values["oauth_consumer_key"] = auth.ClientID
values["oauth_version"] = "1.0" //include here
//encode each key/value, sort key and build string
params := sortedParams(values)

In possession of the parameters you must produce the basis for the signature. At this point you make two more mistakes:

  1. You do not encode the request url and
  2. You do not encode the collected parameters.

In the documentation it says:

To Encode the HTTP method, base URL, and Parameter string into a single string:

  1. Convert the HTTP Method to uppercase and set the output string Equal to this value.
  2. Append the ː&' Character to the output string.
  3. Percent Find the URL and append it to the output string.
  4. Append the ː&' Character to the output string.
  5. Percent Encounter the Parameter string and append it to the output string.

Make sure to Percent Encode the Parameter string! The Signature base string should contain Exactly 2 ampersand ː&' characters.

So you should do:

//build signature base
baseString := fmt.Sprintf("POST&%s&%s", 
    url.QueryEscape(auth.RequestToken), //here is request token url
    url.QueryEscape(params))

Before making the request you make two more mistakes, you remove oauth_version of the initial parameters and does not encode the signature. And this step is done both in the inclusion of the signature in the parameters and in the header of the request. Behold:

The Signing key is Simply the Percent encoded Consumer secret, Followed by an ampersand Character ː&'[...]

That way you should do something like this:

values["oauth_signature"] = url.QueryEscape(signature)
header := fmt.Sprintf(`OAuth oauth_nonce="%s", ...`,
        url.QueryEscape(auth.ANonce), 
        url.QueryEscape(auth.Path), 
        url.QueryEscape(t), 
        url.QueryEscape(auth.ClientID), 
        url.QueryEscape(signature))

Removing these errors will solve your problem! Link to the references:

I tested your code and left it on playground for a better understanding.

I hope I’ve helped you!

  • Excellent guy the tips you gave me and for having made this detailed explanation, I don’t know how to thank you. Fortunately I had already managed to solve the problems a few days ago, after much break the head and read and re-read the API documentation, but I see that with these tips I still have things to improve in the middle code haha. Thank you very much even, I’ll leave the link here of my code in case you want to take a look tbm: github_twitterapi

  • I saw your code! You really still need to be careful with the documentation. Try to follow exactly what you ask for. Another suggestion is to create your own encounter. I’ve never tried it, but I’ve heard that there are cases where the url.Queryescape does not return the correct result. Finally, success!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.