OAuth2 Authorization stage relies on a user-agent, which is typically either the system browser or an embedded user-agent such as Qt WebEngine.
The choice between system browser and an embedded user-agent depends on several factors. The following describes few main considerations:
https or custom uri-scheme redirect URLs (see QOAuthUriSchemeReplyHandler). With these platforms an embedded user-agent can be used to work around the limitation.Given these considerations, using the system browser is recommended for native applications. But as hinted by some of the points above, there may still be valid use cases for using an embedded user-agent.
Using the system browser requires opening it and navigating to the authorization URL configured by the application. Typical usage looks as follows:
connect(&m_oauth, &QAbstractOAuth::authorizeWithBrowser, this, &QDesktopServices::openUrl);
The code connects QAbstractOAuth::authorizeWithBrowser signal and QDesktopServices::openUrl slot. This opens the system browser, where user performs the necessary authentication and authorization. The application or Qt libraries have no direct control over the system browser, and it typically remains open once the authorization is concluded.
For further details and supported redirect URL schemes with system browser please see OAuth 2.0 Overview, QOAuthHttpServerReplyHandler, and QOAuthUriSchemeReplyHandler.
Qt WebEngine provides a web browser engine to embed web content directly into the Qt application.
Along with core control features, it comes with easy-to-use views for both QtWidgets and QtQuick applications. These views can be used as the user-agent in an OAuth2 authorization. Qt WebEngine is a large and versatile module, and the focus of this documentation is on using it with OAuth2 authorization.
There are many ways to embed the Qt WebEngine as part of the application. From practical point of view the main considerations are:
Qt WebEngine can be used with both QtQuick and QtWidgets applications for OAuth2 authorization. The main difference is in how set up the few necessary enablers.
Following illustrates a simplified QWebEngineView (QtWidget) setup. Error handling and any potential Qt WebEngine configuration is omitted for brevity.
Assuming following widgets:
QWebEngineView *webView = nullptr; QMainWindow mainWindow;
Instead of opening the system browser, we use the QWebEngineView to perform the authorization:
connect(&m_oauth, &QAbstractOAuth::authorizeWithBrowser, this, [this](const QUrl &url) {
mainWindow.show();
webView->load(url);
webView->show();
});Once the authorization is finished, we close the view:
connect(&m_oauth, &QAbstractOAuth::granted, this, [this]() {
// Here we use QNetworkRequestFactory to store the access token
m_api.setBearerToken(m_oauth.token().toLatin1());
m_handler->close();
webView->close();
});For QtQuick applications the flow is in principle the same, but instead of QWebEngineView widget we use WebEngineView QML element:
WebEngineView {
id: authorizationWebView
anchors.fill: parent
visible: false
}This simplified example exposes needed APIs from C++ class
class HttpExample : public QObject
{
Q_OBJECT
#ifdef QT_QML_LIB
QML_NAMED_ELEMENT(OAuth2)
#endif
public:
Q_INVOKABLE void authorize();
signals:
void authorizationCompleted(bool success);
void authorizeWithBrowser(const QUrl &url);Which are then used on the QML-side for invoking WebEngineView to handle the authorization:
onAuthorizeWithBrowser:
(url) => {
console.log("Starting authorization with WebView")
authorizationWebView.url = url
authorizationWebView.visible = true
}
onAuthorizationCompleted:
(success) => {
console.log("Authorized: " + success);
authorizationWebView.visible = false
}The choice of redirect URI scheme (http, https, or custom-uri scheme) has an impact how to use Qt WebEngine.
With http loopback redirect URI and QOAuthHttpServerReplyHandler the handling works similarly as with system browser. Qt WebEngine redirects the authorization to the reply handler's localhost server similarly as the system browser.
With custom-scheme URIs (such as com.example.myqtapp:/redirect) and QOAuthUriSchemeReplyHandler the flow works also similarly as with system browser.
The main difference is that the application does not need to be configured similarly as the Universal Links on iOS/macOS or App Links on Android, as described in QOAuthUriSchemeReplyHandler documentation.
m_handler.setRedirectUrl(QUrl{"com.example.myqtapp://oauth2redirect"_L1});
m_oauth.setReplyHandler(&m_handler);
connect(&m_oauth, &QAbstractOAuth::authorizeWithBrowser, this, [this](const QUrl &url) {
mainWindow.show();
webView->load(url);
webView->show();
});
connect(&m_oauth, &QAbstractOAuth::granted, this, [this]() {
// Here we use QNetworkRequestFactory to store the access token
m_api.setBearerToken(m_oauth.token().toLatin1());
m_handler.close();
webView->close();
});Technically this works so that Qt WebEngine calls the QDesktopServices::openUrl() for unhandled URI-schemes, whose counterpart QOAuthUriSchemeReplyHandler listens to.
With https URIs and QOAuthUriSchemeReplyHandler the logic changes slightly. Similarly as with Custom scheme URIs the application doesn't need to be configured, but we need to supply the redirection at the end of authorization stage to the web engine.
connect(webView, &QWebEngineView::urlChanged, this, [this](const QUrl &url){
m_handler.handleAuthorizationRedirect(url);
});This needs to be done because from Qt WebEngine point of view the redirect URL is a valid https URL, and by default will attempt to navigate to it.
To prevent such navigation attempts and accidental authorization code exposure (consider the case the redirect URL domain isn't in your control), a more involved filtering should be used. Also the use of QOAuth2AuthorizationCodeFlow::PkceMethod is strongly recommended as it mitigates the impact of authorization code hijacking.
For example:
connect(webView->page(), &QWebEnginePage::navigationRequested,
this, [this](QWebEngineNavigationRequest &request) {
if (request.navigationType() == QWebEngineNavigationRequest::RedirectNavigation
&& m_handler.handleAuthorizationRedirect(request.url())) {
request.reject();
webView->close();
} else {
request.accept();
}
});
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.9/qt-oauth2-browsersupport.html