Comments, Code and Qt. Some words about the wonderful world of software engineering

kQOAuth – OAuth library for Qt

kQOAuth is an OAuth 1.0 library written for Qt in C++. The goal of the library has been to provide easy integration for existing Qt applications utilizing Qt signals describing the OAuth process and also to provide a convenient approach to the OAuth user authentication itself if you are not interested in doing all the steps required yourself. kQOAuth also supports Twitter xAuth.

kQOAuth has support for retrieving the user authorization from the service provider's website. kQOAuth will open the user's web browser to the authorization page, give a local URL as the callback URL and setup a HTTP server on this address to listen for the reply from the service and then processes it.

If you don't want to use the convenience APIs but be in full control of the process, you can construct all the requests yourself when you also get all request reply parameters in the reply signals.

kQOAuth will run on all Qt 4.6 and Qt 4.7 supported platforms. It has been verified on Linux, MeeGo, Symbian (deployment as shared library still missing) and Mac OS X 10.6.

Source code

The source code is available on Gitorious at:
https://github.com/kypeli/kQOAuth

git clone git://github.com/kypeli/kQOAuth.git

To use kQOAuth in your application:

  1. Compile and install
    qmake; make; sudo make install
  2. In your .pro file
    CONFIG += kqoauth
    QT += network
  3. In your source code
    #include <QtKOAuth>

License

The library and the source code is licensed under the GNU Lesser General Public License (LGPL). For more information, visit http://www.gnu.org/licenses/lgpl.html

Main components

The two main classes of kQOAuth are KQOAuthManager and KQOAuthRequest. KQOAuthManager executes the request and keeps track of the authorization process, while KQOAuthRequest describes the next step of the process and takes care of formatting the headers for the request.

KQOAuthManager
Executes OAuth requests (KQOAuthRequest), parses the replies and emits Qt signals describing the process of the OAuth authentication.

KQOAuthManager will keep track of the state of the authorization process. This means that the provided convenience methods can be used to achieve the necessary steps in OAuth authentication without explicitely constructing each request.

KQOAuthManager can also take care of the user authorization to the protected resources. This is considered to be the must cumbersome step in OAuth authentication, so kQOAuth can take care of it for you. This is done by opening the user's web browser to the service provider's authorization page, setting up a local HTTP server that is called upon authorization is completed, and then processing the reply and emitting a signal with the result.

If you are interested in service provider's custom reply, be sure to connect to the signal requestReady(QByteArray networkReply). This signal will contain the raw response as sent from the service. You can then do whatever you want with it depending on the service.

KQOAuthRequest
KQOAuthRequest is given to KQOAuthManager to execute the requested OAuth request. It will also take care of parameter normalization, generating the necessary authorization header and most importantly it will generate the OAuth signature to the header.

kQOAuth gives also the possibility to be in total control of the authorization process if so desired. Internally KQOAuthManager uses KQOAuthRequests to construct the request that are being sent. Nothing prevents you from constructing all the necessary KQOAuthRequests yourself, giving them to KQOAuthManager and listening on requestReady(QByteArray networkReponse) signals when the request is completed. KQOAuthRequest will take care of request signing and header normalization for you anyway.

OAuth requests can be sent to the service as either HTTP POST or GET requests. This can be specified with the method setHttpMethod() giving KQOAuthRequest::GET or KQOAuthRequest::POST as parameter.

KQOAuthRequest_XAuth
KQOAuthRequest_XAuth encapsulates the functionality needed to do a xAuth authentication to Twitter. With xAuth you can do the authentication in one step. When initializing the request, specify the request type to be KQOAuthRequest::AccessToken and give the username and password with the method setXAuthLogin(). Then you can pass the request to KQOAuthManager to execute it. As a reply you will get the signal onAccessTokenReceived(QString accessToken, QString accessTokenSecret) that contain the necessary tokens to be used when accessing protected resources.

The TwitterCLI example application contains a complete functioning example demonstrating the xAuth authentication. Please note that xAuth is only one step and no other requests are needed in order to get access to protected resources.

Example

This is a command line utility for sending Twitter status updates. The application uses the convenience APIs to request access to protected resources and then constructs a request explicitly for sending the Twitter update (although there is a convenience method to do this directly, too).

#include &amp;amp;lt;QtKOAuth&amp;amp;gt;
#include &amp;amp;quot;twittercli.h&amp;amp;quot;

