using twitter api with golang

0

I'm 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?

    
asked by anonymous 08.05.2018 / 14:39

1 answer

0

Your code has a variety of problems! The first is that you are 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 in the playground: link

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

  

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

     
  • Percent encode every key and value that will be signed.
  •   
  • Sort the list of parameters alphabetically 1 by encoded key [2].
  •   
  • For each key / value pair:
  •   
  • Append the encoded key to the output string.
  •   
  • Append the "=" character to the output string.
  •   
  • Append the encoded value to the output string.
  •   
  • If there are more key / value pairs remaining, append to '&'; 'character to   the output string.
  •   

    Note some important points in this step:

  • You should encode the key and value;
  • You must sort the key
  • This means that instead of using 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:

  • You do not encode the request url and
  • You do not encode the collected parameters.
  • In the documentation says:

      

    To encode the HTTP method, base URL, and parameter string into a   single string:

         
  • Convert the HTTP Method to uppercase and set the output string equal   to this value.
  •   
  • Append the '&'; 'character to the output string.
  •   
  • Percent encode the URL and append it to the output string.
  •   
  • Append the '&'; 'character to the output string.
  •   
  • Percent encode 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 errors, you remove% with% of the initial parameters and do not encode the signature. And this step is done both in the inclusion of the signature to the parameters and in the header of the request. See:

      

    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 references:

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

    I hope I have helped you!

        
    12.05.2018 / 02:23