Twitter OAuth Authentication Routines in Lua, for Lightroom Plugins
More Lua code

Having added Twitter support to a bunch of my Lightroom plugins, I thought I'd go ahead and share the Lua routine that does the OAuth authentication.

The OAuth concept seems snazzy, but wow, the documentation is scattered and it was difficult to pin down exactly what was required. It would have been nice had they just shown a simple example all the way through, so perhaps this code can serve as that (at least for the subset of OAuth that Twitter requires).

This code depends on the SHA-1 and HMAC-SHA1 and JSON routines I've also released, but unlike that code, is also dependent on the environment provided to plugins by Lightroom.

Download TwitterAuthentication.lua
Version 6: Jan 13, 2011
(handles request-header auth, all https)

Warning: Version 6 is a huge update from the previous release, to handle big changes at Twitter. I've used this code in my plugins for years, but have not vetted that all the changes work outside my own personal build environment. I hope it does.

Here are some of the header docs, extracted from the file itself....

The code exposes two public functions:

   Twitter_AuthenticateNewCredentials()
   Twitter_SendTweet(credential_bundle, status_text)

The first leads the user through the procedure to grant your application permission to send tweets on their behalf. It returns a “credential bundle” (a Lua table) that can be cached locally (such as in the plugin preferences — see LrPrefs) and used for sending subsequent tweets forever, or until the user your application at Twitter unpermissions.

For example, if you have TWITTER_CREDENTIALS in your exportPresetFields list (with its default set to nil) and P is the local copy of the property table for the plugin (e.g. as passed to sectionsForBottomOfDialog, you might have:

  f:view {
     bind_to_object = P,
     place = 'overlapping',
     fill_horizontal = 1,

     f:static_text {
        fill_horizontal = 1,
        visible = LrBinding.keyIsNotNil 'TWITTER_CREDENTIALS',
        LrView.bind {
           key = 'TWITTER_CREDENTIALS',
           transform = function(credentials)
                          return LOC("$$$/xxx=Authenticated to Twitter as @^1",
                                     credentials.screen_name)
                       end
        },
     },
     f:push_button {
        visible = LrBinding.keyIsNil 'TWITTER_CREDENTIALS',
        enabled = LrBinding.keyIsNotNil '_authenticating_at_twitter',
        title   = "Authenticate at Twitter",
        action  = function()
                     LrFunctionContext.postAsyncTaskWithContext("authenticate at twitter",
                        function(context)
                           context:addFailureHandler(function(status, error)
                                                        LrDialogs.message("INTERNAL ERROR", error, "critical")
                                                     end)
                           context:addCleanupHandler(function()
                                                        _authenticating_at_twitter = nil
                                                     end)
                           _authenticating_at_twitter = true
                           P.TWITTER_CREDENTIALS = Twitter_AuthenticateNewCredentials()
                        end)
                  end
     }
  }

and then later during export...

  local P = exportContext.propertyTable

  if P.TWITTER_CREDENTIALS then
     local result = Twitter_SendTweet(P.TWITTER_CREDENTIALS,
                                      "I just did something with Lightroom!")
     if result == nil then
        -- user has revoked permission, so we'll uncache the credential bundle
        P.TWITTER_CREDENTIALS = nil
     end
  end

You will have to update the code to have it reference the specific Consumer Key and Consumer Secret granted to your application when you registered it at Twitter.


All 5 comments so far, oldest first...

Thank you Jeffrey – you have just saved what little hair I have remaining!

— comment by Mark J M Wilson on June 26th, 2009 at 2:33am JST (15 years, 6 months ago) comment permalink

I used this nice little plugin as start for my lua-oauth library. It helped me very well to get how all this works ;-).

You may find the lua-oauth plugin here: http://dracoblue.net/download/luaoauth-10/61/

– Jan

— comment by DracoBlue on September 17th, 2010 at 5:13am JST (14 years, 3 months ago) comment permalink

I’ve just been noodling around with this but it looks like it’s broken again, Jeffrey. Examining the headers coming back from the post I saw a 410 (gone away), did a little bit of digging and changed the post url to 1.1. That gave me a 400 ‘bad request’ in the status description. Much of anything else is beyond me. No real biggy, I was just messing but I thought you’d like to know.

Twitter completely changed how they go about things since I published this. I’ve gone ahead and put my current version (version 6) that has been working for a couple of years, but I’ve not checked it to see whether it actually works outside my personal build environment. If not, any changes should be minimal, so it should get you going. —Jeffrey

— comment by Kim on December 27th, 2013 at 7:22pm JST (11 years ago) comment permalink

Thanks Jeffrey, appreciated.

— comment by Kim on December 28th, 2013 at 5:10pm JST (10 years, 11 months ago) comment permalink

@Jeffrey: The new “Create Twitter Application” link is:

https://dev.twitter.com/apps/new

The original link I had still goes to a “create application” page, but so does the link you sent. I’m not sure the difference… —Jeffrey

— comment by DracoBlue on December 28th, 2013 at 11:19pm JST (10 years, 11 months ago) comment permalink
Leave a comment...


All comments are invisible to others until Jeffrey approves them.

Please mention what part of the world you're writing from, if you don't mind. It's always interesting to see where people are visiting from.

IMPORTANT:I'm mostly retired, so I don't check comments often anymore, sorry.


You can use basic HTML; be sure to close tags properly.

Subscribe without commenting