Connecting your Qt application with Google Services using OAuth 2.0
January 25, 2017 by Jesús Fernández | Comments
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".
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.
Your application is registered, the dashboard is updated and you can set different options from this screen.
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".
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.
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!
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->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
Subscribe to our newsletter
Subscribe Newsletter
Try Qt 6.8 Now!
Download the latest release here: www.qt.io/download.
Qt 6.8 release focuses on technology trends like spatial computing & XR, complex data visualization in 2D & 3D, and ARM-based development for desktop.
We're Hiring
Check out all our open positions here and follow us on Instagram to see what it's like to be #QtPeople.
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.
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
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.
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).
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
Hi Mark!
I'm sorry, but we are still working on the documentation. But if you have any doubts don't hesitate to ask.
Hi Jes,
Do you any examples for in Python for pyqt version?
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
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
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
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.
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.
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.
Definitely! You can use QtNetworkAuth in this use case.
Sounds great!
An example of this use case would be appreciated.