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

D
Dr. Diaz, Ph.D.
0 points
52 months ago

In light of Google's move to block OAuth requests from embedded web views, we have published an explanation on how to authenticate with Google SSO in Qt, with several pointers to get started, and troubleshooting the common problems in the official solutions.

?
dgl
-1 points
100 months ago

Good, really good. But it doesn't solve the problem of this kind of functions : How do I can make my app open source without at the same time revealing my google secret key.

OAuth is gret for webapps where all the code runs server side. But for a desktop app, all the elements must be in client side, including secret keys ... (This is the same problem for API Keys).

Thanks for this great job anyway

?
Vincent
-1 points
100 months ago

Hi dgl:

You expect your users use the google account you created? I think users should have their own account. When users use your app, they should login to their own account.

?
Jes&#250;s Fern&#225;ndez
-1 points
100 months ago

I agree :(. And I don't have a solution for this.
It is also a problem in open source web apps. In a desktop application, you can publish the code without client credentials and embed it in the binary version (it's also possible to get it disassembling your binary).

?
Mark
-1 points
99 months ago

Is there any available documentation for QOAuth2AuthorizationCodeFlow class API?

http://doc.qt.io/qt-5/qtnet... does not seem to have any reference to it.

How can we explore in details all the available APIs?

Great job, thanks,
Mark

?
Jes&#250;s Fern&#225;ndez
-1 points
99 months ago

Hi Mark!

I'm sorry, but we are still working on the documentation. But if you have any doubts don't hesitate to ask.

Prudhvi Raj Raavi
-1 points
38 months ago

Hi Jes,

Do you any examples for in Python for pyqt version?

?
pyrosbrother
-1 points
99 months ago

Do you plan to publish a sample program to help us to test the Google Services using Qt ?
Actually I do not succeed with your article but I want to dig this point which I find very interesting.
This piece of software could help other Qt users like me.

Hope you could help us more to find the way.

Regards

?
Jes&#250;s Fern&#225;ndez
-1 points
99 months ago

Hi!

I'm planning to write the following part of this post. You can also check the example of how to use OAuth 2 in the path: qt5/qtnetworkauth/examples/oauth/redditclient

?
pyrosbrother
-1 points
99 months ago

Hello,

Thank you for your answer. It show me the way to get a valid answer from Google API.
That's a real improvement and I could test it also on iOS with success too ! That's really a good good job for us.

Regards

?
dev-sst
-1 points
99 months ago

Hi,
will QtNetworkAuth make it possible to create a Qt based server without bothering with user registration?
Most users generally don't want to register with username/password/email for every tiny service around.

If the server can provide an e.g. OpenID based login, then the user can just utilize the server after authenticating with his trusted OpenID provider.
Also the complexity of user management in the server is reduced to setting default permissions (or roles or w/e) instead of registration->email verification->permissions.

?
Jes&#250;s Fern&#225;ndez
-1 points
99 months ago

Hi!

QtNetworkAuth will help you how to get the access tokens from different authentication providers. You could write your HTTP server and handle authentication with QtNetworkAuth in the same way you use it for a desktop app.

But QtNetworkAuth won't work as an "Authorization server," check the OAuth 2.0 documentation for more details.

?
dev-sst
-1 points
99 months ago

There seems to be a misunderstanding,
the idea is to authenticate a client similar to web services where you can login with your google account instead of creating a service specific account (e.g. in gerrit you could login via OpenID).

My example would be a Qt based client that connects to a Qt based server where the server only needs to check the access token of some extern authorization server.
For example the client connects to the server providing a google account (via OpenID Connect or whatever) instead of implementing user registration in the server.

?
Jes&#250;s Fern&#225;ndez
0 points
99 months ago

Definitely! You can use QtNetworkAuth in this use case.

?
dev-sst
0 points
99 months ago

Sounds great!
An example of this use case would be appreciated.