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