I'm getting Bad Authentication data response in twitter friends/list API. I'm getting userid, screen name, authToken and authTokenSecret when login.

func loadFollowers(userid:String) {

    //let twapi = "https://api.twitter.com/1.1/followers/list.json?cursor=-1&user_id=\(session)&count=5000"
    let twapi = "https://api.twitter.com/1.1/friends/list.json?cursor=-1&user_id=\(userid)&count=10"
    let url2 = URL(string: twapi)!
    print(url2)
    URLSession.shared.dataTask(with: url2, completionHandler: { (data, response, error) in

    //UIApplication.shared.isNetworkActivityIndicatorVisible = false
        do {
            let userData = try JSONSerialization.jsonObject(with: data!, options:[])
            print(userData)
        } catch {
            NSLog("Account Information could not be loaded \(error)")
        }
    }).resume()
}

Output:

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

What are the required parameters to send in friends/list.json API. In this document they given all parameters are optional. https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-list


Because this friends/list api requires authentication in order to fetch friends list.Requires Authentication: Yes


In Swift 4.2, Xcode 10.1 and iOS 12.1

Finally i got the solution for this. Here first we need Authorisation then need to implement friends list api.

Pure Swift code is not available. But i implemented in pure swift.

If you want to get friends/list data from twitter you need to use two API's.

1) oauth2/token API

2) friends/list API

In oauth2/token api you can get access token, because you need access token for friends list. And you need user id, screen name.

But here you must remember one important point.

1) First use oauth2/token api for access token.

2) After getting access token use twitter login api for user id and screen name.

3) Now use friends/list api.

Here first if you use twitter login then oauth2/token api for access token, you can get like Bad Authentication data error. So you please follow above 3 steps in order.

1) Get access token code (oauth2/token api):

func getAccessToken() {

    //RFC encoding of ConsumerKey and ConsumerSecretKey
    let encodedConsumerKeyString:String = "sx5r...S9QRw".addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed)!
    let encodedConsumerSecretKeyString:String = "KpaSpSt.....tZVGhY".addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed)!
    print(encodedConsumerKeyString)
    print(encodedConsumerSecretKeyString)
    //Combine both encodedConsumerKeyString & encodedConsumerSecretKeyString with " : "
    let combinedString = encodedConsumerKeyString+":"+encodedConsumerSecretKeyString
    print(combinedString)
    //Base64 encoding
    let data = combinedString.data(using: .utf8)
    let encodingString = "Basic "+(data?.base64EncodedString())!
    print(encodingString)
    //Create URL request
    var request = URLRequest(url: URL(string: "https://api.twitter.com/oauth2/token")!)
    request.httpMethod = "POST"
    request.setValue(encodingString, forHTTPHeaderField: "Authorization")
    request.setValue("application/x-www-form-urlencoded;charset=UTF-8", forHTTPHeaderField: "Content-Type")
    let bodyData = "grant_type=client_credentials".data(using: .utf8)!
    request.setValue("\(bodyData.count)", forHTTPHeaderField: "Content-Length")
    request.httpBody = bodyData

    let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil else { // check for fundamental networking error
        print("error=\(String(describing: error))")
        return
        }

        let responseString = String(data: data, encoding: .utf8)
        let dictionary = data
        print("dictionary = \(dictionary)")
        print("responseString = \(String(describing: responseString!))")

        if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
            print("statusCode should be 200, but is \(httpStatus.statusCode)")
            print("response = \(String(describing: response))")
        }

        do {
            let response = try JSONSerialization.jsonObject(with: data, options: []) as! Dictionary<String, Any>
            print("Access Token response : \(response)")
            print(response["access_token"]!)
            self.accessToken = response["access_token"] as! String

            self.getStatusesUserTimeline(accessToken:self.accessToken)

        } catch let error as NSError {
            print(error)
        }
    }

    task.resume()
}

Output :

{"token_type":"bearer","access_token":"AAAAAAAAAAAAAAAAAAA............xqT3t8T"}

2) Login with twitter code

@IBAction func onClickTwitterSignin(_ sender: UIButton) {

    //Login and get session
    TWTRTwitter.sharedInstance().logIn { (session, error) in

        if (session != nil) {
            //Read data
            let name = session?.userName ?? ""
            print(name)
            print(session?.userID  ?? "")
            print(session?.authToken  ?? "")
            print(session?.authTokenSecret  ?? "")

             // self.loadFollowers(userid: session?.userID ?? "")

            //Get user email id
            let client = TWTRAPIClient.withCurrentUser()
            client.requestEmail { email, error in
                if (email != nil) {
                    let recivedEmailID = email ?? ""
                    print(recivedEmailID)
                } else {
                    print("error--: \(String(describing: error?.localizedDescription))");
                }
            }
            //Get user profile image url's and screen name
            let twitterClient = TWTRAPIClient(userID: session?.userID)
            twitterClient.loadUser(withID: session?.userID ?? "") { (user, error) in
                print(user?.profileImageURL ?? "")
                print(user?.profileImageLargeURL ?? "")
                print(user?.screenName ?? "")
            }



            let storyboard = self.storyboard?.instantiateViewController(withIdentifier: "SVC") as! SecondViewController
            self.navigationController?.pushViewController(storyboard, animated: true)
        } else {
            print("error: \(String(describing: error?.localizedDescription))");
        }
    }

}

Output:

Here you will get userName, userId, authtoken, authTokenSecret, screen name and email etc.

3) Now get friends list from friends/list api. Here you can get friends/list, users/lookup, followers/ids, followers/list api's data etc...

func getStatusesUserTimeline(accessToken:String) {

    let userId = "109....456"
    let twitterClient = TWTRAPIClient(userID: userId)
    twitterClient.loadUser(withID: userId) { (user, error) in
        if user != nil {
            //Get users timeline tweets
            var request = URLRequest(url: URL(string: "https://api.twitter.com/1.1/friends/list.json?screen_name=KS....80&count=10")!) //users/lookup, followers/ids, followers/list 
            request.httpMethod = "GET"
            request.setValue("Bearer "+accessToken, forHTTPHeaderField: "Authorization")

            let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil else { // check for fundamental networking error
                print("error=\(String(describing: error))")
                return
                }

      //                    let responseString = String(data: data, encoding: .utf8)
      //                    let dictionary = data
      //                    print("dictionary = \(dictionary)")
      //                    print("responseString = \(String(describing: responseString!))")

                if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
                    print("statusCode should be 200, but is \(httpStatus.statusCode)")
                    print("response = \(String(describing: response))")
                }

                do {
                    let response = try JSONSerialization.jsonObject(with: data, options: [])
                    print(response)

                } catch let error as NSError {
                    print(error)
                }
            }

            task.resume()

        }
    }

}

This code not available any where. I tried a lot for this code and i spent lot of time for this. Thank you.