OAuthSwift / OAuthSwiftAlamofire

Utility method to sign Alamofire request
MIT License
104 stars 38 forks source link

OAuthSwift adapter causing error 32 on Twitter client #4

Closed lanza closed 7 years ago

lanza commented 7 years ago
{"errors":[{"code":32,"message":"Could not authenticate you."}]}

is the exact error.

Given

 let params = ["status":tweet.urlEscaped]
 let url = "https://api.twitter.com/1.1/statuses/update.json

Running

oAuthSwift.client.post(url, parameters: params, headers: nil, success: { result in
    dump(result.1)
    print(String(data: result.0, encoding: .utf8)!)
}, failure: nil)

Works just fine.

let sessionManager = SessionManager.default
sessionManager.adapter = oAuthSwift.requestAdapte 
sessionManager.request(url, method: .post, parameters: params, headers: nil).responseJSON { response
    dump(response.request!)
    print(String(data: response.data!,encoding: .utf8)!) 
}

Fails.

I'm not quite well versed enough with OAuthSwift's workings to figure out exactly what is going on that causes the problem.

phimage commented 7 years ago

Could you post the two dump?

lanza commented 7 years ago

When using OAuthSwiftAlamofire:

▿ https://api.twitter.com/1.1/statuses/update.json
   ▿ url: Optional(https://api.twitter.com/1.1/statuses/update.json)
     ▿ some: https://api.twitter.com/1.1/statuses/update.json
       - _url: https://api.twitter.com/1.1/statuses/update.json #0
         - super: NSObject
   - cachePolicy: 0
   - timeoutInterval: 60.0
   - mainDocumentURL: nil
   - networkServiceType: __ObjC.NSURLRequest.NetworkServiceType
   - allowsCellularAccess: true
        ▿ httpMethod: Optional("POST")
     - some: "POST"
   ▿ allHTTPHeaderFields: Optional(["Authorization": "OAuth oauth_consumer_key=\"key\", oauth_nonce=\"504E0AD3\", oauth_signature=\"sig\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"1478119940\", oauth_token=\"209123799-JO4ZMbChhXeBQgCDBZLR9d5rhIrw0pTRZ2R3tUVY\", oauth_version=\"1.0\""])
     ▿ some: 1 key/value pair
       ▿ (2 elements)
         - .0: "Authorization"
         - .1: "OAuth oauth_consumer_key=\"key\", oauth_nonce=\"504E0AD3\", oauth_signature=\"sig\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"1478119940\", oauth_token=\"209123799-JO4ZMbChhXeBQgCDBZLR9d5rhIrw0pTRZ2R3tUVY\", oauth_version=\"1.0\""
   ▿ httpBody: Optional(11 bytes)
     ▿ some: 11 bytes
       - count: 11
       ▿ pointer: 0x0000610000221430
         - pointerValue: 106652630127664
       ▿ bytes: 11 elements
         - 115
         - 116
         - 97
         - 116
         - 117
         - 115
         - 61
         - 84
         - 101
         - 115
         - 116
   - httpBodyStream: nil
   - httpShouldHandleCookies: false
   - httpShouldUsePipelining: false
 {"errors":[{"code":32,"message":"Could not authenticate you."}]}`
lanza commented 7 years ago

OAuthSwift:

▿ Optional(https://api.twitter.com/1.1/statuses/update.json)
  ▿ some: https://api.twitter.com/1.1/statuses/update.json
    ▿ url: Optional(https://api.twitter.com/1.1/statuses/update.json)
      ▿ some: https://api.twitter.com/1.1/statuses/update.json
        - _url: https://api.twitter.com/1.1/statuses/update.json #0
          - super: NSObject
    - cachePolicy: 0
    - timeoutInterval: 60.0
    - mainDocumentURL: nil
    - networkServiceType: __ObjC.NSURLRequest.NetworkServiceType
    - allowsCellularAccess: true
    ▿ httpMethod: Optional("POST")
      - some: "POST"
    ▿ allHTTPHeaderFields: Optional(["Content-Type": "application/x-www-form-urlencoded; charset=utf-8", "Authorization": "OAuth oauth_consumer_key=\"key\", oauth_nonce=\"3FD1B3F5\", oauth_signature=\"sig\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"1478120278\", oauth_token=\"209123799-JO4ZMbChhXeBQgCDBZLR9d5rhIrw0pTRZ2R3tUVY\", oauth_version=\"1.0\""])
      ▿ some: 2 key/value pairs
        ▿ (2 elements)
          - .0: "Content-Type"
          - .1: "application/x-www-form-urlencoded; charset=utf-8"
        ▿ (2 elements)
          - .0: "Authorization"
          - .1: "OAuth oauth_consumer_key=\"key\", oauth_nonce=\"3FD1B3F5\", oauth_signature=\"key\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"1478120278\", oauth_token=\"209123799-JO4ZMbChhXeBQgCDBZLR9d5rhIrw0pTRZ2R3tUVY\", oauth_version=\"1.0\""
    ▿ httpBody: Optional(11 bytes)
      ▿ some: 11 bytes
        - count: 11
        ▿ pointer: 0x000060000003c270
          - pointerValue: 105553116512880
        ▿ bytes: 11 elements
          - 115
          - 116
          - 97
          - 116
          - 117
          - 115
          - 61
          - 66
          - 108
          - 97
          - 104
    - httpBodyStream: nil
    - httpShouldHandleCookies: false
    - httpShouldUsePipelining: false
lanza commented 7 years ago

This should be instantly reproducible as I eliminated any code that would be specific to my implementation. Just simply running the post request on the sample project should yield these same results if you'd like to play with it. I've reset my consumer key/secret pair multiple times, used different phones, used the simulator etc. I can't find anything that would be traceable to my implementation.

phimage commented 7 years ago

So the difference is

an header "Content-Type": "application/x-www-form-urlencoded; charset=utf-8" and a different body Could you edit your dumps comments and add OAuthSwift title or OAuthSwift+Alamofire

I don't know how alamofire manage your request. I will test if I have time

lanza commented 7 years ago

No, that header is in both of them. It's absence in that dump was the result of me tinkering with the code to see if that was the problem. If you run clean OAuthSwiftAlamofire & OAuthSwift those headers will be there in both.

Here's all the code you need to replicate this problem. The dump I'm using to print the request for OAuthSwift's request is right before resume() is called on the task within OAuthSwift.

    let baseURL = "https://api.twitter.com"
    var oauthURL: String { return baseURL + "/oauth" }
    let oauthConsumerKey = insert your key here
    let oauthConsumerSecret = insert your secret here
    var requestTokenURL: String { return oauthURL + "/request_token" }
    var authorizeURL: String { return oauthURL + "/authorize" }
    var accessTokenURL: String { return oauthURL + "/access_token" }
    var callbackURL: String { return "oauth-swift://oauth-callback/twitter" }
    let oAuthSwift = OAuth1Swift(consumerKey: oauthConsumerKey, consumerSecret: oauthConsumerSecret, requestTokenUrl: requestTokenURL, authorizeUrl: authorizeURL, accessTokenUrl: accessTokenURL)
    oAuthSwift.authorize(withCallbackURL: callbackURL, success: {_,_,_ in }, failure: nil)

    let url = "https://api.twitter.com/1.1/statuses/update.json"
    let params = ["status":"Hello"]
    let sessionManager = SessionManager.default
    sessionManager.adapter = oAuthSwift.requestAdapter
    sessionManager.request(url, method: .post, parameters: params, headers: nil).responseJSON { response in
        print("--------------------------------")
        dump(response.request!)
        print("--------------------------------")
        print(String(data: response.request!.httpBody!, encoding: .utf8)!)
        print("--------------------------------")
        print(String(data: response.data!,encoding: .utf8)!)
        print("--------------------------------")
    }
    //  oAuthSwift.client.post(url, parameters: params, headers: nil, success: { result in
    // }, failure: nil)
phimage commented 7 years ago

I think I jave found the problem With Alamofire the ["status":"Hello"] is not in oauth signature calculation because Alamofire already encode parameters into request body (using URLEncoding.encode(request, parameters))

There is no available decode method, and parameters is not passed to adapter...

So the only workaround is using URLEncoding.queryStringin request function sessionManager.request(url, method: .post, parameters: params, encoding: URLEncoding.queryString, headers: nil)

lanza commented 7 years ago

Great, that worked. Not exactly sure what that did as I don't know oauth and HTTP headers well enough, but it fixed the issue. Thanks!