Revitalizing QtNetworkAuth for Modern OAuth2 Needs

Qt Network Authorization module was released 8 years ago in Qt 5.8. Since those days, the role and use of OAuth2 has grown significantly.  Today, many people use OAuth2 in one form or another; be it by clicking a “Sign-in with ...” button or allowing your favorite online drawing application to store the results on your cloud drive. 

Since the days of Qt 5.8, several new standards have also been introduced or gained significant traction. To address these, Qt 6.8 and the upcoming Qt 6.9 introduce several new features, bug fixes, and documentation improvements.

In this blog, I’d like to walk you through the highlights. 

Qt 6.8: Improving Quality, Security, and Documentation

The Qt 6.8 release was a focused effort on improving the Qt Network Authorization module based on user feedback. The bugs and suggestions on Qt Bug Report were systematically groomed and handled, resulting in many fixes and enhancements. Let's have a look at some notable changes.

Overview Documentation

Getting started with OAuth2 can be a bit daunting at first. To help with this, the module now has overview documentation that also serves as an introduction. You can find the  the documentation here (Qt 6.9 version). 

PKCE – Small but Important Security Enhancement

PKCE (Proof Key for Code Exchange)  is a security mechanism to mitigate the impact of authorization code hijacking and is particularly important for the authorization code grant (QOAuth2AuthorizationCodeFlow). PKCE is supported since Qt 6.8 and is enabled by default. If needed, the default behavior can be adjusted - see this enum and the related setter. 

Improved Redirection Support on Mobile Platforms

One of the challenges with native applications is the handling of OAuth2 redirection: when the authorization server completes the authorization, where should it redirect the user’s browser with the result? This is different from Web development, where - almost by definition - there is a reachable redirect URL to use. 

The main solution for native applications is to use a localhost web server, running on the same device as the application itself. This is what Qt Network Authorization has supported since the beginning. While the native application best practices RFC endorses this approach, there are also some drawbacks. Most notably, commercial authorization server providers may impose limitations on using such local host redirections. 

For this purpose, Qt 6.8 introduces a new reply-handler class, QOAuthUriSchemeReplyHandler. This new handler is capable of handling custom URL schemes (for example com.example.myapp://) and https.

These are supported on platforms where the operating system provides the necessary enablers, namely macOS, iOS, and Android. Using these can provide several benefits in terms of authorization server compliance, security, and user experience. Since the operating system knows that your application is registered to a specific scheme, it can put focus back on your application upon redirection. 

A note on supported platforms: there doesn't seem to be similar operating-system-level support on desktop Windows [0] or desktop Linux that wouldn’t involve modifying the system registry or using xdg-mime, making them difficult to support with Qt Network Auth library [1]. However, we’d be more than happy to hear from you if there is an approach we’ve missed so far.

[0] Seems more possible with UWP, but Qt 6 doesn't support UWP

[1] It should be possible (with some application-specific implementation and configuration) to use these mechanisms. One way could be to register an application/script for the scheme, and then catch and forward the redirect URL to this function in the actual application.

Qt 6.9: Feature Update

The focus of the upcoming Qt 6.9 is to add new features and make the system more convenient to use. 

Device Authorization Flow

Qt 6.9 introduces a new authorization flow known as Device Authorization Grant. This flow is a fairly recent RFC addition and quite widely supported. The flow is intended for devices that have limited input capabilities (or none). This includes devices like televisions, HMIs, and IoT devices. A big difference to the pre-existing Authorization Code Flow is that the user authorizes the access on some other device (phone, laptop, etc.) and redirection handling on the limited device is not needed.

A concrete example is a television screen that displays a QR code for the user to read with their phone. After reading the QR code, the user completes the authorization on that phone. After that, the television (or other device) gets the authorization results from the server.

oauth2-qt-io-qr-codeFor more details, see QOAuth2DeviceAuthorizationFlow.

OpenID Connect Token Acquisition

OAuth2 is mainly about authorization, which means giving the application permission to access resources. In contrast, OpenID Connect (OIDC) is about authentication, which means providing the application with a trustworthy identity of the user. OIDC is widely used as part of Single Sign On solutions, "Sign-in With ... buttons", and more. 

Technically, OIDC is a thin layer on top of OAuth2. Qt 6.9 adds the basic capability to acquire ID tokens that contain the user’s identity.  

It should be noted that the support for OIDC is not complete in Qt 6.9. Notably, at the moment Qt doesn’t provide ID token verification out of the box. However, we’ve documented ways to achieve this with 3rd party libraries with examples, see the overview documentation.  

Our main goal with this, in Qt 6.9, was to make it possible to use OIDC (albeit with limitations). If you have any OIDC-related feedback, please leave a comment here or in QTBUG-129383. 

Using Qt WebEngine as User Agent

With OAuth2 it is typical and often recommended to use the system browser for authorization. However, there are cases where using a user-agent embedded in the application can make sense (see the OAuth2 Browser Support documentation for details). Qt 6.9 makes it easier to use a user-agent other than the system browser, including Qt WebEngine. 

Token Refresh Convenience

Access tokens are typically only valid for an hour or less. If the authorization server provides a refresh token, it can be used to refresh the access token without user interaction. Qt 6.9 adds a new signal, QAbstractOAuth2::accessTokenAboutToExpire(), which is emitted as the token approaches expiration.  

You can fine-tune the emission time with the refreshLeadTime property. You can also enable automatic refresh by setting the autoRefresh property to true.

Separating Requested and Granted Scope

In an OAuth2 authorization request, a scope defines what resources the application wants to access. However, the requested scope and the actual granted scope can differ. The user may have authorized just partial access, or the authorization server’s policy may impose changes. 

Therefore, it’s important for the application to check what was actually granted and adjust the application behavior accordingly. To help with this, in Qt 6.9 there are two new properties: requestedScope and grantedScope. Prior to Qt 6.9, there is just a single scope property serving as a hybrid of the two roles, making it unclear which meaning the property has at any given time. 

Modifying Network Requests

OAuth2 involves multiple HTTP requests - for requesting, refreshing, and polling for tokens, as well as initiating the authorization in the case of the new Device Flow. While it was always possible to adjust request parameters in Qt Network Authorization, modifying the requests themselves was less straightforward.

The ability to do this can be very important if the authorization server expects, for example, specific HTTP headers to be present in the requests. These can be use-case specific headers, or simply additional authorization headers.  

Qt 6.9 addresses this need by allowing you to customize the network requests before they're sent - see  setNetworkRequestModifier() for details.

HTTPS Redirect Handler for Development Time

One requested feature introduced by Qt 6.9 is the ability use an https localhost reply-handler.  This should be useful for testing during development-time, and in some controlled and provisioned environments (see here for further details).

Manual Redirect URL Hostname Definition

When we use a localhost web server to handle the redirection from the authorization server, we need to decide on the hostname. Should it be localhost? Or 127.0.0.1? Or [::1]? This is a surprisingly multifaceted topic which I’ll not cover here, but you can see the details and related Qt 6.8 and Qt 6.9 changes here and here.  These changes aim to provide sensible defaults while still allowing you to override them if necessary.

Qt 6.9 now includes means to manually specify the hostname, irrespective of the underlying actual IP address. 

Final Thoughts

I’m personally quite happy with how much these two Qt releases (Qt 6.8 and Qt 6.9) take Qt’s OAuth2 story forward.  Each bug fix, documentation improvement, and new feature may seem small on its own, but together I hope they greatly improve the developer experience.  


Blog Topics:

Comments