Request failed: forbidden (403) for fabric twitterkit - ios

I'm trying to extract the members of a list using the TwitterKit API for iOS. As I understand, doing this will allow me to be "guest-authenticated" bypassing the need for my personal consumer and consumer-secret keys.
The code below attempts to get the members of a list using this REST endpoint
let client = TWTRAPIClient()
let endpoint = "https://api.twitter.com/1.1/lists/members.json"
let params = ["owner_screen_name" : "palafo", "slug" : "breakingnews"]
var clientError : NSError?
let request = client.URLRequestWithMethod("GET", URL: endpoint, parameters: params, error: &clientError)
client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
if connectionError != nil {
print("Error: \(connectionError)")
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
print("json: \(json)")
} catch let jsonError as NSError {
print("json error: \(jsonError.localizedDescription)")
}
}
Running that gives me this error:
Error Domain=TwitterAPIErrorDomain Code=220 "Request failed: forbidden (403)" UserInfo={NSLocalizedFailureReason=Twitter API error : Your credentials do not allow access to this resource (code 220), TWTRNetworkingStatusCode=403, NSErrorFailingURLKey=https://api.twitter.com/1.1/lists/members.json?owner_screen_name=palafo&slug=breakingnews, NSLocalizedDescription=Request failed: forbidden (403)})
If I change endpoint to instead get the statuses in that list using this other REST endpoint, I get a proper JSON response.
let endpoint = "https://api.twitter.com/1.1/lists/statuses.json"
Does this mean that Fabric's guest authentication does not allow me to get the members of a list?

I solved mine by using clientWithUserId instead of just initializing using just init.
NSString *userID = [Twitter sharedInstance].sessionStore.session.userID;
TWTRAPIClient *client = [[TWTRAPIClient alloc] initWithUserID:userID];

Related

swift:receive AWS id_token after sending facebook current token to AWS Cognito?

I want to send the facebook access token to the AWS Cognito and then receive an authorization token which can further be sent as an Authorization header in HTTP Put request.
However, I always get "unauthorized" response from the AWS end point.
When I try to print :
credentialsProvider.credentials().continueOnSuccessWith(executor: AWSExecutor.default()) { (task) -> Any? in
print(task.error)
return true
}
I get the following output:
Optional(Error Domain=com.amazonaws.AWSJSONBuilderErrorDomain Code=4 "serialized object is neither a valid json Object nor NSData object: {
IdentityPoolId = "******";
Logins = {
"graph.facebook.com" = "<FBSDKAccessToken: *******>";
};
}" UserInfo={NSLocalizedDescription=serialized object is neither a valid json Object nor NSData object: {
IdentityPoolId = "*****+*";
Logins = {
"graph.facebook.com" = "<FBSDKAccessToken: ******>";
};
}})
This is my code:
import AWSCognito
class FacebookProvider: NSObject, AWSIdentityProviderManager {
func logins() -> AWSTask<NSDictionary> {
if let token = FBSDKAccessToken.current() {
return AWSTask(result: [AWSIdentityProviderFacebook:token])
}
return AWSTask(error:NSError(domain: "Facebook Login", code: -1 , userInfo: ["Facebook" : "No current Facebook access token"]))
}
}
class API {
..............
public func putOrder(when fbLogin: Bool, _ order: Order, onSuccess: #escaping(JSON) -> Void,
on Failure: #escaping(Error)-> Void) {
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .EUCentral1 ,
identityPoolId:"*****", identityProviderManager:FacebookProvider())
let configuration = AWSServiceConfiguration(region: AWSRegionType.EUCentral1, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let url = "\(serverURL)\(API.loginOrderPath)"
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(url: NSURL(string: url)! as URL)
urlRequest.httpMethod = API.apiMethodPut
urlRequest.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
urlRequest.setValue("\(credentialsProvider.credentials())", forHTTPHeaderField: "Authorization")
do {
var json: JSON
json = ["companyId": order.companyId, "drinks": order.drinksId, "payment": order.payment, "tip": order.tip]
urlRequest.httpBody = try json.rawData()
let task = URLSession.shared.dataTask(with: urlRequest as URLRequest, completionHandler: {data, response, error -> Void in
if error != nil {
Failure(error!)
} else {
if let response = try? JSON(data: data!) {
onSuccess(response)
} else {
}
}
})
task.resume()
} catch _ {
}
}
}
Expected Result: JSON response from the AWS Server
Actual Result : unauthorised
The reason why your are receiving an unauthorized response from API Gateway is double :
credentialsProvider.credentials() is not serialized to JSON and can not be "as is" for the authorization headers.
Looks like you are trying to manually call API Gateway, by managing your self the low level details of the URL Request. I don't see code to add a signature to the request. All authenticated API Gateway requests must be signed (see https://docs.aws.amazon.com/apigateway/api-reference/making-http-requests/) and the Authorization header must contain the credentials used to compute the signature.
Managing the low level details of AWS Signature is not trivial. You should not write code to do that but use the AWS iOS SDK instead. In particular, if you're trying to call API Gateway with Cognito User Pool authorisation, have a look at this example : https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-generate-sdk-ios-swift.html.
The API Gateway console will generate the client side code required to run this example (see https://docs.aws.amazon.com/apigateway/latest/developerguide/genearte-ios-sdk-of-an-api.html)
This should remove a lot of boiler plate from your code, making it easier to read and to maintain.
The flow posted in your comment above, the iOS SDK will take care of 2/ 3/ and 4/ steps for you - automatically.

Load twitter posts from different users

Hi need to load twitter posts from different users.
I know how to load post from single user.
Perform request with search query FROM:<username>.
Do you know the way how to load posts from different users?
I tried something like this FROM:<username1>&&<username2> - but it doesn't work.
Any ideas?
You can make use of TwitterKit framework which is available in cocoapods GitHub - https://github.com/twitter/twitter-kit-ios/wiki/Access-Twitter's-REST-API
Cocoapods - https://cocoapods.org/pods/TwitterKit
Its twitter's own library, so you can always rely on that.
To load multiple tweets you need to use the below code
let client = TWTRAPIClient()
let tweetIDs = ["510908888888487103", "510908133777777104"]
client.loadTweets(withIDs: tweetIDs) { (tweets, error) -> Void in
// handle the response or error
}
If you want to to access other Twitter API endpoints, you can construct a request manually also like below
let client = TWTRAPIClient()
let statusesShowEndpoint = "https://api.twitter.com/1.1/statuses/show.json"
let params = ["id": "20"]
var clientError : NSError?
let request = client.urlRequest(withMethod: "GET", url: statusesShowEndpoint, parameters: params, error: &clientError)
client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
if connectionError != nil {
print("Error: \(connectionError)")
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: [])
print("json: \(json)")
} catch let jsonError as NSError {
print("json error: \(jsonError.localizedDescription)")
}
}
Hope this one helps.
I found an approach. I have to use Twitter iOS SDK and TWTRAPIClient for performing the request. https://api.twitter.com/1.1/statuses/user_timeline.json is endpoint for getting tweets of certain user with some username.
NSURLRequest *r = [[TWTRAPIClient new] URLRequestWithMethod:#"GET"
URL:#"https://api.twitter.com/1.1/statuses/user_timeline.json"
parameters:#{#"screen_name":name}
error:nil];
[[TWTRAPIClient new] sendTwitterRequest:r completion:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
if(data){
NSArray *tweets = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
[TWTRTweet tweetsWithJSONArray:tweets]
}
}];

