I'm using the Swifter library to access Twitter in my Swift iOS 8 app: https://github.com/mattdonnelly/Swifter. The problem is that I'm getting a 401 Not Authorized error from Twitter. I double checked any possible reasons for this:
With both these problems fixed (according to the Twitter docs), I'm still faced with this issue. I'm thinking it has something to do with how I authenticate. I'm trying to access a public feed without using ACAccount on the device.
Here is my code:
// MARK: Twitter
var swifter: Swifter
required init(coder aDecoder: NSCoder) {
self.swifter = Swifter(consumerKey: "KEY", consumerSecret: "SECRET")
super.init(coder: aDecoder)
}
func getTwitterTimeline() {
let failureHandler: ((NSError) -> Void) = {
error in
self.alertWithTitle("Error", message: error.localizedDescription)
}
self.swifter.getStatusesUserTimelineWithUserID("erhsannounce", count: 20, sinceID: nil, maxID: nil, trimUser: true, contributorDetails: false, includeEntities: true, success: {
(statuses: [JSONValue]?) in
if statuses != nil {
self.tweets = statuses!
}
}, failure: failureHandler)
}
func alertWithTitle(title: String, message: String) {
var alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
UPDATE: I've been working on the app, trying to achieve the functionality of using App only (not user based) auth and access token to read a public timeline.
I updated the code to use an access token and app only auth. Still not working though.
required init(coder aDecoder: NSCoder) {
let accessToken = SwifterCredential.OAuthAccessToken(key: "KEY", secret: "SECRET")
let credential = SwifterCredential(accessToken: accessToken)
self.swifter = Swifter(consumerKey: "cKEY", consumerSecret: "cSECRET", appOnly: true)
swifter.client.credential = credential
super.init(coder: aDecoder)
}
You need to authenticate with the server using App Only Authentication rather than passing in an OAuth Token.
As well as this, you are also not requesting status' with userId correctly as you are passing in the user's screen name. You need to obtain the user id with the username and then request for status'.
The complete working code is below:
required init(coder aDecoder: NSCoder) {
self.swifter = Swifter(consumerKey: "cKEY", consumerSecret: "cSECRET", appOnly: true)
super.init(coder: aDecoder)
self.swifter.authorizeAppOnlyWithSuccess({ (accessToken, response) -> Void in
self.twitterIsAuthenticated = true
}, failure: { (error) -> Void in
println("Error Authenticating: \(error.localizedDescription)")
})
}
@IBAction func getUserButtonPressed(sender: UIButton?) {
if (self.twitterIsAuthenticated) {
self.getTwitterUserWithName("erhsannounce")
} else {
// Authenticate twitter again.
}
}
func getTwitterUserWithName(userName: String) {
self.swifter.getUsersShowWithScreenName(userName, includeEntities: true, success: { (user) -> Void in
if let userDict = user {
if let userId = userDict["id_str"] {
self.getTwitterStatusWithUserId(userId.string!)
}
}
}, failure: failureHandler)
}
func getTwitterStatusWithUserId(idString: String) {
let failureHandler: ((error: NSError) -> Void) = {
error in
println("Error: \(error.localizedDescription)")
}
self.swifter.getStatusesUserTimelineWithUserID(idString, count: 20, sinceID: nil, maxID: nil, trimUser: true, contributorDetails: false, includeEntities: true, success: {
(statuses: [JSONValue]?) in
if statuses != nil {
self.tweets = statuses
}
}, failure: failureHandler)
}
It looks as though you are not Authenticating with the server.
From your code I can see you are using OAuth authentication initialisation but are failing to call the authenticate function.
swifter.authorizeWithCallbackURL(callbackURL, success: {
(accessToken: SwifterCredential.OAuthAccessToken?, response: NSURLResponse) in
// Handle success
},
failure: {
(error: NSError) in
// Handle Failure
})
Add this in and then call your getTwitterTimeline() afterwards.
I hope this helps