Connecting your Qt application with Google Services using OAuth 2.0

With the Qt 5.8 release, we have added QtNetworkAuth as a Technology Preview module. It is focused on helping developers with this auth******** madness. Currently, it supports OAuth1 and OAuth2. In the future, it will feature more authorization methods.

This post is a first glance of the OAuth2 support in Qt, it covers how to use Google to authorize an application. Your application will be able to show the typical log-in/authorize app screen, just like a web application (NOTE: A browser or a webview is needed):

.

The IETF defines OAuth 2.0 as:

The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service, either on behalf of a resource owner by orchestrating an approval interaction between the resource owner and the HTTP service, or by allowing the third-party application to obtain access on its own behalf.

OAuth authorization is also a requirement to use the Google APIs and access user information stored in Google Services like Gmail, Drive, Youtube, Maps, and others.

If you are interested in how to create an application using OAuth2, please continue reading.

Register your new project

Before start writing code, you need to register a new project in the service provider. This step is necessary because you have to request the client credentials to identify your application. The following steps are based on Google API Console but they are similar to other providers.

Creating new project

To start the project registration, access Google API Console, then, press "Create Project".

spectacle-t26843

A “New Project” dialog appears. Type the name of your project and click the "Create" button. Now you are ready to manage your new project.

spectacle-g26843

Your application is registered, the dashboard is updated and you can set different options from this screen.

spectacle-a26843

Creating the credentials

You have to get credentials to identify the application. Go to the "Credentials" section in the dashboard and press the "Create credentials" button. You need to choose which type of credentials you need. Choose "OAuth client ID".

spectacle-x26843

In the next screen, you can configure a "consent screen" with your Email address, product name, homepage, product logo, ... Fill it with your data and press the "Save" button.

Go back to the previous "Create client ID" screen to choose the "Application type". Different options are available here; you need to choose "Web application". Give it a name.

spectacle-r26843

Under "Restrictions" there is an important field: the "Authorized redirect URIs".

If the user chooses to allow your application to manage his data. The application has to receive an "access token" to be used during authenticated calls. The "access token" can be received in several ways, but the most common way is to receive a call to your web server with the "access token". In web applications, a server path to handle the notification is enough. A desktop application need to fake it using a local browser.

Add a URI accessible by your Internet browser including the port if you are using a different one than 80. When the application is running, a basic HTTP server will receive information from the browser.

Most of the times you need to use a URI like: "http://localhost:8080/cb".

NOTE: The path "/cb" is mandatory in the current QOAuthHttpServerReplyHandler implementation.

NOTE: You can configure different URIs. In this example, a single URI is assumed.

End the process by pressing the "Create" button and you will see a new credential in the list of credentials with an "Edit", "Delete" and "Download" buttons at the right. Click the download button and... Finally, you get a JSON file ready to parse!

spectacle-m27458

In the screenshot above you can see some new URIs and the client_id and the client_secret. There is no need to use the JSON file, you can hardcode this information directly in your application.

Writing the Google API Wrapper code

I will omit the part of defining the class and show the relevant code.

In your code create a QOAuth2AuthorizationCodeFlow object:

auto google = new QOAuth2AuthorizationCodeFlow;

Configure the scope you need to access from the application. The scope is the desired permissions the application needs. It can be a single string or a list of strings separated by a character defined by the provider. (Google uses the space character as separator).

NOTE: The scopes are different depending on the provider. To get a list of scopes supported by Google APIs click here.

Let's use the scope to access the user email:

google->setScope("email");

Connect the authorizeWithBrowser signal to the QDesktopServices::openUrl function to open an external browser to complete the authorization.

connect(google, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser,
    &QDesktopServices::openUrl);

Parse the downloaded JSON to get the settings and information needed. document is an object of type QJsonDocument with the file loaded.

const auto object = document.object();
const auto settingsObject = object["web"].toObject();
const QUrl authUri(settingsObject["auth_uri"].toString());
const auto clientId = settingsObject["client_id"].toString();
const QUrl tokenUri(settingsObject["token_uri"].toString());
const auto clientSecret(settingsObject["client_secret"].toString());
const auto redirectUris = settingsObject["redirect_uris"].toArray();
const QUrl redirectUri(redirectUris[0].toString()); // Get the first URI
const auto port = static_cast<quint16>(redirectUri.port()); // Get the port

 

After parsing the file configure the google object.

google->setAuthorizationUrl(authUri);
google->setClientIdentifier(clientId);
google->setAccessTokenUrl(tokenUri);
google->setClientIdentifierSharedKey(clientSecret);

Create and assign a QOAuthHttpServerReplyHandler as the reply handler of the QOAuth2AuthorizationCodeFlow object. A reply handler is an object that handles the answers from the server and gets the tokens as the result of the authorization process.

auto replyHandler = new QOAuthHttpServerReplyHandler(port, this);
google->setReplyHandler(replyHandler);

The grant function will start the authorization process.

google->grant();

If everything was OK, you should receive a QOAuth2AuthorizationCodeFlow::granted signal and start sending authorized requests.

You can try sending a request using https://www.googleapis.com/plus/v1/people/me

auto reply = google-&gt;get(QUrl("https://www.googleapis.com/plus/v1/people/me"));

 

It will give you a QNetworkReply and when QNetworkReply::finished is emited you will be able to read the data.

To be continued...


Blog Topics:

Comments