Cannot find serverAuthCode for user using Google Client Library in Swift

So the problem that I cam experincrein is that I am trying to authenticate with Azure using client side auth with the Google API Client Library. I can get the refresh, access and ID tokens but the serverAuthCode is nil. I need the serverAuthCode in order to create the HTTP request to call the Azure authentication endpoint. The Azure SDK for iOS doesn't support client side authentication for Google (I've spoken to multiple engineers at Microsoft all of them have suggested not using their SDK for authentication because they don't support it). I don't know what to do besides try wrapping my head around AWS. Any Help?
Also, here is the piece of code
func viewController(vc : UIViewController, finishedWithAuth authResult : GTMOAuth2Authentication, error : NSError?) {
let azureGoogleServerAuthToken = authResult.userData.serverAuthCode
let azureGoogleIdToken = authResult.parameters["id_token"] as! String
let request = NSMutableURLRequest(URL: NSURL(string: "https://retip-ios.azurewebsites.net/.auth/login/google")!)
request.HTTPMethod = "POST"
let postString = "authorization_code=\(azureGoogleServerAuthToken)&id_token=\(azureGoogleIdToken)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
guard error == nil && data != nil else { // check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? NSHTTPURLResponse where httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()
It fails with an exception saying that it is finding nil every time. I have isolated it out to verify that this is what is causing the exception.
Thanks in advance.
After speaking with Azure support directly and working with them for over a week to find a solution, it appears as if their documentation is purposely vague on the issue because they do not support client side authentication with Google. Any solution would need to be custom built, meaning that this is not achievable through the Azure SDK.

Error code 403 when using guest authentication with TwitterKit iOS for getting user timeline

I am using Fabric's twitter kit for getting a username's tweets in my iOS application by making a request to the REST API endpoint "https://api.twitter.com/1.1/statuses/user_timeline.json"
I am have correctly set up my "consumer key" and "consumer secret key" as provided by the Fabric app in my AppDelegate and info.plist , but I repeatedly get the following error message -
Error: Optional(Error Domain=TwitterAPIErrorDomain Code=200 "Request
failed: forbidden (403)"
UserInfo={NSErrorFailingURLKey=https://api.twitter.com/1.1/guest/activate.json,
NSLocalizedDescription=Request failed: forbidden (403),
NSLocalizedFailureReason=Twitter API error : Forbidden. (code 200)})
My code is as under follows -
Twitter.sharedInstance().startWithConsumerKey(TWITTER_CONSUMER_KEY, consumerSecret: TWITTER_CONSUMER_KEY_SECRET)
Fabric.with([Twitter.sharedInstance()])
let userId = Twitter.sharedInstance().sessionStore.session()?.userID
let client = TWTRAPIClient.init(userID: userId)
let params = ["screen_name": twitterUsername, "count" : "10"]
var clientError : NSError?
let request = client.URLRequestWithMethod("GET", URL: TWITTER_TIMELINE_ENDPOINT, parameters: params, error: &clientError)
client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
if(connectionError == nil) {
self.twitterJson = self.nsdataToJSON(data!)!
self.constructTweetView(self.twitterJson)
}
else {
print("Error: \(connectionError)")
}
I am on the most recent version of TwitterKit(>2.0)
How can I go about resolving this ?
Thanks!
Add key in exception domains as shown in info.plist. Following fixed bug for me.

Why am I getting this error posting a request to the Uber Sandbox? NSURLErrorDomain error -1012

I can get product ID's from the products path but I get this error when trying to post a request to the sandbox schedule a ride. Trying to figure out what I'm doing wrong here. I have the bearer token added. I'm not sure what it wants or what is missing.
Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x7f8c13939ed0 {NSErrorFailingURLStringKey=https://sandbox-api.uber.com/v1/requests, NSUnderlyingError=0x7f8c0ac78410 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1012.)", NSErrorFailingURLKey=https://sandbox-api.uber.com/v1/requests}
func performPostUberRequest(url: NSURL, prodId: String) {
let params:[String: AnyObject] = [
"start_latitude" : "39.955715",
"start_longitude" : "-75.1680298",
"end_latitude" : "39.9542675",
"end_longitude" : "-75.1409609",
"product_id": prodId
]
var error: NSError?
var request: NSMutableURLRequest = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.addValue("Bearer \(uberToken)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: NSJSONWritingOptions.allZeros, error: &error)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()){
response, data, error in
if let error = error {
println(error)
} else if data != nil {
if let json: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as? NSDictionary {
println(json)
}
}
}
}
According to your comments: { code = unauthorized; message = "Missing scope: request"; }, you may miss the scope, which can be specified on your Uber developer dashboard where you registered the app and got the secret and client id and stuff.
If you have done this you should have added the necessary scopes into the parameters when you requested authorization code and access token through OAuth2.0 at the beginning.
In my imeplementation, the scopes were specified as the following:
[[NXOAuth2AccountStore sharedStore] setClientID:_clientID
secret:_clientSecret
scope:[NSSet setWithObjects:#"request", #"history_lite", #"profile", #"request_receipt", nil]
authorizationURL:[NSURL URLWithString:#"https://login.uber.com/oauth/authorize"]
tokenURL:[NSURL URLWithString:#"https://login.uber.com/oauth/token"]
redirectURL:[NSURL URLWithString:_redirectURL]
keyChainGroup:nil
forAccountType:_applicationName];

Resources