Search code examples
swifttwitteroauth

Access Twitter using Swift


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:

  1. Consumer key/secret is wrong
  2. Make sure not to use API v1 (use 1.1)

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)
    }

Solution

  • Update 02-03-2015

    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