|
| 1 | +# OAuth 1.0 and 2.0 for Qt |
| 2 | + |
| 3 | +This library encapsulates the OAuth 1.0 and 2.0 client authentication flows, and the sending of authenticated HTTP requests. |
| 4 | + |
| 5 | +The primary target is Qt Quick applications on embedded devices. |
| 6 | + |
| 7 | +Notes to contributors: |
| 8 | + |
| 9 | + * Please follow the coding style of the existing source |
| 10 | + * Code contributions are released under Simplified BSD License, as specified in LICENSE. Do not contribute if this license does not suit your code |
| 11 | + |
| 12 | +## Classes |
| 13 | + |
| 14 | +Class | Header | Purpose |
| 15 | +:-- | :-- | :-- |
| 16 | +O0AbstractStore | o0abstractstore.h | Base class of persistent stores |
| 17 | +O0BaseAuth | o0baseauth.h | Base class of OAuth authenticators |
| 18 | +O0SettingsStore | o0settingsstore.h | QSettings-based persistent store |
| 19 | +o0keyChainStore | o0keychainstore.h | Settings stored through the system keychain [keychain](https://github.com/frankosterfeld/qtkeychain) |
| 20 | +O0SimpleCrypt | o0simplecrypt.h | Simple encryption and decryption by Andre Somers |
| 21 | +O1 | o1.h | Generic OAuth 1.0 authenticator |
| 22 | +O1Dropbox | o1dropbox.h | Dropbox OAuth specialization |
| 23 | +O1Flickr | o1flickr.h | Flickr OAuth specialization |
| 24 | +O1Freshbooks | o1freshbooks.h | Freshbooks OAuth specialization |
| 25 | +O1Requestor | o1requestor.h | Makes authenticated OAuth 1.0 requests: GET, POST or PUT, handles timeouts |
| 26 | +O1RequestParameter | o1.h | An extra request parameter participating in request signing |
| 27 | +O1Twitter | o1twitter.h | Twitter OAuth specialization |
| 28 | +O2 | o2.h | Generic OAuth 2.0 authenticator |
| 29 | +O2Facebook | o2facebook.h | Facebook OAuth specialization |
| 30 | +O2Gft | o2gft.h | Google Fusion Tables OAuth specialization |
| 31 | +O2Google | o2google.h | Google Oauth specialization [scopes](https://developers.google.com/identity/protocols/googlescopes) |
| 32 | +O2Hubic | o2hubic.h | Hubic OAuth specialization |
| 33 | +O2Reply | o2reply.h | A network request/reply that can time out |
| 34 | +O2ReplyServer | o2replyserver.h | HTTP server to process authentication responses |
| 35 | +O2Requestor | o2requestor.h | Makes authenticated OAuth 2.0 requests (GET, POST or PUT), handles timeouts and token expiry |
| 36 | +O2Skydrive | o2skydrive.h | OneDrive OAuth specialization |
| 37 | +O2SurveyMonkey | o2surveymonkey.h | SurveyMonkey OAuth specialization |
| 38 | +OXTwitter | oxtwitter.h | Twitter XAuth specialization |
| 39 | + |
| 40 | +## Installation |
| 41 | + |
| 42 | +Clone the Github repository, then add all files in *src* to your Qt project, by including *src/src.pri*. |
| 43 | + |
| 44 | +## Basic Usage |
| 45 | + |
| 46 | +This example assumes a hypothetical Twitter client that will post tweets. Twitter is using OAuth 1.0. |
| 47 | + |
| 48 | +### Setup |
| 49 | + |
| 50 | +Include the required header files, and have some member variables that will be used for authentication and sending requests: |
| 51 | + |
| 52 | + #include "o1twitter.h" |
| 53 | + #include "o1requestor.h" |
| 54 | + O1Twitter *o1; |
| 55 | + |
| 56 | +### Initialization |
| 57 | + |
| 58 | +Instantiate one of the authenticator classes, like O1Twitter, set your application ID and application secret, and install the signal handlers: |
| 59 | + |
| 60 | + o1 = new O1Twitter(this); |
| 61 | + o1->setClientId(MY_CLIENT_ID); |
| 62 | + o1->setClientSecret(MY_CLIENT_SECRET); |
| 63 | + connect(o1, SIGNAL(linkedChanged()), this, SLOT(onLinkedChanged())); |
| 64 | + connect(o1, SIGNAL(linkingFailed()), this, SLOT(onLinkingFailed())); |
| 65 | + connect(o1, SIGNAL(linkingSucceeded()), this, SLOT(onLinkingSucceeded())); |
| 66 | + connect(o1, SIGNAL(openBrowser(QUrl)), this, SLOT(onOpenBrowser(QUrl))); |
| 67 | + connect(o1, SIGNAL(closeBrowser()), this, SLOT(onCloseBrowser())); |
| 68 | + |
| 69 | +**Note:** For browserless Twitter authentication, you can use the OXTwitter specialized class which can do Twitter XAuth. You will need to additionally provide your Twitter login credentials (username & password) before calling *link()*. |
| 70 | + |
| 71 | +### Handling Signals |
| 72 | + |
| 73 | +O2 is an asynchronous library. It will send signals at various stages of authentication and request processing. |
| 74 | + |
| 75 | +To handle these signals, implement the following slots in your code: |
| 76 | + |
| 77 | + void onLinkedChanged() { |
| 78 | + // Linking (login) state has changed. |
| 79 | + // Use o1->linked() to get the actual state |
| 80 | + } |
| 81 | + |
| 82 | + void onLinkingFailed() { |
| 83 | + // Login has failed |
| 84 | + } |
| 85 | + |
| 86 | + void onLinkingSucceeded() { |
| 87 | + // Login has succeeded |
| 88 | + } |
| 89 | + |
| 90 | + void onOpenBrowser(const QUrl *url) { |
| 91 | + // Open a web browser or a web view with the given URL. |
| 92 | + // The user will interact with this browser window to |
| 93 | + // enter login name, password, and authorize your application |
| 94 | + // to access the Twitter account |
| 95 | + } |
| 96 | + |
| 97 | + void onCloseBrowser() { |
| 98 | + // Close the browser window opened in openBrowser() |
| 99 | + } |
| 100 | + |
| 101 | +### Logging In |
| 102 | + |
| 103 | +To log in (e.g. to link your application to the OAuth service), call the link() method: |
| 104 | + |
| 105 | + o1->link(); |
| 106 | + |
| 107 | +This initiates the authentication sequence. Your signal handlers above will be called at various stages. Lastly, if linking succeeds, onLinkingSucceeded() will be called. |
| 108 | + |
| 109 | +### Logging Out |
| 110 | + |
| 111 | +To log out, call the unlink() method: |
| 112 | + |
| 113 | + o1->unlink(); |
| 114 | + |
| 115 | +Logging out always succeeds, and requires no user interaction. |
| 116 | + |
| 117 | +### Sending Authenticated Requests |
| 118 | + |
| 119 | +Once linked, you can start sending authenticated requests to the service. We start with a simple example of sending a text-only tweet or as it's known in Twitter docs, a 'status update'. |
| 120 | + |
| 121 | +First we need a Qt network manager and an O1 requestor object: |
| 122 | + |
| 123 | + QNetworkAccessManager *manager = new QNetworkAccessManager(this); |
| 124 | + O1Requestor *requestor = new O1Requestor(manager, o1, this); |
| 125 | + |
| 126 | +Next, create parameters for posting the update: |
| 127 | + |
| 128 | + QByteArray paramName("status"); |
| 129 | + QByteArray tweetText("My first tweet!"); |
| 130 | + |
| 131 | + QList<O1RequestParameter> requestParams = QList<O1RequestParameter>(); |
| 132 | + requestParams << O1RequestParameter(paramName, tweetText); |
| 133 | + |
| 134 | + QByteArray postData = O1::createQueryParams(requestParams); |
| 135 | + |
| 136 | + // Using Twitter's REST API ver 1.1 |
| 137 | + QUrl url = QUrl("https://api.twitter.com/1.1/statuses/update.json"); |
| 138 | + |
| 139 | + QNetworkRequest request(url); |
| 140 | + request.setHeader(QNetworkRequest::ContentTypeHeader, O2_MIME_TYPE_XFORM); |
| 141 | + |
| 142 | +Finally we authenticate and send the request using the O1 requestor object: |
| 143 | + |
| 144 | + QNetworkReply *reply = requestor->post(request, reqestParams, postData); |
| 145 | + |
| 146 | +Continuing with the example, we will now send a tweet containing an image as well as a message. |
| 147 | + |
| 148 | +We create an HTTP request containing the image and the message, in the format specified by Twitter: |
| 149 | + |
| 150 | + QString imagePath("/tmp/image.jpg"); |
| 151 | + QString message("My tweet with an image!"); |
| 152 | + |
| 153 | + QFileInfo fileInfo(imagePath); |
| 154 | + QFile file(imagePath); |
| 155 | + file.open(QIODevice::ReadOnly); |
| 156 | + |
| 157 | + QString boundary("7d44e178b0439"); |
| 158 | + QByteArray data(QString("--" + boundary + "\r\n").toAscii()); |
| 159 | + data += "Content-Disposition: form-data; name=\"media[]\"; filename=\"" + fileInfo.fileName() + "\"\r\n"; |
| 160 | + data += "Content-Transfer-Encoding: binary\r\n"; |
| 161 | + data += "Content-Type: application/octet-stream\r\n\r\n"; |
| 162 | + data += file.readAll(); |
| 163 | + file.close(); |
| 164 | + data += QString("\r\n--") + boundary + "\r\n"; |
| 165 | + data += "Content-Disposition: form-data; name=\"status\"\r\n"; |
| 166 | + data += "Content-Transfer-Encoding: binary\r\n"; |
| 167 | + data += "Content-Type: text/plain; charset=utf-8\r\n\r\n"; |
| 168 | + data += message.toUtf8(); |
| 169 | + data += QString("\r\n--") + boundary + "--\r\n"; |
| 170 | + |
| 171 | + QNetworkRequest request; |
| 172 | + // Using Twitter's REST API ver 1.1 |
| 173 | + request.setUrl(QUrl("https://api.twitter.com/1.1/statuses/update_with_media.json")); |
| 174 | + request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + boundary); |
| 175 | + request.setHeader(QNetworkRequest::ContentLengthHeader, data.length()); |
| 176 | + |
| 177 | + QNetworkReply *reply = requestor->post(request, QList<O1RequestParameter>(), data); |
| 178 | + |
| 179 | +That's it. Tweets using the O2 library! |
| 180 | + |
| 181 | +### Storing OAuth Tokens |
| 182 | + |
| 183 | +O2 provides simple storage classes for writing OAuth tokens in a peristent location. Currently, a QSettings based backing store **O2SettingsStore** is provided in O2. O2SettingsStore keeps all token values in an encrypted form. You have to specify the encryption key to use while constructing the object: |
| 184 | + |
| 185 | + O0SettingsStore settings = new O0SettingsStore("myencryptionkey"); |
| 186 | + // Set the store before starting OAuth, i.e before calling link() |
| 187 | + o1->setStore(settings); |
| 188 | + ... |
| 189 | + |
| 190 | +You can also create it with your customized QSettings object. O2SettingsStore will then use that QSettings object for storing the tokens: |
| 191 | + |
| 192 | + O0SettingsStore settings = new O0SettingsStore(mySettingsObject, "myencryptionkey"); |
| 193 | + |
| 194 | +Once set, O2SettingsStore takes ownership of the QSettings object. |
| 195 | + |
| 196 | +**Note:** If you do not specify a storage object to use, O2 will create one by default (which QSettings based), and use it. In such a case, a default encryption key is used for encrypting the data. |
| 197 | + |
| 198 | +### Extra OAuth Tokens |
| 199 | + |
| 200 | +Some OAuth service providers provide additional information in the access token response. Eg: Twitter returns 2 additional tokens in it's access token response - *screen_name* and *user_id*. |
| 201 | + |
| 202 | +O2 provides all such tokens via the property - *extraTokens*. You can query this property after a successful OAuth exchange, i.e after the *linkingSucceeded()* signal has been emitted. |
| 203 | + |
| 204 | +## More Examples |
| 205 | + |
| 206 | +The *examples* folder contains complete example applications: |
| 207 | + |
| 208 | +Name | Description |
| 209 | +:-- | :-- |
| 210 | +facebookdemo | Command line application authenticating with Facebook |
| 211 | +sialis | QT Quick Twitter client using OAuth 1 |
| 212 | +twitterdemo | Command line client for authenticating with Twitter and posting status updates. Uses OAuth 1 or Twitter XAuth |
| 213 | + |
| 214 | +## Change Log |
| 215 | + |
| 216 | +### 0.1.0 |
| 217 | + |
| 218 | +* Persist the extra tokens, too |
| 219 | +* Add Qt Quick Twitter client example |
| 220 | + |
| 221 | + |
| 222 | + |
| 223 | + |
0 commit comments