TwitterCLI::TwitterCLI() {
oauthRequest = new KQOAuthRequest;
oauthManager = new KQOAuthManager(this);
}

void TwitterCLI::getAccess() {
connect(oauthManager, SIGNAL(temporaryTokenReceived(QString,QString)),
this, SLOT(onTemporaryTokenReceived(QString, QString)));

connect(oauthManager, SIGNAL(authorizationReceived(QString,QString)),
this, SLOT( onAuthorizationReceived(QString, QString)));

connect(oauthManager, SIGNAL(accessTokenReceived(QString,QString)),
this, SLOT(onAccessTokenReceived(QString,QString)));

oauthRequest-&amp;amp;gt;initRequest(KQOAuthRequest::TemporaryCredentials,
QUrl(&amp;amp;quot;https://api.twitter.com/oauth/request_token&amp;amp;quot;));
oauthRequest-&amp;amp;gt;setConsumerKey(&amp;amp;quot;9PqhX2sX7DlmjNJ5j2Q&amp;amp;quot;);
oauthRequest-&amp;amp;gt;setConsumerSecretKey(&amp;amp;quot;1NYYhpIw1fXItywS9Bw6gGRmkRyF9zB54UXkTGcI8&amp;amp;quot;);

oauthManager-&amp;amp;gt;setHandleUserAuthorization(true);

oauthManager-&amp;amp;gt;executeRequest(oauthRequest);
}

void TwitterCLI::onTemporaryTokenReceived(QString token, QString tokenSecret)
{
QUrl userAuthURL(&amp;amp;quot;https://api.twitter.com/oauth/authorize&amp;amp;quot;);

if( oauthManager-&amp;amp;gt;lastError() == KQOAuthManager::NoError) {
qDebug() &amp;amp;lt;&amp;amp;lt; &amp;amp;quot;Opening authorization web site: &amp;amp;quot; &amp;amp;lt;&amp;amp;lt; userAuthURL;
oauthManager-&amp;amp;gt;getUserAuthorization(userAuthURL);
}

}

void TwitterCLI::onAuthorizationReceived(QString token, QString verifier) {
qDebug() &amp;amp;lt;&amp;amp;lt; &amp;amp;quot;User authorization received: &amp;amp;quot; &amp;amp;lt;&amp;amp;lt; token &amp;amp;lt;&amp;amp;lt; verifier;

oauthManager-&amp;amp;gt;getUserAccessTokens(
QUrl(&amp;amp;quot;https://api.twitter.com/oauth/access_token&amp;amp;quot;)
);
}

void TwitterCLI::onAccessTokenReceived(QString token, QString tokenSecret) {
qDebug() &amp;amp;lt;&amp;amp;lt; &amp;amp;quot;Access token received: &amp;amp;quot; &amp;amp;lt;&amp;amp;lt; token &amp;amp;lt;&amp;amp;lt; tokenSecret;

oauthSettings.setValue(&amp;amp;quot;oauth_token&amp;amp;quot;, token);
oauthSettings.setValue(&amp;amp;quot;oauth_token_secret&amp;amp;quot;, tokenSecret);

qDebug() &amp;amp;lt;&amp;amp;lt; &amp;amp;quot;Access tokens now stored. You can Tweet now!&amp;amp;quot;;

QCoreApplication::exit(0);
}

void TwitterCLI::onAuthorizedRequestDone() {
qDebug() &amp;amp;lt;&amp;amp;lt; &amp;amp;quot;Request sent to Twitter!&amp;amp;quot;;
QCoreApplication::exit(0);
}

void TwitterCLI::sendTweet(QString tweet) {

if( oauthSettings.value(&amp;amp;quot;oauth_token&amp;amp;quot;).toString().isEmpty() ||
oauthSettings.value(&amp;amp;quot;oauth_token_secret&amp;amp;quot;).toString().isEmpty()) {
qDebug() &amp;amp;lt;&amp;amp;lt; &amp;amp;quot;No access tokens. Aborting.&amp;amp;quot;;

return;
}

oauthRequest-&amp;amp;gt;initRequest(KQOAuthRequest::AuthorizedRequest,
QUrl(&amp;amp;quot;http://api.twitter.com/1/statuses/update.xml&amp;amp;quot;)
);
oauthRequest-&amp;amp;gt;setConsumerKey(&amp;amp;quot;9PqhX2sX7DlmjNJ5j2Q&amp;amp;quot;);
oauthRequest-&amp;amp;gt;setConsumerSecretKey(&amp;amp;quot;1NYYhpIw1fXItywS9Bw6gGRmkRyF9zB54UXkTGcI8&amp;amp;quot;);
oauthRequest-&amp;amp;gt;setToken(oauthSettings.value(&amp;amp;quot;oauth_token&amp;amp;quot;).toString());
oauthRequest-&amp;amp;gt;setTokenSecret(oauthSettings.value(&amp;amp;quot;oauth_token_secret&amp;amp;quot;).toString());

KQOAuthParameters params;
params.insert(&amp;amp;quot;status&amp;amp;quot;, tweet);
oauthRequest-&amp;amp;gt;setAdditionalParameters(params);

oauthManager-&amp;amp;gt;executeRequest(oauthRequest);

connect(oauthManager, SIGNAL(authorizedRequestReady()),
this, SLOT(onAuthorizedRequestReady()));
}

The complete source code for the application can be found at http://www.gitorious.org/kqoauth/kqoauth/blobs/master/examples/twittercli/twittercli.cpp

References

kQOAuth is already used by the following projects:

  • eCoach - eCoach is an application for recording and managing sport activities with Nokia N900.
  • OpenOffice.org

And many many more...

Changelog

  • 0.95: Critical bug fixes for POST requests and token in user authorization page URL.
  • 0.94: xAuth support was added.
  • 0.93: Added support to use custom QNetworkAccessManager
  • 0.92: Network service reply is emitted with signal requestReady(QByteArray) from KQOAuthManager.
  • 0.91: GET support was added

Roadmap

kQOAuth is still in development. Here are the items, in priority order, I still want to add to kQOAuth:

  • Support for OAuth 2.0 Native Application profile
  • More example application to demonstrate how kQOAuth interacts with different services (Hattrick, Vimeo and more...)

So OAuth 2.0 support is coming down the line. This, however, requires some refactoring of the code that we want to do before the support can be added.

Contact

In case you have any questions about kQOAuth or suggestions for improvements, please send me an email at johan@paul.fi or via Twitter @kypeli

  • slvr32

    … This is done by opening the user’s web browser…

    I’m not sure I’d call kQOauth a library, considering that overhead :/

    • http://www.johanpaul.com/blog/ Johan Paul

      I am sure you do understand that
      – OAuth 1.0 requires the user authentication to be done with a web browser and
      – You do not need to use this feature of the library if you don’t want. You can use kQOAuth just for request signing and sending and do the user authentication yourself however you want to do it.

      ?

      Or did I misunderstand your comment?

      • slvr32

        Sorry, I just caught the web browser detail with a quick glance, and thanks for the follow-up. I just ran across QOAuth the other day, but the kQOAuth news item @ maemo.org was the first I’d heard of kQOAuth, and I’m curious about QOAuth vs kQOauth differences.

        • http://www.johanpaul.com/blog/ Johan Paul

          About QOAuth I can tell you that I needed an OAuth library in Qt for my own project and looked at QOAuth. But there were some reasons I wanted to improve on it so I wrote my own lib. Anyone is free to judge by himself, but I think kQOAuth is more Qt-like and also kQOAuth uses signals-slots to be async. I also added the convenience APIs so it should be really easy to use the lib.

          Last but not least, QOAuth has a dependency to QCA project (which is a big library) and kQOAuth does not have any external dependencies.

  • Sam

    Hey

    It doesn’t compile for Symbian in Nokia Qt SDK. I keep getting error when i open root pro file and hit build.
    :: error: No rule to make target `NokiaQtSDKSymbianSDKepoc32releasearmv5LIBkqoauth.dso’, needed by `NokiaQtSDKSymbianSDKepoc32releasegcceudebtwittercli.exe’. Stop.

    Can you fix this please?

    • http://www.johanpaul.com/blog/ Johan Paul

      I am sorry, but I can’t. I don’t have experience in Symbian, nor a device to test with or even interest in Symbian. So I haven’t included any Symbian specific build rules (whatever may be needed).

      If you know how to fix this, I am more than happy to include a patch.

      • Sam

        I was able to compile it statically inside my application, but not as a library like it was ment to be in your .pro file. Didn’t test it on the device yet though :)

        • http://www.johanpaul.com/blog/ Johan Paul

          For Symbian? Cool!!

          Please share the results how it works on the device :)

        • Sam

          I will try tonight! btw. any estimate when can we expect support for GET requests also?

        • http://www.johanpaul.com/blog/ Johan Paul

          Real soon now :) I just need to get it done… not a big deal. Any suggestions on a service that uses GET requests so I can test this?

        • Sam

          I would need GET requests for HeiaHeia http://apiwiki.heiaheia.com/doku.php?id=apimethods , i dont know other services but im sure others using GET also exists.

        • http://www.johanpaul.com/blog/ Johan Paul

          Nice, thanks. Follow me on Twitter @kypeli and I will let you know when GET support is there. Hopefully tonight. Then you can tell me if it worked :)

        • Sam

          It works on symbian, at least i am able to get request tokens…Didnt try to make other requests yet.

        • Sam

          Did you test if the GET request actually works?:) I cant get it to work :(

        • http://www.johanpaul.com/blog/ Johan Paul

          I did test against an OAuth 1.0 test server at http://term.ie/oauth/example/ and it did echo back correctly the GET parameters I sent it. You can see the functional test and what I do at http://gitorious.org/kqoauth/kqoauth/blobs/master/tests/ft_kqoauth/ft_kqoauth.cpp#line250.

          But no, I didn’t test against any “real” service like HeiaHeia. Maybe I should do that at some point too.

        • Sam

          I dont know why but the GET request fails always and i get “Invalid OAuth request” reply. I sniffed the traffic with wireshark and for me it shows like it tries to pass oauth_callback for authenticated requests also? I thought its needed only for authorization. I might have done something wrong of course.Another difference between your test and my code getting the sports list from HeiaHeia is that you add those parameters? I dont have to add any parameters for request to heiaheia when i want to get sports list like it says on the api: http://apiwiki.heiaheia.com/doku.php?id=getsports

          Otherwise the library is very good! Much better than qoauth or oauth c library.. :) Thank you!

        • http://www.johanpaul.com/blog/ Johan Paul

          Thank you for your kind words! :)

          I would like to sort out your problem, but I would prefer doing it over email. So you could please send me your email address for example as a direct message on Twitter where you can find me as Kypeli. I will get back to you.

        • Sam

          i sent you message on IRC at freenode :)

        • http://www.johanpaul.com/blog/ Johan Paul

          …but looking at HeiaHeia Wiki and thinking of it, kQOAuth should provide an API to return the raw data the service replies with. So if I got it right, HeiaHeia replies with XML data, which kQOAuth really doesn’t handle right now.

          So expect a fix soon and some API that will get you the raw service data that is sent as the GET request reply from the service. I will announce it on Twitter when it’s done (if nobody is faster and wants to contribute ;))

        • http://www.johanpaul.com/blog/ Johan Paul

          Ok, I did some changed:

          – requestReady() signal now contains the raw server response as sent from the server. New signature is: requestReady(QByteArray). The signal is emitted after each request is done.

          Please let me know if this solved your issue.

  • http://www.johanpaul.com/blog/ Johan Paul

    I’ve added support for GET requests as well. You do them as before with POST requests, but specify the type of the request to be KQOAuthRequest::GET.

    Please also note that I refactored how service specific additional parameters are given;
    – Now both POST and GET requests use the same interface to specify the additional parameters for the request: through request->setAdditionalParameters(params)
    – setRequestBody() was removed as obsolete.

  • Tim Juntunen

    Under source code heading, point 2, please add to the .pro file:
    QT += network

    • http://www.johanpaul.com/blog/ Johan Paul

      Yes! Thank you, that’s maybe not automatically obvious :) Fixed.

  • D7p

    ive just cloned the git and am trying to build kQOAuth in QT creator but i get this error : error: symbol(s) not found for architecture x86_64

    Im using a Mac with osx 10.7.5 and QT 4.7.4

    any clue why or how to fix it

    • http://www.johanpaul.com/blog/ Johan Paul

      I haven’t been working on kQOAuth for a while now, but when I did, I did work on a Macbook Pro. But this was a few years ago, so not sure if something has changed for Qt on Mac.

      Do you get this error for other Qt apps too? Doesn’t sound kQOAuth specific in my opinion.

      • D7p

        this is kQOAuth specific error. Is kQOAuth still being actively developed.

        • http://www.johanpaul.com/blog/ Johan Paul

          Weird that it is kQOAuth specific. It just uses the same Qt libs as any other program.

          I don’t actively develop it, no. The source code it there, feel free to send pull requests.

        • D7p

          thats what i though. this is for a uni project so i dont have the time to fix upgrade issues unfortunately. do you know of any other qt libraries for OAuth (apart from QOAuth)