├── .tag ├── examples ├── examples.pro ├── oauth │ ├── oauth.pro │ ├── redditclient │ │ ├── doc │ │ │ ├── images │ │ │ │ └── redditclient-example.png │ │ │ └── src │ │ │ │ └── qtnetworkauth-redditclient.qdoc │ │ ├── redditclient.pro │ │ ├── main.cpp │ │ ├── CMakeLists.txt │ │ ├── redditmodel.h │ │ └── redditmodel.cpp │ └── CMakeLists.txt └── CMakeLists.txt ├── .gitreview ├── dependencies.yaml ├── src ├── oauth │ ├── doc │ │ ├── images │ │ │ ├── oauth2-codeflow-stages.webp │ │ │ ├── oauth2-refresh-details.webp │ │ │ ├── oauth2-codeflow-details.webp │ │ │ ├── oauth2-deviceflow-stages.webp │ │ │ └── oauth2-deviceflow-details.webp │ │ ├── src │ │ │ ├── qtnetworkauth-examples.qdoc │ │ │ ├── qtnetworkauth-toc.qdoc │ │ │ ├── qtnetworkauth.qdoc │ │ │ ├── external-resources.qdoc │ │ │ ├── qtnetworkauth-security.qdoc │ │ │ └── qtnetworkauth-oauth2-browsersupport.qdoc │ │ ├── snippets │ │ │ ├── MainWindow.qml │ │ │ ├── CMakeLists.txt │ │ │ ├── main.cpp │ │ │ └── src_oauth_replyhandlers_p.h │ │ └── qtnetworkauth.qdocconf │ ├── configure.cmake │ ├── qoauthglobal.h │ ├── qoauthoobreplyhandler_p.h │ ├── qabstractoauthreplyhandler_p.h │ ├── qoauthoobreplyhandler.h │ ├── qabstractoauthreplyhandler.h │ ├── qoauthurischemereplyhandler.h │ ├── CMakeLists.txt │ ├── qoauth2authorizationcodeflow_p.h │ ├── qoauth1signature_p.h │ ├── qoauthhttpserverreplyhandler.h │ ├── qabstractoauth_p.h │ ├── qoauthhttpserverreplyhandler_p.h │ ├── qoauth2deviceauthorizationflow.h │ ├── qoauth1signature.h │ ├── qoauth2deviceauthorizationflow_p.h │ ├── qoauth1_p.h │ ├── qoauth2authorizationcodeflow.h │ ├── qabstractoauthreplyhandler.cpp │ ├── qoauthoobreplyhandler.cpp │ ├── qoauth1.h │ ├── qabstractoauth.h │ └── qabstractoauth2_p.h └── CMakeLists.txt ├── tests ├── manual │ └── examples │ │ └── twittertimeline │ │ ├── doc │ │ ├── images │ │ │ └── twittertimeline-example.png │ │ └── src │ │ │ └── qtnetworkauth-twittertimeline.qdoc │ │ ├── twittertimeline.pro │ │ ├── twitter.h │ │ ├── CMakeLists.txt │ │ ├── twittertimelinemodel.h │ │ ├── twitter.cpp │ │ ├── twitterdialog.ui │ │ ├── main.cpp │ │ └── twittertimelinemodel.cpp ├── CMakeLists.txt └── auto │ ├── oauthurischemereplyhandler │ ├── CMakeLists.txt │ └── tst_oauthurischemereplyhandler.cpp │ ├── cmake │ └── CMakeLists.txt │ ├── CMakeLists.txt │ ├── abstractoauth2 │ └── CMakeLists.txt │ ├── oauth1signature │ └── CMakeLists.txt │ ├── abstractoauth │ ├── CMakeLists.txt │ └── tst_abstractoauth.cpp │ ├── oauth2codeflow │ └── CMakeLists.txt │ ├── oauth2deviceflow │ └── CMakeLists.txt │ ├── oauth1 │ └── CMakeLists.txt │ ├── oauthhttpserverreplyhandler │ ├── CMakeLists.txt │ └── certs │ │ ├── selfsigned-server.crt │ │ └── selfsigned-server.key │ └── shared │ ├── tlswebserver.h │ ├── certs │ ├── selfsigned-client.crt │ ├── selfsigned-server.crt │ ├── selfsigned-client.key │ └── selfsigned-server.key │ ├── webserver.h │ ├── oauthtestutils.cpp │ ├── tlswebserver.cpp │ ├── oauthtestutils.h │ └── webserver.cpp ├── .cmake.conf ├── dist ├── REUSE.toml ├── changes-6.0.0 ├── changes-5.14.0 ├── changes-5.15.0 ├── changes-5.13.1 ├── changes-5.14.1 ├── changes-5.11.3 ├── changes-5.12.2 ├── changes-5.12.3 ├── changes-5.12.4 ├── changes-5.12.5 ├── changes-5.13.2 ├── changes-5.14.2 ├── changes-5.11.1 ├── changes-5.12.0 ├── changes-5.11.2 ├── changes-5.12.1 ├── changes-5.12.10 ├── changes-5.15.2 └── changes-5.13.0 ├── LICENSES ├── LicenseRef-Qt-Commercial.txt └── BSD-3-Clause.txt ├── coin ├── module_config.yaml └── axivion │ └── ci_config_linux.json ├── CMakeLists.txt ├── REUSE.toml └── licenseRule.json /.tag: -------------------------------------------------------------------------------- 1 | b35c63031c4ca615be64be362527115329c9f691 2 | -------------------------------------------------------------------------------- /examples/examples.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS += oauth 3 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=codereview.qt-project.org 3 | project=qt/qtnetworkauth 4 | defaultbranch=dev 5 | -------------------------------------------------------------------------------- /dependencies.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | ../qtbase: 3 | ref: c17ae1096e0548041150b692b3458de19df2f534 4 | required: true 5 | -------------------------------------------------------------------------------- /examples/oauth/oauth.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | qtHaveModule(widgets) { 4 | SUBDIRS += \ 5 | redditclient 6 | } 7 | -------------------------------------------------------------------------------- /src/oauth/doc/images/oauth2-codeflow-stages.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtnetworkauth/HEAD/src/oauth/doc/images/oauth2-codeflow-stages.webp -------------------------------------------------------------------------------- /src/oauth/doc/images/oauth2-refresh-details.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtnetworkauth/HEAD/src/oauth/doc/images/oauth2-refresh-details.webp -------------------------------------------------------------------------------- /src/oauth/doc/images/oauth2-codeflow-details.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtnetworkauth/HEAD/src/oauth/doc/images/oauth2-codeflow-details.webp -------------------------------------------------------------------------------- /src/oauth/doc/images/oauth2-deviceflow-stages.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtnetworkauth/HEAD/src/oauth/doc/images/oauth2-deviceflow-stages.webp -------------------------------------------------------------------------------- /src/oauth/doc/images/oauth2-deviceflow-details.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtnetworkauth/HEAD/src/oauth/doc/images/oauth2-deviceflow-details.webp -------------------------------------------------------------------------------- /examples/oauth/redditclient/doc/images/redditclient-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtnetworkauth/HEAD/examples/oauth/redditclient/doc/images/redditclient-example.png -------------------------------------------------------------------------------- /tests/manual/examples/twittertimeline/doc/images/twittertimeline-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtnetworkauth/HEAD/tests/manual/examples/twittertimeline/doc/images/twittertimeline-example.png -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from src.pro. 5 | 6 | set(QT_SBOM_DEFAULT_QT_LICENSE_ID_LIBRARIES "QT_COMMERCIAL_OR_GPL3") 7 | 8 | add_subdirectory(oauth) 9 | -------------------------------------------------------------------------------- /examples/oauth/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | # Generated from oauth.pro. 5 | 6 | if(TARGET Qt::Widgets) 7 | qt_internal_add_example(redditclient) 8 | endif() 9 | -------------------------------------------------------------------------------- /.cmake.conf: -------------------------------------------------------------------------------- 1 | set(QT_REPO_MODULE_VERSION "6.12.0") 2 | set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1") 3 | set(QT_EXTRA_INTERNAL_TARGET_DEFINES 4 | "QT_NO_CONTEXTLESS_CONNECT=1" 5 | "QT_NO_FOREACH=1" 6 | "QT_NO_QASCONST=1" 7 | "QT_NO_URL_CAST_FROM_STRING=1" 8 | ) 9 | -------------------------------------------------------------------------------- /dist/REUSE.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[annotations]] 4 | path = ["**"] 5 | precedence = "override" 6 | comment = "Licensed as documentation." 7 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 8 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" 9 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | # Generated from examples.pro. 5 | 6 | qt_examples_build_begin(EXTERNAL_BUILD) 7 | 8 | add_subdirectory(oauth) 9 | 10 | qt_examples_build_end() 11 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from tests.pro. 5 | 6 | if(QT_BUILD_STANDALONE_TESTS) 7 | # Add qt_find_package calls for extra dependencies that need to be found when building 8 | # the standalone tests here. 9 | endif() 10 | 11 | qt_build_tests() 12 | -------------------------------------------------------------------------------- /examples/oauth/redditclient/redditclient.pro: -------------------------------------------------------------------------------- 1 | QT += widgets network networkauth 2 | requires(qtConfig(listview)) 3 | 4 | TARGET = redditclient 5 | 6 | # Input 7 | SOURCES += main.cpp \ 8 | redditmodel.cpp 9 | 10 | HEADERS += \ 11 | redditmodel.h 12 | 13 | # install 14 | target.path = $$[QT_INSTALL_EXAMPLES]/oauth/redditclient 15 | INSTALLS += target 16 | -------------------------------------------------------------------------------- /tests/auto/oauthurischemereplyhandler/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | qt_internal_add_test(tst_oauthurischemereplyhandler 5 | SOURCES 6 | tst_oauthurischemereplyhandler.cpp 7 | LIBRARIES 8 | Qt::Core 9 | Qt::Gui 10 | Qt::Network 11 | Qt::NetworkAuth 12 | ) 13 | -------------------------------------------------------------------------------- /tests/auto/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | project(qtnetworkauth_cmake_tests) 6 | 7 | enable_testing() 8 | 9 | find_package(Qt6Core REQUIRED) 10 | 11 | include("${_Qt6CTestMacros}") 12 | 13 | _qt_internal_test_module_includes( 14 | NetworkAuth QOAuthHttpServerReplyHandler 15 | ) 16 | -------------------------------------------------------------------------------- /src/oauth/configure.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | qt_feature("urischeme_replyhandler" PRIVATE 5 | LABEL "URI Scheme Reply Handler" 6 | CONDITION QT_FEATURE_gui 7 | ) 8 | 9 | qt_configure_add_summary_section(NAME "Qt NetworkAuth") 10 | qt_configure_add_summary_entry(ARGS "urischeme_replyhandler") 11 | qt_configure_end_summary_section() 12 | -------------------------------------------------------------------------------- /src/oauth/doc/src/qtnetworkauth-examples.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \group examples-qtnetworkauth 6 | \title Qt Network Authorization Examples 7 | \brief Example projects demonstrating the functionality in Qt Network 8 | Authorization. 9 | 10 | Qt Network Authorization has the following examples: 11 | */ 12 | -------------------------------------------------------------------------------- /tests/manual/examples/twittertimeline/twittertimeline.pro: -------------------------------------------------------------------------------- 1 | QT = core widgets network networkauth 2 | requires(qtConfig(tableview)) 3 | CONFIG -= app_bundle 4 | 5 | HEADERS += \ 6 | twitter.h \ 7 | twittertimelinemodel.h 8 | 9 | SOURCES += \ 10 | main.cpp \ 11 | twitter.cpp \ 12 | twittertimelinemodel.cpp 13 | 14 | FORMS += \ 15 | twitterdialog.ui 16 | 17 | # install 18 | target.path = $$[QT_INSTALL_EXAMPLES]/oauth/twittertimeline 19 | INSTALLS += target 20 | -------------------------------------------------------------------------------- /LICENSES/LicenseRef-Qt-Commercial.txt: -------------------------------------------------------------------------------- 1 | Licensees holding valid commercial Qt licenses may use this software in 2 | accordance with the the terms contained in a written agreement between 3 | you and The Qt Company. Alternatively, the terms and conditions that were 4 | accepted by the licensee when buying and/or downloading the 5 | software do apply. 6 | 7 | For the latest licensing terms and conditions, see https://www.qt.io/terms-conditions. 8 | For further information use the contact form at https://www.qt.io/contact-us. 9 | -------------------------------------------------------------------------------- /coin/module_config.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | accept_configuration: 3 | condition: property 4 | property: features 5 | not_contains_value: Disable 6 | 7 | instructions: 8 | Build: 9 | - type: EnvironmentVariable 10 | variableName: VERIFY_SOURCE_SBOM 11 | variableValue: "ON" 12 | - !include "{{qt/qtbase}}/coin_module_build_template_v2.yaml" 13 | 14 | Test: 15 | - !include "{{qt/qtbase}}/coin_module_test_template_v3.yaml" 16 | - !include "{{qt/qtbase}}/coin_module_test_docs.yaml" 17 | -------------------------------------------------------------------------------- /tests/auto/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | add_subdirectory(abstractoauth2) 5 | add_subdirectory(cmake) 6 | add_subdirectory(oauth1) 7 | add_subdirectory(oauth2codeflow) 8 | add_subdirectory(oauth2deviceflow) 9 | add_subdirectory(oauth1signature) 10 | add_subdirectory(oauthhttpserverreplyhandler) 11 | if(QT_FEATURE_urischeme_replyhandler) 12 | add_subdirectory(oauthurischemereplyhandler) 13 | endif() 14 | if(QT_FEATURE_private_tests) 15 | add_subdirectory(abstractoauth) 16 | endif() 17 | -------------------------------------------------------------------------------- /tests/auto/abstractoauth2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | list(APPEND test_data "../shared/certs") 5 | 6 | qt_internal_add_test(tst_abstractoauth2 7 | SOURCES 8 | tst_abstractoauth2.cpp 9 | ../shared/oauthtestutils.h ../shared/oauthtestutils.cpp 10 | INCLUDE_DIRECTORIES 11 | ../shared 12 | LIBRARIES 13 | Qt::CorePrivate 14 | Qt::Network 15 | Qt::NetworkAuth 16 | Qt::NetworkAuthPrivate 17 | TESTDATA ${test_data} 18 | ) 19 | -------------------------------------------------------------------------------- /src/oauth/doc/src/qtnetworkauth-toc.qdoc: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (C) 2025 The Qt Company Ltd. 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 4 | /*! 5 | \page qtnetworkauth-toc.html 6 | \title Qt Network Authorization module topics 7 | The following list has links to all the individual topics (HTML files) 8 | in the Qt Network Authorization module. 9 | 10 | \list 11 | \li \l {OAuth 2.0 Overview}{Overview} 12 | \li \l {Qt OAuth2 Browser Support}{Browser Support} 13 | \li \l {Qt Network Authorization Security Considerations}{Security Considerations} 14 | \endlist 15 | */ 16 | -------------------------------------------------------------------------------- /tests/auto/oauth1signature/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from oauth1signature.pro. 5 | 6 | ##################################################################### 7 | ## tst_oauth1signature Test: 8 | ##################################################################### 9 | 10 | qt_internal_add_test(tst_oauth1signature 11 | SOURCES 12 | tst_oauth1signature.cpp 13 | LIBRARIES 14 | Qt::CorePrivate 15 | Qt::NetworkAuth 16 | ) 17 | 18 | #### Keys ignored in scope 1:.:.:oauth1signature.pro:: 19 | # TEMPLATE = "app" 20 | -------------------------------------------------------------------------------- /src/oauth/qoauthglobal.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QOAUTHGLOBAL_H 5 | #define QOAUTHGLOBAL_H 6 | 7 | #include 8 | #include 9 | 10 | QT_BEGIN_NAMESPACE 11 | 12 | #if defined(QT_SHARED) || !defined(QT_STATIC) 13 | # if defined(QT_BUILD_NETWORKAUTH_LIB) 14 | # define Q_OAUTH_EXPORT Q_DECL_EXPORT 15 | # else 16 | # define Q_OAUTH_EXPORT Q_DECL_IMPORT 17 | # endif 18 | #else 19 | # define Q_OAUTH_EXPORT 20 | #endif 21 | 22 | QT_END_NAMESPACE 23 | 24 | #endif // QOAUTHGLOBAL_H 25 | -------------------------------------------------------------------------------- /tests/auto/abstractoauth/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from abstractoauth.pro. 5 | 6 | ##################################################################### 7 | ## tst_abstractoauth Test: 8 | ##################################################################### 9 | 10 | qt_internal_add_test(tst_abstractoauth 11 | SOURCES 12 | tst_abstractoauth.cpp 13 | LIBRARIES 14 | Qt::CorePrivate 15 | Qt::Network 16 | Qt::NetworkAuth 17 | Qt::NetworkAuthPrivate 18 | ) 19 | 20 | #### Keys ignored in scope 1:.:.:abstractoauth.pro:: 21 | # TEMPLATE = "app" 22 | -------------------------------------------------------------------------------- /tests/auto/oauth2codeflow/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | list(APPEND test_data "../shared/certs") 5 | 6 | qt_internal_add_test(tst_oauth2codeflow 7 | SOURCES 8 | ../shared/webserver.h ../shared/webserver.cpp 9 | ../shared/tlswebserver.h ../shared/tlswebserver.cpp 10 | ../shared/oauthtestutils.h ../shared/oauthtestutils.cpp 11 | tst_oauth2codeflow.cpp 12 | INCLUDE_DIRECTORIES 13 | ../shared 14 | LIBRARIES 15 | Qt::CorePrivate 16 | Qt::Network 17 | Qt::NetworkAuth 18 | Qt::NetworkAuthPrivate 19 | TESTDATA ${test_data} 20 | ) 21 | -------------------------------------------------------------------------------- /tests/auto/oauth2deviceflow/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | list(APPEND test_data "../shared/certs") 5 | 6 | qt_internal_add_test(tst_oauth2deviceflow 7 | SOURCES 8 | ../shared/webserver.h ../shared/webserver.cpp 9 | ../shared/tlswebserver.h ../shared/tlswebserver.cpp 10 | ../shared/oauthtestutils.h ../shared/oauthtestutils.cpp 11 | tst_oauth2deviceflow.cpp 12 | INCLUDE_DIRECTORIES 13 | ../shared 14 | LIBRARIES 15 | Qt::CorePrivate 16 | Qt::Network 17 | Qt::NetworkAuth 18 | Qt::NetworkAuthPrivate 19 | TESTDATA ${test_data} 20 | ) 21 | 22 | -------------------------------------------------------------------------------- /dist/changes-6.0.0: -------------------------------------------------------------------------------- 1 | Qt 6.0.0 is a new major version release of Qt. It is not binary compatible with 2 | earlier Qt releases. 3 | 4 | The goal has been to retain as much source compatibility with Qt 5.15 as 5 | possible, but some changes were inevitable to make Qt a better framework. 6 | 7 | To make it easier to port to Qt 6.0, we have created a porting guide to 8 | summarize those changes and provide guidance to handle them. In the guide, you 9 | can find links to articles about changes that may affect your application and 10 | help you transition from Qt 5.15 to Qt 6.0: 11 | 12 | https://doc.qt.io/qt-6/portingguide.html 13 | 14 | For more details refer to the online documentation of Qt 6.0: 15 | 16 | https://doc.qt.io/qt-6/index.html 17 | 18 | -------------------------------------------------------------------------------- /tests/auto/oauth1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from oauth1.pro. 5 | 6 | ##################################################################### 7 | ## tst_oauth1 Test: 8 | ##################################################################### 9 | 10 | qt_internal_add_test(tst_oauth1 11 | SOURCES 12 | ../shared/webserver.h ../shared/webserver.cpp 13 | tst_oauth1.cpp 14 | INCLUDE_DIRECTORIES 15 | ../shared 16 | LIBRARIES 17 | Qt::CorePrivate 18 | Qt::Network 19 | Qt::NetworkAuth 20 | Qt::NetworkAuthPrivate 21 | ) 22 | 23 | #### Keys ignored in scope 1:.:.:oauth1.pro:: 24 | # TEMPLATE = "app" 25 | -------------------------------------------------------------------------------- /src/oauth/qoauthoobreplyhandler_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | // 5 | // W A R N I N G 6 | // ------------- 7 | // 8 | // This file is not part of the Qt API. It exists for the convenience 9 | // of the Network Access API. This header file may change from 10 | // version to version without notice, or even be removed. 11 | // 12 | // We mean it. 13 | // 14 | 15 | #ifndef QOAUTHOOBREPLYHANDLER_P_H 16 | #define QOAUTHOOBREPLYHANDLER_P_H 17 | 18 | #include 19 | 20 | QT_BEGIN_NAMESPACE 21 | 22 | class QOAuthOobReplyHandlerPrivate : public QObjectPrivate 23 | { 24 | }; 25 | 26 | QT_END_NAMESPACE 27 | 28 | #endif // QOAUTHOOBREPLYHANDLER_P_H 29 | -------------------------------------------------------------------------------- /dist/changes-5.14.0: -------------------------------------------------------------------------------- 1 | Qt 5.14 introduces many new features and improvements as well as bugfixes 2 | over the 5.13.x series. For more details, refer to the online documentation 3 | included in this distribution. The documentation is also available online: 4 | 5 | https://doc.qt.io/qt-5/index.html 6 | 7 | The Qt version 5.14 series is binary compatible with the 5.13.x series. 8 | Applications compiled for 5.13 will continue to run with 5.14. 9 | 10 | Some of the changes listed in this file include issue tracking numbers 11 | corresponding to tasks in the Qt Bug Tracker: 12 | 13 | https://bugreports.qt.io/ 14 | 15 | Each of these identifiers can be entered in the bug tracker to obtain more 16 | information about a particular change. 17 | 18 | - This release contains only minor code improvements. 19 | -------------------------------------------------------------------------------- /dist/changes-5.15.0: -------------------------------------------------------------------------------- 1 | Qt 5.15 introduces many new features and improvements as well as bugfixes 2 | over the 5.14.x series. For more details, refer to the online documentation 3 | included in this distribution. The documentation is also available online: 4 | 5 | https://doc.qt.io/qt-5/index.html 6 | 7 | The Qt version 5.15 series is binary compatible with the 5.14.x series. 8 | Applications compiled for 5.14 will continue to run with 5.15. 9 | 10 | Some of the changes listed in this file include issue tracking numbers 11 | corresponding to tasks in the Qt Bug Tracker: 12 | 13 | https://bugreports.qt.io/ 14 | 15 | Each of these identifiers can be entered in the bug tracker to obtain more 16 | information about a particular change. 17 | 18 | - This release contains only minor code improvements. 19 | -------------------------------------------------------------------------------- /src/oauth/qabstractoauthreplyhandler_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | // 5 | // W A R N I N G 6 | // ------------- 7 | // 8 | // This file is not part of the Qt API. It exists for the convenience 9 | // of the Network Access API. This header file may change from 10 | // version to version without notice, or even be removed. 11 | // 12 | // We mean it. 13 | // 14 | 15 | #ifndef QABSTRACTOAUTHREPLYHANDLER_P_H 16 | #define QABSTRACTOAUTHREPLYHANDLER_P_H 17 | 18 | #include 19 | #include 20 | 21 | QT_BEGIN_NAMESPACE 22 | 23 | Q_DECLARE_LOGGING_CATEGORY(lcReplyHandler) 24 | 25 | QT_END_NAMESPACE 26 | 27 | #endif // QABSTRACTOAUTHREPLYHANDLER_P_H 28 | -------------------------------------------------------------------------------- /dist/changes-5.13.1: -------------------------------------------------------------------------------- 1 | Qt 5.13.1 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.13.0. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.13 series is binary compatible with the 5.12.x series. 10 | Applications compiled for 5.12 will continue to run with 5.13. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /dist/changes-5.14.1: -------------------------------------------------------------------------------- 1 | Qt 5.14.1 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.14.0. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.14 series is binary compatible with the 5.13.x series. 10 | Applications compiled for 5.13 will continue to run with 5.14. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /tests/auto/oauthhttpserverreplyhandler/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from oauthhttpserverreplyhandler.pro. 5 | 6 | ##################################################################### 7 | ## tst_oauthhttpserverreplyhandler Test: 8 | ##################################################################### 9 | 10 | qt_internal_add_test(tst_oauthhttpserverreplyhandler 11 | SOURCES 12 | ../shared/webserver.h ../shared/webserver.cpp 13 | tst_oauthhttpserverreplyhandler.cpp 14 | INCLUDE_DIRECTORIES 15 | ../shared 16 | LIBRARIES 17 | Qt::CorePrivate 18 | Qt::Network 19 | Qt::NetworkAuth 20 | ) 21 | 22 | #### Keys ignored in scope 1:.:.:oauthhttpserverreplyhandler.pro:: 23 | # TEMPLATE = "app" 24 | -------------------------------------------------------------------------------- /dist/changes-5.11.3: -------------------------------------------------------------------------------- 1 | Qt 5.11.3 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.11.0 through 5.11.2. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | http://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.11 series is binary compatible with the 5.10.x series. 10 | Applications compiled for 5.10 will continue to run with 5.11. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /dist/changes-5.12.2: -------------------------------------------------------------------------------- 1 | Qt 5.12.2 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.12.0 through 5.12.1. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.12 series is binary compatible with the 5.11.x series. 10 | Applications compiled for 5.11 will continue to run with 5.12. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /dist/changes-5.12.3: -------------------------------------------------------------------------------- 1 | Qt 5.12.3 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.12.0 through 5.12.2. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.12 series is binary compatible with the 5.11.x series. 10 | Applications compiled for 5.11 will continue to run with 5.12. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /dist/changes-5.12.4: -------------------------------------------------------------------------------- 1 | Qt 5.12.4 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.12.0 through 5.12.3. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.12 series is binary compatible with the 5.11.x series. 10 | Applications compiled for 5.11 will continue to run with 5.12. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /dist/changes-5.12.5: -------------------------------------------------------------------------------- 1 | Qt 5.12.5 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.12.0 through 5.12.4. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.12 series is binary compatible with the 5.11.x series. 10 | Applications compiled for 5.11 will continue to run with 5.12. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /dist/changes-5.13.2: -------------------------------------------------------------------------------- 1 | Qt 5.13.2 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.13.0 through 5.13.1. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.13 series is binary compatible with the 5.12.x series. 10 | Applications compiled for 5.12 will continue to run with 5.13. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /dist/changes-5.14.2: -------------------------------------------------------------------------------- 1 | Qt 5.14.2 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.14.0 through 5.14.1. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.14 series is binary compatible with the 5.13.x series. 10 | Applications compiled for 5.13 will continue to run with 5.14. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | - This release contains only minor code improvements. 21 | -------------------------------------------------------------------------------- /tests/manual/examples/twittertimeline/twitter.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef TWITTERTIMELINE_TWITTER_H 5 | #define TWITTERTIMELINE_TWITTER_H 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | class Twitter : public QOAuth1 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | Twitter(QObject *parent = nullptr); 17 | Twitter(const std::pair &clientCredentials, QObject *parent = nullptr); 18 | Twitter(const QString &screenName, 19 | const std::pair &clientCredentials, 20 | QObject *parent = nullptr); 21 | 22 | signals: 23 | void authenticated(); 24 | 25 | private: 26 | Q_DISABLE_COPY(Twitter) 27 | 28 | QOAuthHttpServerReplyHandler *replyHandler = nullptr; 29 | }; 30 | 31 | #endif // TWITTERTIMELINE_TWITTER_H 32 | -------------------------------------------------------------------------------- /examples/oauth/redditclient/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "redditmodel.h" 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | using namespace Qt::StringLiterals; 12 | 13 | int main(int argc, char **argv) 14 | { 15 | QApplication app(argc, argv); 16 | QCommandLineParser parser; 17 | 18 | const QCommandLineOption clientId(QStringList() << "i"_L1 << "client-id"_L1, 19 | "Specifies the application client id"_L1, "client_id"_L1); 20 | 21 | parser.addOptions({clientId}); 22 | parser.process(app); 23 | 24 | if (parser.isSet(clientId)) { 25 | QListView view; 26 | RedditModel model(parser.value(clientId)); 27 | view.setModel(&model); 28 | view.show(); 29 | return app.exec(); 30 | } else { 31 | parser.showHelp(); 32 | } 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /tests/manual/examples/twittertimeline/doc/src/qtnetworkauth-twittertimeline.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \example twittertimeline 6 | \title Twitter Timeline Example 7 | \ingroup examples-qtnetworkauth 8 | \brief Demonstrates authenticating with OAuth to access a Twitter timeline. 9 | \excludefromcreator 10 | \image twittertimeline-example.png Screenshot of the example 11 | 12 | The \e {Twitter Timeline} example uses OAuth, as supported by 13 | \l {Qt Network Authorization}, to sign in to Twitter and display a timeline 14 | of tweets (in text format) associated with the authenticated user. 15 | 16 | To use this example, a consumer key and secret from Twitter are needed. 17 | To register the application visit https://apps.twitter.com. 18 | You’ll need to add \e http://localhost:1337/callback as a callback URL 19 | in your Twitter app settings. 20 | 21 | \include examples-run.qdocinc 22 | */ 23 | -------------------------------------------------------------------------------- /dist/changes-5.11.1: -------------------------------------------------------------------------------- 1 | Qt 5.11.1 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.11.0. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | http://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.11 series is binary compatible with the 5.10.x series. 10 | Applications compiled for 5.10 will continue to run with 5.11. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | **************************************************************************** 21 | * Qt 5.11.1 Changes * 22 | **************************************************************************** 23 | 24 | - This release contains only minor code improvements. 25 | -------------------------------------------------------------------------------- /dist/changes-5.12.0: -------------------------------------------------------------------------------- 1 | Qt 5.12 introduces many new features and improvements as well as bugfixes 2 | over the 5.11.x series. For more details, refer to the online documentation 3 | included in this distribution. The documentation is also available online: 4 | 5 | https://doc.qt.io/qt-5/index.html 6 | 7 | The Qt version 5.12 series is binary compatible with the 5.11.x series. 8 | Applications compiled for 5.11 will continue to run with 5.12. 9 | 10 | Some of the changes listed in this file include issue tracking numbers 11 | corresponding to tasks in the Qt Bug Tracker: 12 | 13 | https://bugreports.qt.io/ 14 | 15 | Each of these identifiers can be entered in the bug tracker to obtain more 16 | information about a particular change. 17 | 18 | **************************************************************************** 19 | * Library * 20 | **************************************************************************** 21 | 22 | OAuth 23 | ---- 24 | 25 | - QAbstractOAuth2 26 | * Added refreshToken property. 27 | -------------------------------------------------------------------------------- /dist/changes-5.11.2: -------------------------------------------------------------------------------- 1 | Qt 5.11.2 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.11.0 through 5.11.1. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | http://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.11 series is binary compatible with the 5.10.x series. 10 | Applications compiled for 5.10 will continue to run with 5.11. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | **************************************************************************** 21 | * Qt 5.11.2 Changes * 22 | **************************************************************************** 23 | 24 | - This release contains only minor code improvements. 25 | -------------------------------------------------------------------------------- /dist/changes-5.12.1: -------------------------------------------------------------------------------- 1 | Qt 5.12.1 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.12.0. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | http://doc.qt.io/qt-5/index.html 8 | 9 | The Qt version 5.12 series is binary compatible with the 5.11.x series. 10 | Applications compiled for 5.11 will continue to run with 5.12. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | **************************************************************************** 21 | * General * 22 | **************************************************************************** 23 | 24 | - Use 127.0.0.1 in place of localhost for redirect URI following RFC 8252. 25 | -------------------------------------------------------------------------------- /tests/auto/shared/tlswebserver.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2022 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef TLSWEBSERVER_H 5 | #define TLSWEBSERVER_H 6 | 7 | #include "webserver.h" 8 | 9 | #ifndef QT_NO_SSL 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | class QTcpSocket; 18 | class QSslConfiguration; 19 | class QUrl; 20 | QT_END_NAMESPACE 21 | 22 | class TlsWebServer : public QSslServer 23 | { 24 | public: 25 | using HttpRequest = WebServer::HttpRequest; 26 | using Handler = WebServer::Handler; 27 | 28 | TlsWebServer(Handler handler, const QSslConfiguration &config, QObject *parent = nullptr); 29 | QUrl url(const QString &path); 30 | void setExpectedSslErrors(const QSet &errors); 31 | 32 | private: 33 | Handler handler; 34 | QMap clients; 35 | QSet expectedSslErrors; 36 | }; 37 | 38 | #endif // !QT_NO_SSL 39 | 40 | #endif // TLSWEBSERVER_H 41 | -------------------------------------------------------------------------------- /examples/oauth/redditclient/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | project(redditclient LANGUAGES CXX) 6 | 7 | if(NOT DEFINED INSTALL_EXAMPLESDIR) 8 | set(INSTALL_EXAMPLESDIR "examples") 9 | endif() 10 | 11 | set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/oauth/redditclient") 12 | 13 | find_package(Qt6 REQUIRED COMPONENTS Core Gui Network NetworkAuth Widgets) 14 | 15 | qt_standard_project_setup() 16 | 17 | qt_add_executable(redditclient 18 | main.cpp 19 | redditmodel.cpp redditmodel.h 20 | ) 21 | 22 | set_target_properties(redditclient PROPERTIES 23 | WIN32_EXECUTABLE TRUE 24 | MACOSX_BUNDLE TRUE 25 | ) 26 | target_link_libraries(redditclient PRIVATE 27 | Qt6::Core 28 | Qt6::Gui 29 | Qt6::Network 30 | Qt6::NetworkAuth 31 | Qt6::Widgets 32 | ) 33 | 34 | install(TARGETS redditclient 35 | RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" 36 | BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" 37 | LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" 38 | ) 39 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from qtnetworkauth.pro. 5 | 6 | cmake_minimum_required(VERSION 3.16) 7 | 8 | include(.cmake.conf) 9 | project(QtNetworkAuth 10 | VERSION "${QT_REPO_MODULE_VERSION}" 11 | DESCRIPTION "Qt Network Auth Libraries" # special case 12 | HOMEPAGE_URL "https://qt.io/" 13 | LANGUAGES CXX C 14 | ) 15 | 16 | find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals) 17 | 18 | # This should be called as early as possible, just after find_package(BuildInternals) where it is 19 | # defined. 20 | qt_internal_project_setup() 21 | 22 | find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Core Network) 23 | find_package(Qt6 ${PROJECT_VERSION} QUIET CONFIG OPTIONAL_COMPONENTS Widgets Gui) 24 | 25 | if(NOT TARGET Qt::Network) 26 | message(NOTICE "Skipping the build as the condition \"TARGET Qt::Network\" is not met.") 27 | return() 28 | endif() 29 | 30 | if(NOT QT_FEATURE_http) 31 | message(NOTICE "Skipping the build as the condition \"QT_FEATURE_http\" is not met.") 32 | return() 33 | endif() 34 | qt_build_repo() 35 | -------------------------------------------------------------------------------- /src/oauth/qoauthoobreplyhandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QOAUTHOOBREPLYHANDLER_H 5 | #define QOAUTHOOBREPLYHANDLER_H 6 | 7 | #include 8 | 9 | #ifndef QT_NO_HTTP 10 | 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | // ### Qt 7 remove this undocumented class and arrange it's functionality otherwise (QTBUG-124329) 16 | class QOAuthOobReplyHandlerPrivate; 17 | class Q_OAUTH_EXPORT QOAuthOobReplyHandler : public QAbstractOAuthReplyHandler 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit QOAuthOobReplyHandler(QObject *parent = nullptr); 23 | ~QOAuthOobReplyHandler() override; 24 | 25 | QString callback() const override; 26 | 27 | protected: 28 | void networkReplyFinished(QNetworkReply *reply) override; 29 | explicit QOAuthOobReplyHandler(QOAuthOobReplyHandlerPrivate &, QObject *parent = nullptr); 30 | 31 | private: 32 | QVariantMap parseResponse(const QByteArray &response); 33 | }; 34 | 35 | QT_END_NAMESPACE 36 | 37 | #endif // QT_NO_HTTP 38 | 39 | #endif // QOAUTHOOBREPLYHANDLER_H 40 | -------------------------------------------------------------------------------- /coin/axivion/ci_config_linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "Project": { 3 | "BuildSystemIntegration": { 4 | "child_order": [ 5 | "GCCSetup", 6 | "CMake", 7 | "LinkLibraries" 8 | ] 9 | }, 10 | "CMake": { 11 | "_active": true, 12 | "_copy_from": "CMakeIntegration", 13 | "build_environment": {}, 14 | "build_options": "-j4", 15 | "generate_options": "--fresh", 16 | "generator": "Ninja" 17 | }, 18 | "GCCSetup": { 19 | "_active": true, 20 | "_copy_from": "Command", 21 | "build_command": "gccsetup --cc gcc --cxx g++ --config ../../../axivion/" 22 | }, 23 | "LinkLibraries": { 24 | "_active": true, 25 | "_copy_from": "AxivionLinker", 26 | "input_files": [ 27 | "build/lib/lib*.so*.ir" 28 | ], 29 | "ir": "build/$(env:TESTED_MODULE_COIN).ir" 30 | } 31 | }, 32 | "_Format": "1.0", 33 | "_Version": "7.6.2", 34 | "_VersionNum": [ 35 | 7, 36 | 6, 37 | 2, 38 | 12725 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /tests/auto/shared/certs/selfsigned-client.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDADCCAeigAwIBAgIUCZMzRYZccCDU28Sk62T1ICZcfLcwDQYJKoZIhvcNAQEL 3 | BQAwIjEgMB4GA1UEAwwXcXRuZXR3b3JrYXV0aF9hdXRvdGVzdHMwIBcNMDAxMjMx 4 | MjMwMTAxWhgPMjEyODA0MjUyMzAxMDFaMCIxIDAeBgNVBAMMF3F0bmV0d29ya2F1 5 | dGhfYXV0b3Rlc3RzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA19hR 6 | CjGusW7if8rojjys4FUSRc+XWUJXeCQjoVsKaUNPHGgihrDCYwUuNEtOkIt+M7fO 7 | DoB46aZI/4mwkAetPIq70W+ww4myQKj66Q/JD7LZ3653ErmFuZpS5oXAjbXUbRPQ 8 | hYGxozt6MGH2QsInw3qGaIFbrqj2H66QtLKqYOYDohwD0Iy8L/83JT3lITB9gly2 9 | o20ZIbIvwWhERtlnI6mN8J76plZWUhmygKcy0rI/uHBobdcO6PFfccGt0UIL5Iqk 10 | /VtCHdDI/azQJjV15C6ErSPSEJnqA/XPXwq5+77AU9yPBZ+5SBNhxoDjBi8kP12s 11 | Xn9RzEzg5pZVkAxQLQIDAQABoywwKjAJBgNVHRMEAjAAMB0GA1UdDgQWBBQ/aX4e 12 | u4u6G8W2MrvseIVVc+DCpDANBgkqhkiG9w0BAQsFAAOCAQEAtH1nUoiixKQI0QB+ 13 | 9Y7tMvrl3hxJPrzpZJ8a/LHXrxIb3Q5NrZiCNNP6VHky0SMn2R1EXzpai6vhvv1K 14 | MbmhwY70JJtcWlwGDZC73rUSRigHkxYhl2pS92ApjD6gj6MHM1CojylBqYpBAUHH 15 | FBe/Kbvs3kX8VrAnXhwua9BUD+A4zrbnJvMu4zkZDAGARpZFbuCNQ+tv86Dr/x/1 16 | jV1nh6GXJWqWmPZS/pX9y2XWvA2bhWuyYgSkHJSuNrUSnztKcIKxXEKgOovNoX2F 17 | h3epBpPgZK6c/mkdeeMl5PlSgnsRIpp0mEW9IrFp3EDtbZDebj2A83U5dVysYdwA 18 | IqSNqQ== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /tests/auto/shared/certs/selfsigned-server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDADCCAeigAwIBAgIUHbqecJIZyZuVjw3wxN45Kd0guzIwDQYJKoZIhvcNAQEL 3 | BQAwIjEgMB4GA1UEAwwXcXRuZXR3b3JrYXV0aF9hdXRvdGVzdHMwIBcNMDAxMjMx 4 | MjMwMTAxWhgPMjEyODA0MjUyMzAxMDFaMCIxIDAeBgNVBAMMF3F0bmV0d29ya2F1 5 | dGhfYXV0b3Rlc3RzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtws+ 6 | v+B9vItR1VwOO1xLF0NuLCimIxVTo6hAGiazSQU+wN4zmOD6c5f8QDmtoM8e1gWi 7 | kZ9jc5j9p7fYnreLJ7PTnBudb433GuFlVqYztxfiVePlwOEG7VDk7pbWTN+WlTSz 8 | 2Rm1IHk91CnanVvWAPnadSmETju/mbGnHQ2OBggnNZXMtyU5xU0SOxdt9JiTsdar 9 | n6pAkqrzdUa2H/X6g42xA/0kY1xxtasfM+CptUBpYqT+DWqg0kemiu4lsZoQr+di 10 | gHXbUjWWiycyYXdfo4VkpejIaOjY4hk21iGfRo4SRCBBgUKJFCvmE2Vm86BH1pMW 11 | 4zX/7T5Pdg7zns0whQIDAQABoywwKjAJBgNVHRMEAjAAMB0GA1UdDgQWBBRhMWqr 12 | TIOVg8O4mrrBuDasZR9TBTANBgkqhkiG9w0BAQsFAAOCAQEAOVs185gl/j9O7lsE 13 | 0gmo/0GFiUpXga9IEgiPyJyUFbw7vxfak3S5JBVpzAiWbeVw8MyI941DDzaxYjG3 14 | QG2KACxBh7HTMX3w+KTbSL0RmtXJGsU+IjQNgUuM+s+cY0tCGSbGI5Anx/sDaHL3 15 | r4l+KT87/H/jo2yC5hsAaZQ/7BM0TtQ307l0fsJ+4BRMe1VQtXL7QRH0wty1X5DQ 16 | BKb+EsdQ3KP+PKjPmzyU6QESTShvQAVV7u87yGoAG85IQGwmIrcb1//ZshxR1d0c 17 | X1HCL6ZKo/aKhHZ/+z6v4RAF8+6KdSAYbZdfktsyp25kO5HR1gh/6jyfMbd+wD9U 18 | vS3IYg== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /examples/oauth/redditclient/redditmodel.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef REDDITMODEL_H 5 | #define REDDITMODEL_H 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | QT_FORWARD_DECLARE_CLASS(QRestAccessManager) 16 | 17 | class RedditModel : public QAbstractTableModel 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | RedditModel(QObject *parent = nullptr); 23 | RedditModel(const QString &clientId, QObject *parent = nullptr); 24 | 25 | int rowCount(const QModelIndex &parent) const override; 26 | int columnCount(const QModelIndex &parent) const override; 27 | QVariant data(const QModelIndex &index, int role) const override; 28 | 29 | signals: 30 | void error(const QString &errorString); 31 | 32 | private: 33 | void updateHotThreads(); 34 | 35 | QNetworkRequestFactory redditApi; 36 | QRestAccessManager *network = nullptr; 37 | QOAuth2AuthorizationCodeFlow oauth2; 38 | QList threads; 39 | }; 40 | 41 | #endif // REDDITMODEL_H 42 | -------------------------------------------------------------------------------- /examples/oauth/redditclient/doc/src/qtnetworkauth-redditclient.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \example redditclient 6 | \examplecategory {Networking} 7 | \title Reddit Example 8 | \ingroup examples-qtnetworkauth 9 | \brief Demonstrates authenticating with OAuth 2 to access Reddit. 10 | \image redditclient-example.png Screenshot of the example 11 | 12 | The \e {Reddit} example uses OAuth 2, as supported by 13 | \l {Qt Network Authorization}, to sign in to Reddit and display the 14 | Reddit posts (in text format) associated with the authenticated user. 15 | 16 | To use this example, a consumer key from Reddit is needed. 17 | To register the application visit \l{https://www.reddit.com/prefs/apps/}. 18 | \note Choose \e {installed app} when creating the application. 19 | \note Set the redirect URI to \e http://localhost:1337/ in Reddit settings. 20 | 21 | \include examples-run.qdocinc 22 | 23 | Before launching, add \c --client-id to the executable command line, 24 | followed by your consumer key from \l {https://www.reddit.com/prefs/apps/}. 25 | */ 26 | -------------------------------------------------------------------------------- /tests/auto/oauthhttpserverreplyhandler/certs/selfsigned-server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDADCCAeigAwIBAgIUHbqecJIZyZuVjw3wxN45Kd0guzIwDQYJKoZIhvcNAQEL 3 | BQAwIjEgMB4GA1UEAwwXcXRuZXR3b3JrYXV0aF9hdXRvdGVzdHMwIBcNMDAxMjMx 4 | MjMwMTAxWhgPMjEyODA0MjUyMzAxMDFaMCIxIDAeBgNVBAMMF3F0bmV0d29ya2F1 5 | dGhfYXV0b3Rlc3RzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtws+ 6 | v+B9vItR1VwOO1xLF0NuLCimIxVTo6hAGiazSQU+wN4zmOD6c5f8QDmtoM8e1gWi 7 | kZ9jc5j9p7fYnreLJ7PTnBudb433GuFlVqYztxfiVePlwOEG7VDk7pbWTN+WlTSz 8 | 2Rm1IHk91CnanVvWAPnadSmETju/mbGnHQ2OBggnNZXMtyU5xU0SOxdt9JiTsdar 9 | n6pAkqrzdUa2H/X6g42xA/0kY1xxtasfM+CptUBpYqT+DWqg0kemiu4lsZoQr+di 10 | gHXbUjWWiycyYXdfo4VkpejIaOjY4hk21iGfRo4SRCBBgUKJFCvmE2Vm86BH1pMW 11 | 4zX/7T5Pdg7zns0whQIDAQABoywwKjAJBgNVHRMEAjAAMB0GA1UdDgQWBBRhMWqr 12 | TIOVg8O4mrrBuDasZR9TBTANBgkqhkiG9w0BAQsFAAOCAQEAOVs185gl/j9O7lsE 13 | 0gmo/0GFiUpXga9IEgiPyJyUFbw7vxfak3S5JBVpzAiWbeVw8MyI941DDzaxYjG3 14 | QG2KACxBh7HTMX3w+KTbSL0RmtXJGsU+IjQNgUuM+s+cY0tCGSbGI5Anx/sDaHL3 15 | r4l+KT87/H/jo2yC5hsAaZQ/7BM0TtQ307l0fsJ+4BRMe1VQtXL7QRH0wty1X5DQ 16 | BKb+EsdQ3KP+PKjPmzyU6QESTShvQAVV7u87yGoAG85IQGwmIrcb1//ZshxR1d0c 17 | X1HCL6ZKo/aKhHZ/+z6v4RAF8+6KdSAYbZdfktsyp25kO5HR1gh/6jyfMbd+wD9U 18 | vS3IYg== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /dist/changes-5.12.10: -------------------------------------------------------------------------------- 1 | Qt 5.12.10 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.12.9. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5.12/index.html 8 | 9 | The Qt version 5.12 series is binary compatible with the 5.11.x series. 10 | Applications compiled for 5.11 will continue to run with 5.12. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | **************************************************************************** 21 | * Important Behavior Changes * 22 | **************************************************************************** 23 | 24 | **************************************************************************** 25 | * Library * 26 | **************************************************************************** 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/manual/examples/twittertimeline/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from twittertimeline.pro. 5 | 6 | cmake_minimum_required(VERSION 3.16) 7 | project(twittertimeline LANGUAGES CXX) 8 | 9 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 10 | 11 | set(CMAKE_AUTOMOC ON) 12 | set(CMAKE_AUTORCC ON) 13 | set(CMAKE_AUTOUIC ON) 14 | 15 | if(NOT DEFINED INSTALL_EXAMPLESDIR) 16 | set(INSTALL_EXAMPLESDIR "examples") 17 | endif() 18 | 19 | set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/oauth/twittertimeline") 20 | 21 | find_package(Qt6 COMPONENTS Core) 22 | find_package(Qt6 COMPONENTS Widgets) 23 | find_package(Qt6 COMPONENTS Network) 24 | find_package(Qt6 COMPONENTS NetworkAuth) 25 | 26 | qt_add_executable(twittertimeline 27 | main.cpp 28 | twitter.cpp twitter.h 29 | twitterdialog.ui 30 | twittertimelinemodel.cpp twittertimelinemodel.h 31 | ) 32 | set_target_properties(twittertimeline PROPERTIES 33 | WIN32_EXECUTABLE TRUE 34 | MACOSX_BUNDLE FALSE 35 | ) 36 | target_link_libraries(twittertimeline PUBLIC 37 | Qt::Core 38 | Qt::Network 39 | Qt::NetworkAuth 40 | Qt::Widgets 41 | ) 42 | 43 | install(TARGETS twittertimeline 44 | RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" 45 | BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" 46 | LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" 47 | ) 48 | -------------------------------------------------------------------------------- /tests/manual/examples/twittertimeline/twittertimelinemodel.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef TWITTERTIMELINEMODEL_H 5 | #define TWITTERTIMELINEMODEL_H 6 | 7 | #include "twitter.h" 8 | 9 | #include 10 | #include 11 | 12 | class TwitterTimelineModel : public QAbstractTableModel 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | TwitterTimelineModel(QObject *parent = nullptr); 18 | 19 | int rowCount(const QModelIndex &parent) const override; 20 | QVariant data(const QModelIndex &index, int role) const override; 21 | int columnCount(const QModelIndex &parent) const override; 22 | QVariant headerData(int section, Qt::Orientation orientation, int role) const override; 23 | 24 | void authenticate(const std::pair &clientCredentials); 25 | QAbstractOAuth::Status status() const; 26 | 27 | public slots: 28 | void updateTimeline(); 29 | 30 | signals: 31 | void authenticated(); 32 | 33 | private: 34 | Q_DISABLE_COPY(TwitterTimelineModel) 35 | 36 | void parseJson(); 37 | 38 | struct Tweet { 39 | quint64 id; 40 | QDateTime createdAt; 41 | QString user; 42 | QString text; 43 | }; 44 | 45 | QList tweets; 46 | Twitter twitter; 47 | }; 48 | 49 | #endif // TWITTERTIMELINEMODEL_H 50 | -------------------------------------------------------------------------------- /dist/changes-5.15.2: -------------------------------------------------------------------------------- 1 | Qt 5.15.2 is a bug-fix release. It maintains both forward and backward 2 | compatibility (source and binary) with Qt 5.15.1. 3 | 4 | For more details, refer to the online documentation included in this 5 | distribution. The documentation is also available online: 6 | 7 | https://doc.qt.io/qt-5.15/index.html 8 | 9 | The Qt version 5.15 series is binary compatible with the 5.14.x series. 10 | Applications compiled for 5.14 will continue to run with 5.15. 11 | 12 | Some of the changes listed in this file include issue tracking numbers 13 | corresponding to tasks in the Qt Bug Tracker: 14 | 15 | https://bugreports.qt.io/ 16 | 17 | Each of these identifiers can be entered in the bug tracker to obtain more 18 | information about a particular change. 19 | 20 | **************************************************************************** 21 | * Important Behavior Changes * 22 | **************************************************************************** 23 | 24 | **************************************************************************** 25 | * Library * 26 | **************************************************************************** 27 | 28 | 29 | OAuth2 30 | ------ 31 | 32 | - [QTBUG-87703] Fixed starting a new session with some servers (e.g. Google) 33 | when using a refresh token. 34 | 35 | -------------------------------------------------------------------------------- /src/oauth/qabstractoauthreplyhandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QABSTRACTOAUTHREPLYHANDLER_H 5 | #define QABSTRACTOAUTHREPLYHANDLER_H 6 | 7 | #include 8 | 9 | #ifndef QT_NO_HTTP 10 | 11 | #include 12 | 13 | #include 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | class Q_OAUTH_EXPORT QAbstractOAuthReplyHandler : public QObject 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit QAbstractOAuthReplyHandler(QObject *parent = nullptr); 23 | virtual ~QAbstractOAuthReplyHandler(); 24 | 25 | virtual QString callback() const = 0; 26 | 27 | public Q_SLOTS: 28 | virtual void networkReplyFinished(QNetworkReply *reply) = 0; 29 | 30 | Q_SIGNALS: 31 | void callbackReceived(const QVariantMap &values); 32 | void tokensReceived(const QVariantMap &tokens); 33 | void tokenRequestErrorOccurred(QAbstractOAuth::Error error, const QString& errorString); 34 | 35 | void replyDataReceived(const QByteArray &data); 36 | void callbackDataReceived(const QByteArray &data); 37 | 38 | protected: 39 | QAbstractOAuthReplyHandler(QObjectPrivate &d, QObject *parent = nullptr); 40 | 41 | private: 42 | Q_DISABLE_COPY(QAbstractOAuthReplyHandler) 43 | }; 44 | 45 | QT_END_NAMESPACE 46 | 47 | #endif // QT_NO_HTTP 48 | 49 | #endif // QABSTRACTOAUTHREPLYHANDLER_H 50 | -------------------------------------------------------------------------------- /src/oauth/doc/snippets/MainWindow.qml: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | import QtQuick 5 | import QtQuick.Controls 6 | import QtWebEngine 7 | 8 | Window { 9 | id: main 10 | width: 800 11 | height: 600 12 | visible: true 13 | 14 | Rectangle { 15 | id: background 16 | anchors.fill: parent 17 | color: "lightsteelblue" 18 | } 19 | 20 | OAuth2 { 21 | id: oauth2 22 | //! [webengine-qml-authorization] 23 | onAuthorizeWithBrowser: 24 | (url) => { 25 | console.log("Starting authorization with WebView") 26 | authorizationWebView.url = url 27 | authorizationWebView.visible = true 28 | } 29 | onAuthorizationCompleted: 30 | (success) => { 31 | console.log("Authorized: " + success); 32 | authorizationWebView.visible = false 33 | } 34 | //! [webengine-qml-authorization] 35 | } 36 | 37 | Column { 38 | anchors.centerIn: parent 39 | Button { 40 | text: "Authorize" 41 | onClicked: oauth2.authorize() 42 | } 43 | } 44 | 45 | //! [webengine-qml-view] 46 | WebEngineView { 47 | id: authorizationWebView 48 | anchors.fill: parent 49 | visible: false 50 | } 51 | //! [webengine-qml-view] 52 | } 53 | -------------------------------------------------------------------------------- /dist/changes-5.13.0: -------------------------------------------------------------------------------- 1 | Qt 5.13 introduces many new features and improvements as well as bugfixes 2 | over the 5.12.x series. For more details, refer to the online documentation 3 | included in this distribution. The documentation is also available online: 4 | 5 | https://doc.qt.io/qt-5/index.html 6 | 7 | The Qt version 5.13 series is binary compatible with the 5.12.x series. 8 | Applications compiled for 5.12 will continue to run with 5.13. 9 | 10 | Some of the changes listed in this file include issue tracking numbers 11 | corresponding to tasks in the Qt Bug Tracker: 12 | 13 | https://bugreports.qt.io/ 14 | 15 | Each of these identifiers can be entered in the bug tracker to obtain more 16 | information about a particular change. 17 | 18 | **************************************************************************** 19 | * QAbstractOAuth * 20 | **************************************************************************** 21 | 22 | - Added prepareRequest and sendCustomRequest methods to authenticate any 23 | custom request, including custom verbs and bodies. 24 | 25 | **************************************************************************** 26 | * QOAuth1Signature * 27 | **************************************************************************** 28 | 29 | - Added customMethodString and setCustomMethodString methods to support 30 | signing requests with custom methods. 31 | -------------------------------------------------------------------------------- /LICENSES/BSD-3-Clause.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) . 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 7 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 8 | 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | -------------------------------------------------------------------------------- /src/oauth/qoauthurischemereplyhandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QOAUTHURISCHEMEREPLYHANDLER_H 5 | #define QOAUTHURISCHEMEREPLYHANDLER_H 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | 14 | class QOAuthUriSchemeReplyHandlerPrivate; 15 | class Q_OAUTH_EXPORT QOAuthUriSchemeReplyHandler : public QOAuthOobReplyHandler 16 | { 17 | Q_OBJECT 18 | Q_PROPERTY(QUrl redirectUrl READ redirectUrl WRITE setRedirectUrl NOTIFY redirectUrlChanged FINAL) 19 | public: 20 | Q_IMPLICIT QOAuthUriSchemeReplyHandler() : QOAuthUriSchemeReplyHandler(nullptr) {} 21 | explicit QOAuthUriSchemeReplyHandler(QObject *parent); 22 | explicit QOAuthUriSchemeReplyHandler(const QUrl &redirectUrl, QObject *parent = nullptr); 23 | ~QOAuthUriSchemeReplyHandler() override; 24 | 25 | QString callback() const override; 26 | 27 | void setRedirectUrl(const QUrl &url); 28 | QUrl redirectUrl() const; 29 | 30 | bool handleAuthorizationRedirect(const QUrl &url); 31 | 32 | bool listen(); 33 | void close(); 34 | bool isListening() const noexcept; 35 | 36 | Q_SIGNALS: 37 | void redirectUrlChanged(); 38 | 39 | private: 40 | Q_DISABLE_COPY(QOAuthUriSchemeReplyHandler) 41 | Q_DECLARE_PRIVATE(QOAuthUriSchemeReplyHandler) 42 | // Private slot for providing a callback slot for QDesktopServices::setUrlHandler 43 | Q_PRIVATE_SLOT(d_func(), bool _q_handleRedirectUrl(const QUrl &url)) 44 | }; 45 | 46 | QT_END_NAMESPACE 47 | 48 | #endif // QOAUTHURISCHEMEREPLYHANDLER_H 49 | -------------------------------------------------------------------------------- /src/oauth/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | # Generated from oauth.pro. 5 | 6 | ##################################################################### 7 | ## NetworkAuth Module: 8 | ##################################################################### 9 | 10 | qt_internal_add_module(NetworkAuth 11 | SOURCES 12 | qabstractoauth.cpp qabstractoauth.h qabstractoauth_p.h 13 | qabstractoauth2.cpp qabstractoauth2.h qabstractoauth2_p.h 14 | qabstractoauthreplyhandler.cpp qabstractoauthreplyhandler.h qabstractoauthreplyhandler_p.h 15 | qoauth1.cpp qoauth1.h qoauth1_p.h 16 | qoauth1signature.cpp qoauth1signature.h qoauth1signature_p.h 17 | qoauth2authorizationcodeflow.cpp qoauth2authorizationcodeflow.h qoauth2authorizationcodeflow_p.h 18 | qoauth2deviceauthorizationflow.cpp qoauth2deviceauthorizationflow.h 19 | qoauth2deviceauthorizationflow_p.h 20 | qoauthglobal.h 21 | qoauthhttpserverreplyhandler.cpp qoauthhttpserverreplyhandler.h qoauthhttpserverreplyhandler_p.h 22 | qoauthoobreplyhandler.cpp qoauthoobreplyhandler.h qoauthoobreplyhandler_p.h 23 | LIBRARIES 24 | Qt::CorePrivate 25 | PUBLIC_LIBRARIES 26 | Qt::Core 27 | Qt::Network 28 | PRIVATE_MODULE_INTERFACE 29 | Qt::CorePrivate 30 | NO_GENERATE_CPP_EXPORTS 31 | ) 32 | 33 | qt_internal_extend_target(NetworkAuth CONDITION QT_FEATURE_urischeme_replyhandler 34 | SOURCES 35 | qoauthurischemereplyhandler.cpp qoauthurischemereplyhandler.h 36 | LIBRARIES 37 | Qt::Gui 38 | ) 39 | 40 | #### Keys ignored in scope 1:.:.:oauth.pro:: 41 | # MODULE = "networkauth" 42 | qt_internal_add_docs(NetworkAuth 43 | doc/qtnetworkauth.qdocconf 44 | ) 45 | 46 | -------------------------------------------------------------------------------- /tests/auto/shared/certs/selfsigned-client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDX2FEKMa6xbuJ/ 3 | yuiOPKzgVRJFz5dZQld4JCOhWwppQ08caCKGsMJjBS40S06Qi34zt84OgHjppkj/ 4 | ibCQB608irvRb7DDibJAqPrpD8kPstnfrncSuYW5mlLmhcCNtdRtE9CFgbGjO3ow 5 | YfZCwifDeoZogVuuqPYfrpC0sqpg5gOiHAPQjLwv/zclPeUhMH2CXLajbRkhsi/B 6 | aERG2WcjqY3wnvqmVlZSGbKApzLSsj+4cGht1w7o8V9xwa3RQgvkiqT9W0Id0Mj9 7 | rNAmNXXkLoStI9IQmeoD9c9fCrn7vsBT3I8Fn7lIE2HGgOMGLyQ/Xaxef1HMTODm 8 | llWQDFAtAgMBAAECggEAa6aZlIn+5MO296GNpxMf7arAOE024O+zjFoJ4zny0Vke 9 | pb5SKfcSnCxDRRWiE3le8hBkFtuAcpfapIhZpRwPDLjsv6IC+SM94f3lVkPnNYsw 10 | Gt16yb35sf4EBrECvirHzbcqMsvietT5NhRFrDoFdvsu+gQ6Y7wlNNvtlBHf4/8o 11 | 9UKCE33Y0Du8m2Xt0M16tPPltKizhf5M/vZmuqjgLGIc5ySvquSbvqT9Ye2ku7Vf 12 | n8LEGAsfXuFFs830s848SSY7rwYVXe6n66Yhu2xlGWADurntJG7suKKNMG62F73W 13 | pxBAhmRJDXacgAdlZglsN8VeGe5IPSa/0+Ls7sWCCQKBgQDZgboJw3ga+bnggX/x 14 | XTMr3jBQdJn9RROr10WCimFU0NrXmVCtQCHPPvlzL0ARmosXNejrotzxnSOuUeRq 15 | cqYeAwRl3cKtto82MLt4HBCr4HwBdIeDvJ3k9Uv+WMx7FqMR5rJoNM16Y+SSrR22 16 | tyzdUf70VzazIesDHMN/why0owKBgQD+C02KSXt6fU2+V+hMd1mhwqK0p/vpow39 17 | WWc+OhlX+OiMUd+k4xf7gzaVktL8/j3YYO0uOwd3BUc50UeaeuQr+ok7Xq10/xrO 18 | QmyALL6zkcdOVT9XCNe/gv3LLIb4bxAyR9RsuFDtKFMicX/Tz3Lqk9IuQGx1SQGC 19 | GdCSt5Bk7wKBgAN2KBLNtJShUs764KFjvVO+ZoBxSp4YQlbixy1rrF7gMAtsWjdX 20 | pPIaa3fk0Z02G26UIg/V+LQzrwSwMvVqu7AQljpUzCtdk2vmXKVttOo3WWHgi+OR 21 | 1eV17e6vVRnEY3X+eOplpLuE6XdYH/fvdFxVWLxkwu8Y5BeZlpbq7PAHAoGAdA/L 22 | 5BLAM+zNONnGijC4pVtbpDdespXIzWcr8NTwQS25aGn7R8Rsb3650Enc1LJ+pL1b 23 | fpR/S5QAv1xqXxwn5CO40IPnsRzfLT5RfZlzomxGZvYxUtz6XEdHFayJGTT8bEw+ 24 | s1DdwAt9N64s3SLYeG0CSBkss8SfyMVscaslb8cCgYAwfumP+Qe4RJfrZNi3b88u 25 | p/K6kx4Qy6xTJlSjWQm4NyRfww4c3BDSLJrZU8+iTIeJCwhLgBE4V7m3o76E589o 26 | XiMH3FZkGphXHDt1ZymbdGlotlVuAmcvBBOD4m51lVtyHqFyx9y7/LmOzenXZGTJ 27 | Ap2t9nPoR3tg59D87Qp8ag== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/auto/shared/certs/selfsigned-server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC3Cz6/4H28i1HV 3 | XA47XEsXQ24sKKYjFVOjqEAaJrNJBT7A3jOY4Ppzl/xAOa2gzx7WBaKRn2NzmP2n 4 | t9iet4sns9OcG51vjfca4WVWpjO3F+JV4+XA4QbtUOTultZM35aVNLPZGbUgeT3U 5 | KdqdW9YA+dp1KYROO7+ZsacdDY4GCCc1lcy3JTnFTRI7F230mJOx1qufqkCSqvN1 6 | RrYf9fqDjbED/SRjXHG1qx8z4Km1QGlipP4NaqDSR6aK7iWxmhCv52KAddtSNZaL 7 | JzJhd1+jhWSl6Mho6NjiGTbWIZ9GjhJEIEGBQokUK+YTZWbzoEfWkxbjNf/tPk92 8 | DvOezTCFAgMBAAECggEAF5/dbPFh+RQ4LyPu+E1cqbd7wDpM2wlVHrHH+DgXeqyx 9 | IT5shWZAHOw4U+e915vz3GakyUu7j79muZ9aV33T+X9Vp/fOdYfqpS8DH9Baq15r 10 | SW+dByxj8vw2V+7i4NAYxNAlCDevr23Gg5wVSasBL2YQAoAlwd0nSQRrT64grvll 11 | SqfoyuOQs7+Fzny0mVHgHjxi0V+4io/pl2UuwnUJWnVhi+t/Eh4WJ+C4SNwIz7UO 12 | mAYoO3LO3sh6QVYObfgnTmEdMLbg8/r1eA4E2MDjB51AlffeeaaydpvtZ/ah76SQ 13 | /R6fYgkX71OJaTXfqKLAgFAtQfUguoL6H/i7Z2GAwQKBgQDFIWJ/dPHbp6uPqHsP 14 | yjLxDEhrgfiBEAnyoDk8+8jaYxeo1p0D5kPJy34upAZP5RUns3UBVAi4BN0J1mxn 15 | 283e2LsedPBc5v3qa1cL5SL/Xzffs86t1rz7grp/mwPhpt3kfH5W4vi1tntBb1Sh 16 | VU37/CfmpwUVbUtMcKgocGh1JQKBgQDttPL1hnf2ISKHpFDSoEv0/tqIZaYwc8Ue 17 | 0OIB5C+sbBo03sKBQkVN5C/PW73KTWlGxDbdZXCrVKG9Sp0jipIIByGBHFTxaqFF 18 | GbMot5ErshzBdGk8A362fMLRca78y2Qxis+OgDCtDWlvwn0gRzhmbJxC+wC6VANG 19 | e/h64jff4QKBgQCEWICHb5z8ylndDdDo7eg7evKX8t9CzuDO2pDzB1t2evakbMln 20 | l81FCnCBoa93LiaAy/Ou25sq6GD5vNJ0+9YAWeNudDX3OUGZg00ieEiByIx7jH0i 21 | qruf48mP6CO3+E6ampY7gRBW9tdTPApGcj30AftL2DAKjaDzBeNvmuAWXQKBgQCx 22 | us7CB0WgkQvJUXFg2puQVhE9VItaxOTI8rNZaKzAhZ9ekoPps4wv/gJFTznrjc++ 23 | Kq0/Aj6oy8GWz7gIP+6J9BL3/x//1ZM5IEsVkZMIkcbwWkLorVBLz6K2iQKmXsjO 24 | RhSEXpKGgXWpK0j1HmssId8AMb5Mks5UIBMchhHy4QKBgGaXPbYFvkofHQDamA5n 25 | 43f6fC7Kt89wGKleYmFVkDkdFLbyIXVFOuGjm5hPz5CQO1YgZALA2N/D86/Plok2 26 | Csz1rAAhKBu4dXjCtpufF6MqvFVanxjUBXBwLckBLHM/nAxD+BMlZYJEysMXV+hI 27 | lFW74EMqE1xyzC8DTKuhn1Uw 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/auto/oauthhttpserverreplyhandler/certs/selfsigned-server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC3Cz6/4H28i1HV 3 | XA47XEsXQ24sKKYjFVOjqEAaJrNJBT7A3jOY4Ppzl/xAOa2gzx7WBaKRn2NzmP2n 4 | t9iet4sns9OcG51vjfca4WVWpjO3F+JV4+XA4QbtUOTultZM35aVNLPZGbUgeT3U 5 | KdqdW9YA+dp1KYROO7+ZsacdDY4GCCc1lcy3JTnFTRI7F230mJOx1qufqkCSqvN1 6 | RrYf9fqDjbED/SRjXHG1qx8z4Km1QGlipP4NaqDSR6aK7iWxmhCv52KAddtSNZaL 7 | JzJhd1+jhWSl6Mho6NjiGTbWIZ9GjhJEIEGBQokUK+YTZWbzoEfWkxbjNf/tPk92 8 | DvOezTCFAgMBAAECggEAF5/dbPFh+RQ4LyPu+E1cqbd7wDpM2wlVHrHH+DgXeqyx 9 | IT5shWZAHOw4U+e915vz3GakyUu7j79muZ9aV33T+X9Vp/fOdYfqpS8DH9Baq15r 10 | SW+dByxj8vw2V+7i4NAYxNAlCDevr23Gg5wVSasBL2YQAoAlwd0nSQRrT64grvll 11 | SqfoyuOQs7+Fzny0mVHgHjxi0V+4io/pl2UuwnUJWnVhi+t/Eh4WJ+C4SNwIz7UO 12 | mAYoO3LO3sh6QVYObfgnTmEdMLbg8/r1eA4E2MDjB51AlffeeaaydpvtZ/ah76SQ 13 | /R6fYgkX71OJaTXfqKLAgFAtQfUguoL6H/i7Z2GAwQKBgQDFIWJ/dPHbp6uPqHsP 14 | yjLxDEhrgfiBEAnyoDk8+8jaYxeo1p0D5kPJy34upAZP5RUns3UBVAi4BN0J1mxn 15 | 283e2LsedPBc5v3qa1cL5SL/Xzffs86t1rz7grp/mwPhpt3kfH5W4vi1tntBb1Sh 16 | VU37/CfmpwUVbUtMcKgocGh1JQKBgQDttPL1hnf2ISKHpFDSoEv0/tqIZaYwc8Ue 17 | 0OIB5C+sbBo03sKBQkVN5C/PW73KTWlGxDbdZXCrVKG9Sp0jipIIByGBHFTxaqFF 18 | GbMot5ErshzBdGk8A362fMLRca78y2Qxis+OgDCtDWlvwn0gRzhmbJxC+wC6VANG 19 | e/h64jff4QKBgQCEWICHb5z8ylndDdDo7eg7evKX8t9CzuDO2pDzB1t2evakbMln 20 | l81FCnCBoa93LiaAy/Ou25sq6GD5vNJ0+9YAWeNudDX3OUGZg00ieEiByIx7jH0i 21 | qruf48mP6CO3+E6ampY7gRBW9tdTPApGcj30AftL2DAKjaDzBeNvmuAWXQKBgQCx 22 | us7CB0WgkQvJUXFg2puQVhE9VItaxOTI8rNZaKzAhZ9ekoPps4wv/gJFTznrjc++ 23 | Kq0/Aj6oy8GWz7gIP+6J9BL3/x//1ZM5IEsVkZMIkcbwWkLorVBLz6K2iQKmXsjO 24 | RhSEXpKGgXWpK0j1HmssId8AMb5Mks5UIBMchhHy4QKBgGaXPbYFvkofHQDamA5n 25 | 43f6fC7Kt89wGKleYmFVkDkdFLbyIXVFOuGjm5hPz5CQO1YgZALA2N/D86/Plok2 26 | Csz1rAAhKBu4dXjCtpufF6MqvFVanxjUBXBwLckBLHM/nAxD+BMlZYJEysMXV+hI 27 | lFW74EMqE1xyzC8DTKuhn1Uw 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /src/oauth/qoauth2authorizationcodeflow_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | // 5 | // W A R N I N G 6 | // ------------- 7 | // 8 | // This file is not part of the Qt API. It exists for the convenience 9 | // of the Network Access API. This header file may change from 10 | // version to version without notice, or even be removed. 11 | // 12 | // We mean it. 13 | // 14 | 15 | #ifndef QOAUTH2AUTHORIZATIONCODEFLOW_P_H 16 | #define QOAUTH2AUTHORIZATIONCODEFLOW_P_H 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | QT_BEGIN_NAMESPACE 28 | 29 | class QOAuth2AuthorizationCodeFlowPrivate : public QAbstractOAuth2Private 30 | { 31 | public: 32 | Q_DECLARE_PUBLIC(QOAuth2AuthorizationCodeFlow) 33 | 34 | QOAuth2AuthorizationCodeFlowPrivate(const QUrl &authorizationUrl, 35 | const QUrl &accessTokenUrl, 36 | const QString &clientIdentifier, 37 | QNetworkAccessManager *manager = nullptr); 38 | 39 | void _q_handleCallback(const QVariantMap &data); 40 | void _q_authenticate(QNetworkReply *reply, QAuthenticator *authenticator); 41 | 42 | QByteArray createPKCEChallenge(); 43 | 44 | QOAuth2AuthorizationCodeFlow::PkceMethod pkceMethod 45 | = QOAuth2AuthorizationCodeFlow::PkceMethod::S256; 46 | quint8 pkceVerifierLength = 43; // RFC 7636 Section 4.1 47 | QByteArray pkceCodeVerifier; 48 | 49 | QPointer currentReply; 50 | }; 51 | 52 | QT_END_NAMESPACE 53 | 54 | #endif // QOAUTH2AUTHORIZATIONCODEFLOW_P_H 55 | -------------------------------------------------------------------------------- /src/oauth/qoauth1signature_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | // 5 | // W A R N I N G 6 | // ------------- 7 | // 8 | // This file is not part of the Qt API. It exists for the convenience 9 | // of the Network Access API. This header file may change from 10 | // version to version without notice, or even be removed. 11 | // 12 | // We mean it. 13 | // 14 | 15 | #ifndef QOAUTH1SIGNATURE_P_H 16 | #define QOAUTH1SIGNATURE_P_H 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | QT_BEGIN_NAMESPACE 27 | 28 | class QOAuth1SignaturePrivate : public QSharedData 29 | { 30 | public: 31 | QOAuth1SignaturePrivate() = default; 32 | QOAuth1SignaturePrivate(const QUrl &url, QOAuth1Signature::HttpRequestMethod method, 33 | const QMultiMap ¶meters, 34 | const QString &clientSharedKey = QString(), 35 | const QString &tokenSecret = QString()); 36 | 37 | QByteArray signatureBaseString() const; 38 | QByteArray secret() const; 39 | static QByteArray parameterString(const QMultiMap ¶meters); 40 | static QByteArray encodeHeaders(const QMultiMap &headers); 41 | 42 | 43 | QOAuth1Signature::HttpRequestMethod method = QOAuth1Signature::HttpRequestMethod::Post; 44 | QByteArray customVerb; 45 | QUrl url; 46 | QString clientSharedKey; 47 | QString tokenSecret; 48 | QMultiMap parameters; 49 | 50 | static QOAuth1SignaturePrivate shared_null; 51 | }; 52 | 53 | QT_END_NAMESPACE 54 | 55 | #endif // QOAUTH1SIGNATURE_P_H 56 | -------------------------------------------------------------------------------- /tests/manual/examples/twittertimeline/twitter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "twitter.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | Twitter::Twitter(QObject *parent) : 11 | Twitter(QString(), std::make_pair(QString(), QString()), parent) 12 | {} 13 | 14 | Twitter::Twitter(const std::pair &clientCredentials, QObject *parent) : 15 | Twitter(QString(), clientCredentials, parent) 16 | {} 17 | 18 | Twitter::Twitter(const QString &screenName, 19 | const std::pair &clientCredentials, 20 | QObject *parent) : 21 | QOAuth1(clientCredentials.first, clientCredentials.second, nullptr, parent) 22 | { 23 | replyHandler = new QOAuthHttpServerReplyHandler(1337, this); 24 | replyHandler->setCallbackPath("callback"); 25 | setReplyHandler(replyHandler); 26 | setTemporaryCredentialsUrl(QUrl("https://api.twitter.com/oauth/request_token")); 27 | setAuthorizationUrl(QUrl("https://api.twitter.com/oauth/authenticate")); 28 | setTokenCredentialsUrl(QUrl("https://api.twitter.com/oauth/access_token")); 29 | 30 | connect(this, &QAbstractOAuth::authorizeWithBrowser, [=](QUrl url) { 31 | QUrlQuery query(url); 32 | 33 | // Forces the user to enter their credentials to authorize the correct 34 | // user account 35 | query.addQueryItem("force_login", "true"); 36 | 37 | if (!screenName.isEmpty()) 38 | query.addQueryItem("screen_name", screenName); 39 | url.setQuery(query); 40 | QDesktopServices::openUrl(url); 41 | }); 42 | 43 | connect(this, &QOAuth1::granted, this, &Twitter::authenticated); 44 | 45 | if (!clientCredentials.first.isEmpty() && !clientCredentials.second.isEmpty()) 46 | grant(); 47 | } 48 | -------------------------------------------------------------------------------- /tests/auto/shared/webserver.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef WEBSERVER_H 5 | #define WEBSERVER_H 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | QT_BEGIN_NAMESPACE 15 | class QTcpSocket; 16 | QT_END_NAMESPACE 17 | 18 | class WebServer : public QTcpServer 19 | { 20 | public: 21 | class HttpRequest { 22 | friend class WebServer; 23 | friend class TlsWebServer; 24 | 25 | quint16 port = 0; 26 | enum class State { 27 | ReadingMethod, 28 | ReadingUrl, 29 | ReadingStatus, 30 | ReadingHeader, 31 | ReadingBody, 32 | AllDone 33 | } state = State::ReadingMethod; 34 | QByteArray fragment; 35 | int bytesLeft = 0; 36 | 37 | bool readMethod(QTcpSocket *socket); 38 | bool readUrl(QTcpSocket *socket); 39 | bool readStatus(QTcpSocket *socket); 40 | bool readHeaders(QTcpSocket *socket); 41 | bool readBody(QTcpSocket *socket); 42 | 43 | public: 44 | enum class Method { 45 | Unknown, 46 | Head, 47 | Get, 48 | Put, 49 | Post, 50 | Delete, 51 | } method = Method::Unknown; 52 | QUrl url; 53 | std::pair version; 54 | QMap headers; 55 | QByteArray body; 56 | }; 57 | 58 | typedef std::function Handler; 59 | 60 | WebServer(Handler handler, QObject *parent = nullptr); 61 | 62 | QUrl url(const QString &path); 63 | 64 | private: 65 | Handler handler; 66 | 67 | QMap clients; 68 | }; 69 | 70 | #endif // WEBSERVER_H 71 | -------------------------------------------------------------------------------- /REUSE.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[annotations]] 4 | path = ["**/.gitattributes", "**.gitignore", "**.gitreview"] 5 | precedence = "closest" 6 | comment = "infrastructure" 7 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 8 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" 9 | 10 | [[annotations]] 11 | path = ["tests/**"] 12 | precedence = "closest" 13 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 14 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GPL-3.0-only" 15 | 16 | [[annotations]] 17 | path = [".tag", ".cmake.conf", "**.yaml", "**.pro", "**ci_config_linux.json"] 18 | precedence = "closest" 19 | comment = "build system" 20 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 21 | SPDX-License-Identifier = "BSD-3-Clause" 22 | 23 | [[annotations]] 24 | path = ["examples/**"] 25 | comment = "this must be after the build system table because example and snippets take precedence over build system" 26 | precedence = "closest" 27 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 28 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" 29 | 30 | [[annotations]] 31 | path = ["**.qdocconf", "**/doc/images/**", 32 | "src/oauth/doc/images/**.webp"] 33 | comment = "documentation" 34 | precedence = "closest" 35 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 36 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" 37 | 38 | [[annotations]] 39 | path = ["**.toml", "licenseRule.json"] 40 | precedence = "override" 41 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 42 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause" 43 | 44 | [[annotations]] 45 | path = ["**/qt_attribution.json"] 46 | precedence = "override" 47 | comment = "not necessary but ready if such a file is added." 48 | SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd." 49 | SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only" 50 | -------------------------------------------------------------------------------- /src/oauth/qoauthhttpserverreplyhandler.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QOAUTHHTTPSERVERREPLYHANDLER_H 5 | #define QOAUTHHTTPSERVERREPLYHANDLER_H 6 | 7 | #include 8 | 9 | #ifndef QT_NO_HTTP 10 | 11 | #include 12 | 13 | #include 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | class QUrlQuery; 18 | #ifndef QT_NO_SSL 19 | class QSslConfiguration; 20 | #endif 21 | 22 | class QOAuthHttpServerReplyHandlerPrivate; 23 | class Q_OAUTH_EXPORT QOAuthHttpServerReplyHandler : public QOAuthOobReplyHandler 24 | { 25 | Q_OBJECT 26 | 27 | public: 28 | explicit QOAuthHttpServerReplyHandler(QObject *parent = nullptr); 29 | explicit QOAuthHttpServerReplyHandler(quint16 port, QObject *parent = nullptr); 30 | explicit QOAuthHttpServerReplyHandler(const QHostAddress &address, quint16 port, 31 | QObject *parent = nullptr); 32 | ~QOAuthHttpServerReplyHandler(); 33 | 34 | QString callback() const override; 35 | 36 | QString callbackPath() const; 37 | void setCallbackPath(const QString &path); 38 | 39 | QString callbackHost() const; 40 | void setCallbackHost(const QString &path); 41 | 42 | QString callbackText() const; 43 | void setCallbackText(const QString &text); 44 | 45 | quint16 port() const; 46 | 47 | bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0); 48 | #ifndef QT_NO_SSL 49 | bool listen(const QSslConfiguration &configuration, 50 | const QHostAddress &address = QHostAddress::Any, quint16 port = 0); 51 | #endif 52 | void close(); 53 | bool isListening() const; 54 | 55 | private: 56 | Q_DECLARE_PRIVATE(QOAuthHttpServerReplyHandler) 57 | QScopedPointer d_ptr; 58 | }; 59 | 60 | QT_END_NAMESPACE 61 | 62 | #endif // QT_NO_HTTP 63 | 64 | #endif // QOAUTHHTTPSERVERREPLYHANDLER_H 65 | -------------------------------------------------------------------------------- /tests/manual/examples/twittertimeline/twitterdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | TwitterDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | Twitter Timeline 15 | 16 | 17 | 18 | 19 | 20 | C&lient Id: 21 | 22 | 23 | clientIdLineEdit 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Client &secret: 34 | 35 | 36 | clientSecretLineEdit 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | &Connect 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 0 55 | 1 56 | 57 | 58 | 59 | QAbstractItemView::NoSelection 60 | 61 | 62 | true 63 | 64 | 65 | false 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/oauth/doc/qtnetworkauth.qdocconf: -------------------------------------------------------------------------------- 1 | include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) 2 | include($QT_INSTALL_DOCS/config/exampleurl-qtnetworkauth.qdocconf) 3 | 4 | project = QtNetworkAuth 5 | description = Qt Network Authorization Reference Documentation 6 | version = $QT_VERSION 7 | buildversion = Qt Network Authorization | Commercial or GPLv3 8 | 9 | qhp.projects = QtNetworkAuth 10 | 11 | qhp.QtNetworkAuth.file = qtnetworkauth.qhp 12 | qhp.QtNetworkAuth.namespace = org.qt-project.qtnetworkauth.$QT_VERSION_TAG 13 | qhp.QtNetworkAuth.virtualFolder = qtnetworkauth 14 | qhp.QtNetworkAuth.indexTitle = Qt Network Authorization 15 | qhp.QtNetworkAuth.indexRoot = 16 | 17 | qhp.QtNetworkAuth.subprojects = manual examples classes 18 | qhp.QtNetworkAuth.subprojects.manual.title = Qt Network Authorization 19 | qhp.QtNetworkAuth.subprojects.manual.indexTitle = Qt Network Authorization module topics 20 | qhp.QtNetworkAuth.subprojects.manual.type = manual 21 | 22 | qhp.QtNetworkAuth.subprojects.examples.title = Examples 23 | qhp.QtNetworkAuth.subprojects.examples.indexTitle = Qt Network Authorization Examples 24 | qhp.QtNetworkAuth.subprojects.examples.selectors = example 25 | qhp.QtNetworkAuth.subprojects.examples.sortPages = true 26 | 27 | qhp.QtNetworkAuth.subprojects.classes.title = C++ Classes 28 | qhp.QtNetworkAuth.subprojects.classes.indexTitle = Qt Network Authorization C++ Classes 29 | qhp.QtNetworkAuth.subprojects.classes.selectors = class doc:headerfile 30 | qhp.QtNetworkAuth.subprojects.classes.sortPages = true 31 | 32 | tagfile = qtnetworkauth.tags 33 | 34 | depends += qtcore qtnetwork qtdoc qtcmake qtgui qtwebengine 35 | 36 | headerdirs += .. 37 | sourcedirs += .. 38 | imagedirs += images 39 | 40 | examplesinstallpath = oauth 41 | exampledirs += ../../../examples/oauth snippets 42 | 43 | #manifestmeta.highlighted.names = "QtNetworkAuth/Twitter Timeline Example" 44 | 45 | navigation.landingpage = "Qt Network Authorization" 46 | navigation.cppclassespage = "Qt Network Authorization C++ Classes" 47 | 48 | # Autogenerate navigation linking based on "Qt Network Authorization module topics": 49 | navigation.toctitles = "Qt Network Authorization module topics" 50 | navigation.toctitles.inclusive = false 51 | 52 | # Enforce zero documentation warnings 53 | warninglimit = 0 54 | -------------------------------------------------------------------------------- /src/oauth/qabstractoauth_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | // 5 | // W A R N I N G 6 | // ------------- 7 | // 8 | // This file is not part of the Qt API. It exists for the convenience 9 | // of the Network Access API. This header file may change from 10 | // version to version without notice, or even be removed. 11 | // 12 | // We mean it. 13 | // 14 | 15 | #ifndef QABSTRACTQOAUTH_P_H 16 | #define QABSTRACTQOAUTH_P_H 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | QT_BEGIN_NAMESPACE 36 | 37 | class QUrlQuery; 38 | 39 | class Q_AUTOTEST_EXPORT QAbstractOAuthPrivate : public QObjectPrivate 40 | { 41 | Q_DECLARE_PUBLIC(QAbstractOAuth) 42 | 43 | public: 44 | QAbstractOAuthPrivate(const char *loggingCategory, 45 | const QUrl &authorizationUrl, 46 | const QString &clientIdentifier, 47 | QNetworkAccessManager *manager); 48 | ~QAbstractOAuthPrivate(); 49 | 50 | QNetworkAccessManager *networkAccessManager(); 51 | void setStatus(QAbstractOAuth::Status status); 52 | static QByteArray generateRandomBase64String(quint8 length); 53 | void setExtraTokens(const QVariantMap &tokens); 54 | 55 | const QLoggingCategory loggingCategory; 56 | QString clientIdentifier; 57 | QString token; 58 | 59 | // Resource Owner Authorization: https://tools.ietf.org/html/rfc5849#section-2.2 60 | QUrl authorizationUrl; 61 | QVariantMap extraTokens; 62 | QAbstractOAuth::Status status = QAbstractOAuth::Status::NotAuthenticated; 63 | QPointer replyHandler; 64 | QScopedPointer defaultReplyHandler; 65 | QPointer networkAccessManagerPointer; 66 | QAbstractOAuth::ModifyParametersFunction modifyParametersFunction; 67 | QAbstractOAuth::ContentType contentType = QAbstractOAuth::ContentType::WwwFormUrlEncoded; 68 | 69 | QByteArray convertParameters(const QVariantMap ¶meters); 70 | void addContentTypeHeaders(QNetworkRequest *request); 71 | 72 | static QUrlQuery createQuery(const QMultiMap ¶meters); 73 | }; 74 | 75 | QT_END_NAMESPACE 76 | 77 | #endif // QABSTRACTQOAUTH_H 78 | -------------------------------------------------------------------------------- /src/oauth/qoauthhttpserverreplyhandler_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | // 5 | // W A R N I N G 6 | // ------------- 7 | // 8 | // This file is not part of the Qt API. It exists for the convenience 9 | // of the Network Access API. This header file may change from 10 | // version to version without notice, or even be removed. 11 | // 12 | // We mean it. 13 | // 14 | 15 | #ifndef QOAUTHHTTPSERVERREPLYHANDLER_P_H 16 | #define QOAUTHHTTPSERVERREPLYHANDLER_P_H 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | QT_BEGIN_NAMESPACE 29 | 30 | class QOAuthHttpServerReplyHandlerPrivate 31 | { 32 | Q_DECLARE_PUBLIC(QOAuthHttpServerReplyHandler) 33 | 34 | public: 35 | explicit QOAuthHttpServerReplyHandlerPrivate(QOAuthHttpServerReplyHandler *p); 36 | ~QOAuthHttpServerReplyHandlerPrivate(); 37 | 38 | QString callback() const; 39 | QString callbackHost() const; 40 | 41 | QTcpServer *httpServer = nullptr; 42 | QString text; 43 | QString path; 44 | QHostAddress callbackAddress; 45 | QString callbackHostname; 46 | quint16 callbackPort = 0; 47 | 48 | private: 49 | void _q_clientConnected(); 50 | void _q_readData(QTcpSocket *socket); 51 | void _q_answerClient(QTcpSocket *socket, const QUrl &url); 52 | void initializeLocalServer(); 53 | bool listen(const QHostAddress &address, quint16 port); 54 | 55 | struct QHttpRequest { 56 | quint16 port = 0; 57 | 58 | bool readMethod(QTcpSocket *socket); 59 | bool readUrl(QTcpSocket *socket); 60 | bool readStatus(QTcpSocket *socket); 61 | bool readHeader(QTcpSocket *socket); 62 | 63 | enum class State { 64 | ReadingMethod, 65 | ReadingUrl, 66 | ReadingStatus, 67 | ReadingHeader, 68 | ReadingBody, 69 | AllDone 70 | } state = State::ReadingMethod; 71 | QByteArray fragment; 72 | 73 | enum class Method { 74 | Unknown, 75 | Head, 76 | Get, 77 | Put, 78 | Post, 79 | Delete, 80 | } method = Method::Unknown; 81 | QUrl url; 82 | std::pair version; 83 | QMap headers; 84 | }; 85 | 86 | QMap clients; 87 | 88 | QOAuthHttpServerReplyHandler *q_ptr; 89 | }; 90 | 91 | QT_END_NAMESPACE 92 | 93 | #endif // QOAUTHHTTPSERVERREPLYHANDLER_P_H 94 | -------------------------------------------------------------------------------- /src/oauth/qoauth2deviceauthorizationflow.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QOAUTH2DEVICEAUTHORIZATIONFLOW_H 5 | #define QOAUTH2DEVICEAUTHORIZATIONFLOW_H 6 | 7 | #include 8 | 9 | #ifndef QT_NO_HTTP 10 | 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | class QDateTime; 16 | class QUrl; 17 | class QString; 18 | class QNetworkAccessManager; 19 | 20 | class QOAuth2DeviceAuthorizationFlowPrivate; 21 | class Q_OAUTH_EXPORT QOAuth2DeviceAuthorizationFlow : public QAbstractOAuth2 22 | { 23 | Q_OBJECT 24 | Q_PROPERTY(QString userCode READ userCode NOTIFY userCodeChanged FINAL) 25 | Q_PROPERTY(QUrl verificationUrl READ verificationUrl NOTIFY verificationUrlChanged FINAL) 26 | Q_PROPERTY(QUrl completeVerificationUrl READ completeVerificationUrl 27 | NOTIFY completeVerificationUrlChanged FINAL) 28 | Q_PROPERTY(bool polling READ isPolling NOTIFY pollingChanged FINAL) 29 | Q_PROPERTY(QDateTime userCodeExpirationAt READ userCodeExpirationAt 30 | NOTIFY userCodeExpirationAtChanged FINAL) 31 | 32 | public: 33 | QOAuth2DeviceAuthorizationFlow(); 34 | explicit QOAuth2DeviceAuthorizationFlow(QObject *parent); 35 | explicit QOAuth2DeviceAuthorizationFlow(QNetworkAccessManager *manager, 36 | QObject *parent = nullptr); 37 | ~QOAuth2DeviceAuthorizationFlow() override; 38 | 39 | QString userCode() const; 40 | QUrl verificationUrl() const; 41 | QUrl completeVerificationUrl() const; 42 | bool isPolling() const; 43 | QDateTime userCodeExpirationAt() const; 44 | 45 | public Q_SLOTS: 46 | void grant() override; 47 | bool startTokenPolling(); 48 | void stopTokenPolling(); 49 | 50 | Q_SIGNALS: 51 | void authorizeWithUserCode(const QUrl &verificationUrl, const QString &userCode, 52 | const QUrl &completeVerificationUrl); 53 | void userCodeChanged(const QString &userCode); 54 | void verificationUrlChanged(const QUrl &verificationUrl); 55 | void completeVerificationUrlChanged(const QUrl &completeVerificationUrl); 56 | void pollingChanged(bool polling); 57 | void userCodeExpirationAtChanged(const QDateTime &expiration); 58 | 59 | protected: 60 | bool event(QEvent *event) override; 61 | 62 | protected Q_SLOTS: 63 | void refreshTokensImplementation() QT7_ONLY(override); 64 | 65 | private: 66 | Q_DISABLE_COPY_MOVE(QOAuth2DeviceAuthorizationFlow) 67 | Q_DECLARE_PRIVATE(QOAuth2DeviceAuthorizationFlow) 68 | }; 69 | 70 | QT_END_NAMESPACE 71 | 72 | #endif // QT_NO_HTTP 73 | 74 | #endif // QOAUTH2DEVICEAUTHORIZATIONFLOW_H 75 | -------------------------------------------------------------------------------- /src/oauth/qoauth1signature.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QOAUTH1SIGNATURE_H 5 | #define QOAUTH1SIGNATURE_H 6 | 7 | #include 8 | 9 | #ifndef QT_NO_HTTP 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | class QUrlQuery; 18 | 19 | class QOAuth1SignaturePrivate; 20 | class Q_OAUTH_EXPORT QOAuth1Signature 21 | { 22 | public: 23 | enum class HttpRequestMethod { 24 | Head = 1, 25 | Get, 26 | Put, 27 | Post, 28 | Delete, 29 | Custom, 30 | 31 | Unknown = 0 32 | }; 33 | 34 | explicit QOAuth1Signature(const QUrl &url = QUrl(), 35 | HttpRequestMethod method = HttpRequestMethod::Post, 36 | const QMultiMap ¶meters = {}); 37 | QOAuth1Signature(const QUrl &url, const QString &clientSharedKey, const QString &tokenSecret, 38 | HttpRequestMethod method = HttpRequestMethod::Post, 39 | const QMultiMap ¶meters = {}); 40 | QOAuth1Signature(const QOAuth1Signature &other); 41 | QOAuth1Signature(QOAuth1Signature &&other); 42 | ~QOAuth1Signature(); 43 | 44 | HttpRequestMethod httpRequestMethod() const; 45 | void setHttpRequestMethod(HttpRequestMethod method); 46 | 47 | QByteArray customMethodString() const; 48 | void setCustomMethodString(const QByteArray &verb); 49 | 50 | QUrl url() const; 51 | void setUrl(const QUrl &url); 52 | 53 | QMultiMap parameters() const; 54 | void setParameters(const QMultiMap ¶meters); 55 | void addRequestBody(const QUrlQuery &body); 56 | 57 | void insert(const QString &key, const QVariant &value); 58 | QList keys() const; 59 | QVariant take(const QString &key); 60 | QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; 61 | 62 | QString clientSharedKey() const; 63 | void setClientSharedKey(const QString &secret); 64 | 65 | QString tokenSecret() const; 66 | void setTokenSecret(const QString &secret); 67 | 68 | QByteArray hmacSha1() const; 69 | QByteArray rsaSha1() const; 70 | QByteArray plainText() const; 71 | 72 | static QByteArray plainText(const QString &clientSharedSecret, const QString &tokenSecret); 73 | 74 | void swap(QOAuth1Signature &other); 75 | QOAuth1Signature &operator=(const QOAuth1Signature &other); 76 | QOAuth1Signature &operator=(QOAuth1Signature &&other); 77 | 78 | private: 79 | QSharedDataPointer d; 80 | }; 81 | 82 | QT_END_NAMESPACE 83 | 84 | #endif // QT_NO_HTTP 85 | 86 | #endif // QOAUTH1SIGNATURE_H 87 | -------------------------------------------------------------------------------- /src/oauth/qoauth2deviceauthorizationflow_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | // 5 | // W A R N I N G 6 | // ------------- 7 | // 8 | // This file is not part of the Qt API. It exists for the convenience 9 | // of the Network Access API. This header file may change from 10 | // version to version without notice, or even be removed. 11 | // 12 | // We mean it. 13 | // 14 | 15 | #ifndef QOAUTH2DEVICEAUTHORIZATIONFLOW_P_H 16 | #define QOAUTH2DEVICEAUTHORIZATIONFLOW_P_H 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | QT_BEGIN_NAMESPACE 31 | 32 | class QRestAccessManager; 33 | class QRestReply; 34 | 35 | class Q_AUTOTEST_EXPORT QOAuth2DeviceAuthorizationFlowPrivate : public QAbstractOAuth2Private 36 | { 37 | public: 38 | Q_DECLARE_PUBLIC(QOAuth2DeviceAuthorizationFlow) 39 | 40 | QOAuth2DeviceAuthorizationFlowPrivate(QNetworkAccessManager *manager = nullptr); 41 | ~QOAuth2DeviceAuthorizationFlowPrivate() override; 42 | 43 | void authorizationReplyFinished(QRestReply &reply); 44 | void tokenReplyFinished(QRestReply &reply); 45 | 46 | void handleTokenSuccessResponse(const QJsonObject &data); 47 | void handleTokenErrorResponse(const QJsonObject &data); 48 | 49 | void tokenAcquisitionFailed(QAbstractOAuth::Error error, const QString &errorString = {}); 50 | 51 | void setUserCode(const QString &code); 52 | void setVerificationUrl(const QUrl &url); 53 | void setVerificationUrlComplete(const QUrl &url); 54 | void setUserCodeExpiration(const QDateTime &expiration); 55 | 56 | bool startTokenPolling(); 57 | void stopTokenPolling(); 58 | void pollTokens(); 59 | bool isNextPollAfterExpiration() const; 60 | 61 | void reset(); 62 | void resetCurrentTokenReply(); 63 | void resetCurrentAuthorizationReply(); 64 | 65 | QRestAccessManager *network(); 66 | 67 | // https://datatracker.ietf.org/doc/html/rfc8628#section-3.2 68 | static inline constexpr auto defaultPollingInterval = std::chrono::seconds(5); 69 | bool useAutoTestDurations = false; 70 | QString userCode; 71 | QString deviceCode; 72 | QDateTime userCodeExpirationUtc; // When devicecode and usercode expire 73 | QUrl verificationUrl; 74 | QUrl completeVerificationUrl; 75 | QRestAccessManager *restAccessManager = nullptr; 76 | QChronoTimer tokenPollingTimer; 77 | QPointer currentAuthorizationReply; 78 | QPointer currentTokenReply; 79 | }; 80 | 81 | QT_END_NAMESPACE 82 | 83 | #endif // QOAUTH2DEVICEAUTHORIZATIONFLOW_P_H 84 | -------------------------------------------------------------------------------- /src/oauth/doc/snippets/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | 6 | project(networkauth_oauth_snippets) 7 | 8 | find_package(Qt6 REQUIRED COMPONENTS Core NetworkAuth Gui Widgets) 9 | find_package(Qt6 OPTIONAL_COMPONENTS Quick WebEngineWidgets WebEngineQuick QUIET) 10 | 11 | qt_standard_project_setup(REQUIRES 6.9) 12 | 13 | add_executable(networkauth_oauth_snippets 14 | main.cpp 15 | src_oauth_replyhandlers_p.h src_oauth_replyhandlers.cpp 16 | ) 17 | 18 | set_target_properties(networkauth_oauth_snippets PROPERTIES 19 | WIN32_EXECUTABLE TRUE 20 | MACOSX_BUNDLE TRUE 21 | ) 22 | 23 | target_link_libraries(networkauth_oauth_snippets 24 | PRIVATE 25 | Qt6::Core 26 | Qt6::NetworkAuth 27 | Qt6::Gui 28 | Qt6::Widgets 29 | ) 30 | 31 | if(TARGET Qt6::WebEngineWidgets) 32 | target_link_libraries(networkauth_oauth_snippets 33 | PRIVATE 34 | Qt6::WebEngineWidgets 35 | ) 36 | else() 37 | message("QtWebEngineWidgets not available, using QWebEngineView as user-agent not possible") 38 | endif() 39 | 40 | if(TARGET Qt6::Quick AND TARGET Qt6::WebEngineQuick) 41 | target_link_libraries(networkauth_oauth_snippets 42 | PRIVATE 43 | Qt6::Quick 44 | Qt6::WebEngineQuick 45 | ) 46 | else() 47 | message("QtWebEngineQuick not available, using WebEngineView as user-agent not possible") 48 | endif() 49 | 50 | # Check if jwt-cpp is available (it's a headers-only library => copy the project's include dir). 51 | # Also check if we have OpenSSL, as jwt-cpp relies on it 52 | #! [oidc-jwt-cpp-available-cmake] 53 | find_package(OpenSSL 1.0.0 QUIET) 54 | set(JWT_CPP_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include") 55 | if(OPENSSL_FOUND AND EXISTS "${JWT_CPP_INCLUDE_DIR}/jwt-cpp/jwt.h") 56 | #! [oidc-jwt-cpp-available-cmake] 57 | message("Found OpenSSL version ${OPENSSL_VERSION}, and jwt-cpp: ${JWT_CPP_INCLUDE_DIR}") 58 | message("Enabling jwt-cpp support") 59 | #! [oidc-jwt-cpp-link-and-include-cmake] 60 | target_include_directories(networkauth_oauth_snippets PRIVATE "${JWT_CPP_INCLUDE_DIR}") 61 | target_link_libraries(networkauth_oauth_snippets PRIVATE OpenSSL::SSL OpenSSL::Crypto) 62 | target_compile_definitions(networkauth_oauth_snippets PRIVATE JWT_CPP_AVAILABLE) 63 | #! [oidc-jwt-cpp-link-and-include-cmake] 64 | else() 65 | message("jwt-cpp support not available (check if OpenSSL and " 66 | "${JWT_CPP_INCLUDE_DIR}/jwt-cpp/jwt.h are available)") 67 | endif() 68 | 69 | if(TARGET Qt6::Quick AND TARGET Qt6::WebEngineQuick) 70 | qt_add_qml_module(networkauth_oauth_snippets 71 | URI OAuthSnippets 72 | VERSION 1.0 73 | SOURCES 74 | src_oauth_replyhandlers_p.h src_oauth_replyhandlers.cpp 75 | QML_FILES 76 | MainWindow.qml 77 | ) 78 | endif() 79 | -------------------------------------------------------------------------------- /src/oauth/doc/snippets/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "src_oauth_replyhandlers_p.h" 5 | 6 | #include 7 | 8 | #ifdef QT_QML_LIB 9 | #include 10 | #endif 11 | 12 | #include 13 | #include 14 | 15 | using namespace Qt::StringLiterals; 16 | 17 | int main(int argc, char *argv[]) 18 | { 19 | QLoggingCategory::setFilterRules(u"qt.networkauth* = true"_s); 20 | QApplication app(argc, argv); 21 | #ifdef QT_QML_LIB 22 | QQmlApplicationEngine engine; 23 | #endif 24 | 25 | QCommandLineParser parser; 26 | // For example: ./networkauth_oauth_snippets --agent widgets --scheme https 27 | QCommandLineOption agentOption({u"agent"_s}, 28 | u"Whether to use WebEngine 'widgets', WebEngine 'qml', or 'system' Browser"_s, 29 | u"Agent"_s, u"system"_s); 30 | QCommandLineOption schemeOption({u"scheme"_s}, u"Whether to use 'http', 'https', 'custom', "_s 31 | u"'deviceflow', or 'https-localhost'"_s, 32 | u"URI scheme"_s, u"http"_s); 33 | parser.addOptions({{agentOption}, {schemeOption}}); 34 | parser.addHelpOption(); 35 | parser.process(app); 36 | auto agent = parser.value(agentOption); 37 | auto scheme = parser.value(schemeOption); 38 | 39 | HttpExample httpExample; 40 | UriSchemeExample uriSchemeExample; 41 | 42 | if (agent == u"qml"_s && scheme == u"http"_s) { 43 | #ifdef QT_WEBENGINEQUICK_LIB 44 | QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &app, 45 | []() { QCoreApplication::exit(1); }, Qt::QueuedConnection); 46 | engine.loadFromModule("OAuthSnippets", "MainWindow"); 47 | #else 48 | qWarning("QtWebEngine not available"); 49 | #endif 50 | } else if (agent == u"system"_s && scheme == u"http"_s) { 51 | httpExample.setupSystemBrowser(); 52 | } else if (agent == u"system"_s && scheme == u"https-localhost"_s) { 53 | httpExample.setupSystemBrowserLocalHostHttps(); 54 | } else if (agent == u"system"_s && scheme == u"custom"_s) { 55 | uriSchemeExample.setupSystemBrowserCustom(); 56 | } else if (agent == u"widgets"_s && scheme == u"custom") { 57 | uriSchemeExample.setupWebEngineWidgetsCustom(); 58 | } else if (agent == u"widgets"_s && scheme == u"https") { 59 | uriSchemeExample.setupWebEngineWidgetsHttps(); 60 | } else if (agent == u"widgets"_s && scheme == u"http"_s) { 61 | httpExample.setupWebEngineWidgets(); 62 | } else if (scheme == u"deviceflow"_s) { 63 | httpExample.setupDeviceFlow(); 64 | } else { 65 | qDebug() << "Currently unsupported option combination:" << agent << scheme; 66 | return EXIT_FAILURE; 67 | } 68 | return app.exec(); 69 | } 70 | -------------------------------------------------------------------------------- /tests/manual/examples/twittertimeline/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "ui_twitterdialog.h" 5 | #include "twittertimelinemodel.h" 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char **argv) 17 | { 18 | QApplication app(argc, argv); 19 | 20 | app.setApplicationName("Twitter Timeline"); 21 | app.setApplicationDisplayName("Twitter Timeline"); 22 | app.setOrganizationDomain("qt.io"); 23 | app.setOrganizationName("The Qt Company"); 24 | 25 | QCommandLineParser parser; 26 | QCommandLineOption token(QStringList() << "k" << "consumer-key", 27 | "Application consumer key", "key"); 28 | QCommandLineOption secret(QStringList() << "s" << "consumer-secret", 29 | "Application consumer secret", "secret"); 30 | QCommandLineOption connect(QStringList() << "c" << "connect", 31 | "Connects to twitter. Requires consumer-key and consumer-secret"); 32 | 33 | parser.addOptions({ token, secret, connect }); 34 | parser.process(app); 35 | 36 | struct TwitterDialog : QDialog, Ui::TwitterDialog { 37 | TwitterTimelineModel model; 38 | 39 | TwitterDialog() 40 | : QDialog() 41 | { 42 | setupUi(this); 43 | view->setModel(&model); 44 | view->horizontalHeader()->hideSection(0); 45 | view->horizontalHeader()->hideSection(1); 46 | } 47 | } twitterDialog; 48 | 49 | const auto authenticate = [&]() { 50 | const auto clientIdentifier = twitterDialog.clientIdLineEdit->text(); 51 | const auto clientSharedSecret = twitterDialog.clientSecretLineEdit->text(); 52 | twitterDialog.model.authenticate(std::make_pair(clientIdentifier, clientSharedSecret)); 53 | }; 54 | const auto buttonSlot = [&]() { 55 | if (twitterDialog.model.status() == Twitter::Status::Granted) 56 | twitterDialog.model.updateTimeline(); 57 | else 58 | authenticate(); 59 | }; 60 | 61 | twitterDialog.clientIdLineEdit->setText(parser.value(token)); 62 | twitterDialog.clientSecretLineEdit->setText(parser.value(secret)); 63 | if (parser.isSet(connect)) { 64 | if (parser.value(token).isEmpty() || parser.value(secret).isEmpty()) { 65 | parser.showHelp(); 66 | } else { 67 | authenticate(); 68 | twitterDialog.view->setFocus(); 69 | } 70 | } 71 | 72 | QObject::connect(twitterDialog.pushButton, &QPushButton::clicked, buttonSlot); 73 | QObject::connect(&twitterDialog.model, &TwitterTimelineModel::authenticated, 74 | std::bind(&QPushButton::setText, twitterDialog.pushButton, "&Update")); 75 | 76 | twitterDialog.show(); 77 | return app.exec(); 78 | } 79 | -------------------------------------------------------------------------------- /tests/auto/shared/oauthtestutils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #include "oauthtestutils.h" 5 | 6 | #ifndef QT_NO_SSL 7 | #include 8 | #include 9 | #endif 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | QString createSignedJWT(const QVariantMap &header, const QVariantMap &payload) 16 | { 17 | auto base64Encode = [](const QByteArray &input) { 18 | return input.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); 19 | }; 20 | // Repeating values which can be overridden and augmented by the supplied 'header' and 'payload' 21 | QVariantMap mergedHeader = {{"alg", "HS256"}, 22 | {"typ", "JWT"}}; 23 | QVariantMap mergedPayload = {{"iss", "https://tst_oauth2.example.com"}, 24 | {"sub", "tst_oauth2"}, 25 | {"aud", "tst_oauth2_client_id"}, 26 | {"exp", QDateTime::currentSecsSinceEpoch() + 300}, // valid 5 mins 27 | {"iat", QDateTime::currentSecsSinceEpoch()}, // issued now 28 | {"name", "No Body"}, 29 | {"email", "no.body@example.com"}}; 30 | mergedHeader.insert(header); 31 | mergedPayload.insert(payload); 32 | 33 | // Signed JWT within OIDC context is: header.payload.signature (separated with dots) 34 | auto header64 = 35 | base64Encode(QJsonDocument::fromVariant(mergedHeader).toJson(QJsonDocument::Compact)); 36 | auto payload64 = 37 | base64Encode(QJsonDocument::fromVariant(mergedPayload).toJson(QJsonDocument::Compact)); 38 | auto token = header64 + "." + payload64; 39 | auto signature64 = 40 | base64Encode(QMessageAuthenticationCode::hash(token, "secret", QCryptographicHash::Sha256)); 41 | token = token + "." + signature64; 42 | return token; 43 | } 44 | 45 | #ifndef QT_NO_SSL 46 | QSslConfiguration createSslConfiguration(const QString &keyFileName, 47 | const QString &certificateFileName) 48 | { 49 | QSslConfiguration configuration(QSslConfiguration::defaultConfiguration()); 50 | 51 | QFile keyFile(keyFileName); 52 | if (keyFile.open(QIODevice::ReadOnly)) { 53 | QSslKey key(keyFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); 54 | if (!key.isNull()) { 55 | configuration.setPrivateKey(key); 56 | } else { 57 | qCritical() << "Could not parse key: " << keyFileName; 58 | } 59 | } else { 60 | qCritical() << "Could not find key: " << keyFileName; 61 | } 62 | 63 | QList localCert = QSslCertificate::fromPath(certificateFileName); 64 | if (!localCert.isEmpty() && !localCert.first().isNull()) { 65 | configuration.setLocalCertificate(localCert.first()); 66 | } else { 67 | qCritical() << "Could not find certificate: " << certificateFileName; 68 | } 69 | 70 | configuration.setPeerVerifyMode(QSslSocket::VerifyPeer); 71 | 72 | return configuration; 73 | } 74 | #endif // QT_NO_SSL 75 | -------------------------------------------------------------------------------- /src/oauth/doc/snippets/src_oauth_replyhandlers_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef QT_WEBENGINEWIDGETS_LIB 10 | #include 11 | #include 12 | #endif 13 | 14 | #include 15 | #include 16 | 17 | #ifdef QT_QML_LIB 18 | #include 19 | #endif 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | using namespace Qt::StringLiterals; 29 | 30 | //! [webengine-qml-control] 31 | class HttpExample : public QObject 32 | { 33 | Q_OBJECT 34 | #ifdef QT_QML_LIB 35 | QML_NAMED_ELEMENT(OAuth2) 36 | #endif 37 | public: 38 | Q_INVOKABLE void authorize(); 39 | 40 | signals: 41 | void authorizationCompleted(bool success); 42 | void authorizeWithBrowser(const QUrl &url); 43 | //! [webengine-qml-control] 44 | 45 | public: 46 | HttpExample(); 47 | void setupSystemBrowser(); 48 | void setupSystemBrowserLocalHostHttps(); 49 | void setupWebEngineWidgets(); 50 | void setupDeviceFlow(); 51 | 52 | void readOIDCConfiguration(const QUrl &url); 53 | void readJSONWebKeySet(const QUrl &url); 54 | void readUserInfo(const QUrl &url) const; 55 | bool verifyIDToken() const; 56 | 57 | private: 58 | //! [httpserver-variables] 59 | QOAuth2AuthorizationCodeFlow m_oauth; 60 | QOAuthHttpServerReplyHandler *m_handler = nullptr; 61 | //! [httpserver-variables] 62 | QNetworkRequestFactory m_api; 63 | QRestAccessManager *m_network = nullptr; 64 | #ifdef QT_WEBENGINEWIDGETS_LIB 65 | QWebEngineView *webView = nullptr; 66 | QMainWindow mainWindow; 67 | #endif 68 | std::optional m_jwks; 69 | 70 | //! [deviceflow-variables] 71 | QOAuth2DeviceAuthorizationFlow m_deviceFlow; 72 | //! [deviceflow-variables] 73 | 74 | //! [oidc-id-token-struct] 75 | struct IDToken { 76 | QJsonObject header; 77 | QJsonObject payload; 78 | QByteArray signature; 79 | }; 80 | //! [oidc-id-token-struct] 81 | std::optional m_oidcConfig; 82 | 83 | //! [oidc-id-token-parser-declaration] 84 | std::optional parseIDToken(const QString &token) const; 85 | //! [oidc-id-token-parser-declaration] 86 | }; 87 | 88 | class UriSchemeExample : public QObject 89 | { 90 | Q_OBJECT 91 | public: 92 | UriSchemeExample(); 93 | void setupSystemBrowserCustom(); 94 | void setupWebEngineWidgetsCustom(); 95 | void setupWebEngineWidgetsHttps(); 96 | 97 | private: 98 | //! [uri-variables] 99 | QOAuth2AuthorizationCodeFlow m_oauth; 100 | QOAuthUriSchemeReplyHandler m_handler; 101 | //! [uri-variables] 102 | QNetworkRequestFactory m_api; 103 | #ifdef QT_WEBENGINEWIDGETS_LIB 104 | //! [webengine-widget-variables] 105 | QWebEngineView *webView = nullptr; 106 | QMainWindow mainWindow; 107 | //! [webengine-widget-variables] 108 | #endif 109 | }; 110 | -------------------------------------------------------------------------------- /src/oauth/qoauth1_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | // 5 | // W A R N I N G 6 | // ------------- 7 | // 8 | // This file is not part of the Qt API. It exists for the convenience 9 | // of the Network Access API. This header file may change from 10 | // version to version without notice, or even be removed. 11 | // 12 | // We mean it. 13 | // 14 | 15 | #ifndef QOAUTH1_P_H 16 | #define QOAUTH1_P_H 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | QT_BEGIN_NAMESPACE 33 | 34 | class QOAuth1Signature; 35 | 36 | class QOAuth1Private : public QAbstractOAuthPrivate 37 | { 38 | public: 39 | Q_DECLARE_PUBLIC(QOAuth1) 40 | 41 | QOAuth1Private(const std::pair &clientCredentials, 42 | QNetworkAccessManager *networkAccessManager = nullptr); 43 | 44 | void appendCommonHeaders(QVariantMap *headers); 45 | void appendSignature(QAbstractOAuth::Stage stage, 46 | QVariantMap *headers, 47 | const QUrl &url, 48 | QNetworkAccessManager::Operation operation, 49 | const QMultiMap parameters); 50 | 51 | QNetworkReply *requestToken(QNetworkAccessManager::Operation operation, 52 | const QUrl &url, 53 | const std::pair &token, 54 | const QVariantMap &additionalParameters); 55 | 56 | QString signatureMethodString() const; 57 | QByteArray generateSignature(const QMultiMap ¶meters, 58 | const QUrl &url, 59 | QNetworkAccessManager::Operation operation) const; 60 | QByteArray generateSignature(const QMultiMap ¶meters, 61 | const QUrl &url, 62 | const QByteArray &verb) const; 63 | QByteArray formatSignature(const QOAuth1Signature &signature) const; 64 | 65 | QVariantMap createOAuthBaseParams() const; 66 | 67 | void _q_onTokenRequestError(QNetworkReply::NetworkError error); 68 | void _q_tokensReceived(const QVariantMap &tokens); 69 | 70 | QString clientIdentifierSharedKey; 71 | QString tokenSecret; 72 | QString verifier; 73 | QUrl temporaryCredentialsUrl; 74 | QUrl tokenCredentialsUrl; 75 | QOAuth1::SignatureMethod signatureMethod = QOAuth1::SignatureMethod::Hmac_Sha1; 76 | const QString oauthVersion = QStringLiteral("1.0"); 77 | bool tokenRequested = false; 78 | 79 | struct OAuth1KeyString 80 | { 81 | static const QString oauthCallback; 82 | static const QString oauthCallbackConfirmed; 83 | static const QString oauthConsumerKey; 84 | static const QString oauthNonce; 85 | static const QString oauthSignature; 86 | static const QString oauthSignatureMethod; 87 | static const QString oauthTimestamp; 88 | static const QString oauthToken; 89 | static const QString oauthTokenSecret; 90 | static const QString oauthVerifier; 91 | static const QString oauthVersion; 92 | }; 93 | }; 94 | 95 | QT_END_NAMESPACE 96 | 97 | #endif // QOAUTH1_P_H 98 | -------------------------------------------------------------------------------- /src/oauth/doc/src/qtnetworkauth.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \page qtnetworkauth-index.html 6 | \title Qt Network Authorization 7 | \brief Provides network authorization capabilities (OAuth). 8 | 9 | Qt Network Authorization provides a set of APIs that enable Qt 10 | applications to implement common authorization and authentication protocols. 11 | For example, an application can implement access controls such as providing 12 | limited access to online accounts and HTTP services without exposing user 13 | passwords. 14 | 15 | This module focuses on \l{OAuth 2.0} and provides limited support for 16 | \l{OpenID}. Refer to the section below about 17 | \l{Supported Authorization and Authentication Protocols} 18 | {supported protocols}. 19 | 20 | \section1 Using the Module 21 | 22 | Using a Qt module requires linking against the module library, either 23 | directly or through other dependencies. Several build tools have dedicated 24 | support for this, including CMake and qmake. 25 | 26 | \section2 Building with CMake 27 | 28 | Use the \c find_package() command to locate the needed module components in 29 | the Qt6 package: 30 | 31 | \badcode 32 | find_package(Qt6 REQUIRED COMPONENTS NetworkAuth) 33 | target_link_libraries(mytarget PRIVATE Qt6::NetworkAuth) 34 | \endcode 35 | 36 | See also the \l{Build with CMake} overview. 37 | 38 | \section2 Building with qmake 39 | 40 | To configure the module for building with qmake, add the module as a value 41 | of the QT variable in the project's .pro file: 42 | 43 | \badcode 44 | QT += networkauth 45 | \endcode 46 | 47 | \section1 Supported Authorization and Authentication Protocols 48 | 49 | Qt Network Authorization module supports functionalities from: 50 | 51 | \list 52 | \li \l {OAuth 1} 53 | \li \l {OAuth 2.0} 54 | \li \l {OpenID} 55 | \li \l {OpenID Connect} 56 | \endlist 57 | 58 | These systems use a trusted \e {authorization server} for issuing access 59 | tokens so that users do not send credentials to resources and resource 60 | owners do not directly manage user credentials. For example, a user of a 61 | cloud-based photo album website does not have to worry about passing their 62 | credentials to the website. Instead, the credentials are 63 | managed by a trusted authorization service through a web interface. 64 | 65 | \section1 Articles and Guides 66 | 67 | \list 68 | \li \l {OAuth 2.0 Overview} 69 | \li \l {Qt OAuth2 Browser Support} 70 | \li \l {Qt Network Authorization Security Considerations} 71 | {Security Considerations} 72 | \endlist 73 | 74 | \section1 Licenses 75 | 76 | Qt Network Authorization is available under commercial licenses from 77 | \l{The Qt Company}. In addition, it is available under the 78 | \l{GNU General Public License, version 3}. 79 | See \l{Qt Licensing} for further details. 80 | 81 | \section1 Examples 82 | \list 83 | \li \l {Qt Network Authorization Examples} 84 | \endlist 85 | 86 | \section1 API Reference 87 | \list 88 | \li \l{Qt Network Authorization C++ Classes}{C++ Classes} 89 | \endlist 90 | */ 91 | 92 | /*! 93 | \module QtNetworkAuth 94 | \title Qt Network Authorization C++ Classes 95 | \ingroup modules 96 | \qtcmakepackage NetworkAuth 97 | \qtvariable networkauth 98 | \brief Provides classes for network authorization support (OAuth). 99 | */ 100 | -------------------------------------------------------------------------------- /src/oauth/qoauth2authorizationcodeflow.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QOAUTH2AUTHORIZATIONCODEFLOW_H 5 | #define QOAUTH2AUTHORIZATIONCODEFLOW_H 6 | 7 | #include 8 | 9 | #ifndef QT_NO_HTTP 10 | 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | class QUrl; 16 | class QString; 17 | class QNetworkAccessManager; 18 | 19 | class QOAuth2AuthorizationCodeFlowPrivate; 20 | class Q_OAUTH_EXPORT QOAuth2AuthorizationCodeFlow : public QAbstractOAuth2 21 | { 22 | Q_OBJECT 23 | #if QT_DEPRECATED_SINCE(6, 13) 24 | Q_PROPERTY(QUrl accessTokenUrl 25 | READ accessTokenUrl 26 | WRITE setAccessTokenUrl 27 | NOTIFY accessTokenUrlChanged) 28 | #endif 29 | Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") 30 | 31 | public: 32 | explicit QOAuth2AuthorizationCodeFlow(QObject *parent = nullptr); 33 | explicit QOAuth2AuthorizationCodeFlow(QNetworkAccessManager *manager, 34 | QObject *parent = nullptr); 35 | 36 | QOAuth2AuthorizationCodeFlow(const QString &clientIdentifier, 37 | QNetworkAccessManager *manager, 38 | QObject *parent = nullptr); 39 | 40 | QOAuth2AuthorizationCodeFlow(const QUrl &authorizationUrl, 41 | const QUrl &accessTokenUrl, 42 | QNetworkAccessManager *manager, 43 | QObject *parent = nullptr); 44 | 45 | QOAuth2AuthorizationCodeFlow(const QString &clientIdentifier, 46 | const QUrl &authorizationUrl, 47 | const QUrl &accessTokenUrl, 48 | QNetworkAccessManager *manager, 49 | QObject *parent = nullptr); 50 | 51 | ~QOAuth2AuthorizationCodeFlow(); 52 | 53 | #if QT_DEPRECATED_SINCE(6, 13) 54 | QT_DEPRECATED_VERSION_X_6_13("Use QAbstractOAuth2::tokenUrl() instead.") 55 | QUrl accessTokenUrl() const; 56 | QT_DEPRECATED_VERSION_X_6_13("Use QAbstractOAuth2::setTokenUrl() instead.") 57 | void setAccessTokenUrl(const QUrl &accessTokenUrl); 58 | #endif 59 | 60 | enum class PkceMethod : quint8 { 61 | S256, 62 | Plain, 63 | None = 255, 64 | }; 65 | Q_ENUM(PkceMethod) 66 | 67 | void setPkceMethod(PkceMethod method, qsizetype length = 43) ; 68 | PkceMethod pkceMethod() const noexcept; 69 | 70 | public Q_SLOTS: 71 | void grant() override; 72 | #if QT_DEPRECATED_SINCE(6, 13) 73 | QT_DEPRECATED_VERSION_X_6_13("Use QAbstractOAuth2::refreshTokens() instead") 74 | void refreshAccessToken(); 75 | #endif 76 | 77 | protected Q_SLOTS: 78 | void refreshTokensImplementation() QT7_ONLY(override); 79 | 80 | protected: 81 | QUrl buildAuthenticateUrl(const QMultiMap ¶meters = {}); 82 | void requestAccessToken(const QString &code); 83 | void resourceOwnerAuthorization(const QUrl &url, 84 | const QMultiMap ¶meters = {}) override; 85 | 86 | Q_SIGNALS: 87 | #if QT_DEPRECATED_SINCE(6, 13) 88 | QT_MOC_COMPAT 89 | QT_DEPRECATED_VERSION_X_6_13("Use QAbstractOAuth2::tokenUrlChanged() instead.") 90 | void accessTokenUrlChanged(const QUrl &accessTokenUrl); 91 | #endif 92 | 93 | private: 94 | Q_DISABLE_COPY(QOAuth2AuthorizationCodeFlow) 95 | Q_DECLARE_PRIVATE(QOAuth2AuthorizationCodeFlow) 96 | }; 97 | 98 | QT_END_NAMESPACE 99 | 100 | #endif // QT_NO_HTTP 101 | 102 | #endif // QOAUTH2AUTHORIZATIONCODEFLOW_H 103 | -------------------------------------------------------------------------------- /examples/oauth/redditclient/redditmodel.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "redditmodel.h" 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | using namespace Qt::StringLiterals; 17 | 18 | static constexpr auto hotUrl = "https://oauth.reddit.com/hot"_L1; 19 | static constexpr auto authorizationUrl = "https://www.reddit.com/api/v1/authorize"_L1; 20 | static constexpr auto accessTokenUrl = "https://www.reddit.com/api/v1/access_token"_L1; 21 | 22 | RedditModel::RedditModel(QObject *parent) : QAbstractTableModel(parent) {} 23 | 24 | RedditModel::RedditModel(const QString &clientId, QObject *parent) : 25 | QAbstractTableModel(parent) 26 | { 27 | QNetworkAccessManager *qnam = new QNetworkAccessManager(this); 28 | network = new QRestAccessManager(qnam, qnam); 29 | 30 | redditApi.setBaseUrl(QUrl(hotUrl)); 31 | 32 | auto replyHandler = new QOAuthHttpServerReplyHandler(QHostAddress::Any, 1337, this); 33 | oauth2.setReplyHandler(replyHandler); 34 | oauth2.setAuthorizationUrl(QUrl(authorizationUrl)); 35 | oauth2.setTokenUrl(QUrl(accessTokenUrl)); 36 | oauth2.setRequestedScopeTokens({"identity", "read"}); 37 | oauth2.setClientIdentifier(clientId); 38 | 39 | QObject::connect(&oauth2, &QAbstractOAuth::granted, this, [this] { 40 | redditApi.setBearerToken(oauth2.token().toLatin1()); 41 | updateHotThreads(); 42 | }); 43 | connect(&oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, this, 44 | &QDesktopServices::openUrl); 45 | oauth2.grant(); 46 | } 47 | 48 | int RedditModel::rowCount(const QModelIndex &parent) const 49 | { 50 | Q_UNUSED(parent); 51 | return threads.size(); 52 | } 53 | 54 | int RedditModel::columnCount(const QModelIndex &parent) const 55 | { 56 | Q_UNUSED(parent); 57 | return threads.size() ? 1 : 0; 58 | } 59 | 60 | QVariant RedditModel::data(const QModelIndex &index, int role) const 61 | { 62 | Q_UNUSED(role); 63 | if (!index.isValid()) 64 | return QVariant(); 65 | 66 | if (role == Qt::DisplayRole) { 67 | const auto childrenObject = threads.at(index.row()); 68 | Q_ASSERT(childrenObject.value("data"_L1).isObject()); 69 | const auto dataObject = childrenObject.value("data"_L1).toObject(); 70 | return dataObject.value("title"_L1).toString(); 71 | } 72 | return QVariant(); 73 | } 74 | 75 | void RedditModel::updateHotThreads() 76 | { 77 | network->get(redditApi.createRequest(), this, [this](QRestReply &reply) { 78 | if (!reply.isSuccess()) { 79 | emit error(reply.errorString()); 80 | return; 81 | } 82 | const auto document = reply.readJson(); 83 | Q_ASSERT(document && document->isObject()); 84 | const auto rootObject = document->object(); 85 | Q_ASSERT(rootObject.value("kind"_L1).toString() == "Listing"_L1); 86 | const auto dataValue = rootObject.value("data"_L1); 87 | Q_ASSERT(dataValue.isObject()); 88 | const auto dataObject = dataValue.toObject(); 89 | const auto childrenValue = dataObject.value("children"_L1); 90 | Q_ASSERT(childrenValue.isArray()); 91 | const auto childrenArray = childrenValue.toArray(); 92 | 93 | if (childrenArray.isEmpty()) 94 | return; 95 | 96 | beginInsertRows(QModelIndex(), threads.size(), childrenArray.size() + threads.size() - 1); 97 | for (const auto childValue : std::as_const(childrenArray)) { 98 | Q_ASSERT(childValue.isObject()); 99 | threads.append(childValue.toObject()); 100 | } 101 | endInsertRows(); 102 | }); 103 | } 104 | -------------------------------------------------------------------------------- /src/oauth/qabstractoauthreplyhandler.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #include "qabstractoauthreplyhandler.h" 5 | #include "qabstractoauthreplyhandler_p.h" 6 | 7 | QT_BEGIN_NAMESPACE 8 | 9 | Q_LOGGING_CATEGORY(lcReplyHandler, "qt.networkauth.replyhandler") 10 | 11 | /*! 12 | \class QAbstractOAuthReplyHandler 13 | \inmodule QtNetworkAuth 14 | \ingroup oauth 15 | \brief Handles replies to OAuth authentication requests. 16 | \since 5.8 17 | 18 | The QAbstractOAuthReplyHandler class handles the answers 19 | to all OAuth authentication requests. 20 | This class is designed as a base whose subclasses implement 21 | custom behavior in the callback() and networkReplyFinished() 22 | methods. 23 | */ 24 | 25 | /*! 26 | \fn QString QAbstractOAuthReplyHandler::callback() const 27 | 28 | Returns an absolute URI that the server will redirect the 29 | resource owner back to when the Resource Owner Authorization step 30 | is completed. If the client is unable to receive callbacks or a 31 | callback URI has been established via other means, the parameter 32 | value \b must be set to "oob" (all lower-case), to indicate an 33 | out-of-band configuration. 34 | 35 | Derived classes should implement this function to provide the 36 | expected callback type. 37 | */ 38 | 39 | /*! 40 | \fn void QAbstractOAuthReplyHandler::networkReplyFinished(QNetworkReply *reply) 41 | 42 | After the server determines whether the request is valid this 43 | function will be called. Reimplement it to get the data received 44 | from the server wrapped in \a reply. \a reply will be automatically 45 | deleted using deleteLater(), it thus must not be stored beyond the 46 | scope of this function. 47 | 48 | */ 49 | 50 | /*! 51 | \fn void QAbstractOAuthReplyHandler::callbackReceived(const QVariantMap &values) 52 | 53 | This signal is emitted when the reply from the server is 54 | received, with \a values containing the token credentials 55 | and any additional information the server may have returned. 56 | When this signal is emitted, the authorization process 57 | is complete. 58 | */ 59 | 60 | /*! 61 | \fn void QAbstractOAuthReplyHandler::tokensReceived(const QVariantMap &tokens) 62 | 63 | This signal is emitted when new \a tokens are received from the 64 | server. 65 | */ 66 | 67 | /*! 68 | 69 | \fn void QAbstractOAuthReplyHandler::tokenRequestErrorOccurred(QAbstractOAuth::Error error, 70 | const QString& errorString) 71 | 72 | This signal is emitted when a token request or refresh \a error has 73 | occurred. The \a errorString may provide further details on the error. 74 | 75 | \sa QAbstractOAuth::requestFailed() 76 | \since 6.6 77 | */ 78 | 79 | /*! 80 | \fn void QAbstractOAuthReplyHandler::replyDataReceived(const QByteArray &data) 81 | 82 | This signal is emitted when an HTTP request finishes and the 83 | data is available. \a data contains the response before parsing. 84 | */ 85 | 86 | /*! 87 | \fn void QAbstractOAuthReplyHandler::callbackDataReceived(const QByteArray &data) 88 | 89 | This signal is emitted when a callback request is received: 90 | \a data contains the information before parsing. 91 | */ 92 | 93 | /*! 94 | Constructs a reply handler as a child of \a parent. 95 | */ 96 | QAbstractOAuthReplyHandler::QAbstractOAuthReplyHandler(QObject *parent) 97 | : QObject(parent) 98 | {} 99 | 100 | /*! 101 | Destroys the reply handler. 102 | */ 103 | QAbstractOAuthReplyHandler::~QAbstractOAuthReplyHandler() 104 | {} 105 | 106 | /*! \internal */ 107 | QAbstractOAuthReplyHandler::QAbstractOAuthReplyHandler(QObjectPrivate &d, QObject *parent) 108 | : QObject(d, parent) 109 | {} 110 | 111 | QT_END_NAMESPACE 112 | -------------------------------------------------------------------------------- /tests/auto/abstractoauth/tst_abstractoauth.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | class tst_AbstractOAuth : public QObject 13 | { 14 | Q_OBJECT 15 | 16 | private: 17 | struct AbstractOAuthPrivate : public QAbstractOAuthPrivate { 18 | AbstractOAuthPrivate() : QAbstractOAuthPrivate("", QUrl(), QString(), nullptr) 19 | {} 20 | }; 21 | 22 | struct AbstractOAuth : QAbstractOAuth { 23 | AbstractOAuth() : QAbstractOAuth(*new AbstractOAuthPrivate(), 24 | nullptr) 25 | {} 26 | 27 | QNetworkReply *head(const QUrl &, const QVariantMap &) override { return nullptr; } 28 | QNetworkReply *get(const QUrl &, const QVariantMap &) override { return nullptr; } 29 | QNetworkReply *post(const QUrl &, const QVariantMap &) override { return nullptr; } 30 | QNetworkReply *put(const QUrl &, const QVariantMap &) override { return nullptr; } 31 | QNetworkReply *deleteResource(const QUrl &, const QVariantMap &) override 32 | { 33 | return nullptr; 34 | } 35 | void grant() override {} 36 | 37 | void prepareRequest(QNetworkRequest *, const QByteArray &, 38 | const QByteArray & = QByteArray()) override 39 | { 40 | } 41 | }; 42 | 43 | private Q_SLOTS: 44 | void authorizationUrlSignal(); 45 | void generateRandomString_data(); 46 | void generateRandomString(); 47 | }; 48 | 49 | void tst_AbstractOAuth::authorizationUrlSignal() 50 | { 51 | AbstractOAuth obj; 52 | QUrl expectedValue = QUrl("http://example.net/"); 53 | const QUrl defaultValue = obj.authorizationUrl(); 54 | QVERIFY(expectedValue != defaultValue); 55 | bool emitted = false; 56 | connect(&obj, &QAbstractOAuth::authorizationUrlChanged, this, [&](const QUrl &value) { 57 | QCOMPARE(expectedValue, value); 58 | emitted = true; 59 | }); 60 | obj.setAuthorizationUrl(expectedValue); 61 | QVERIFY(emitted); 62 | } 63 | 64 | void tst_AbstractOAuth::generateRandomString_data() 65 | { 66 | QTest::addColumn("length"); 67 | for (int i = 0; i <= 255; ++i) 68 | QTest::addRow("%d", i) << i; 69 | } 70 | 71 | // copied from https://xkcd.com/221/ 72 | int getRandomNumber() 73 | { 74 | return 4; // chosen by fair dice roll. 75 | // guaranteed to be random. 76 | } 77 | 78 | void tst_AbstractOAuth::generateRandomString() 79 | { 80 | struct Unprotected : public QAbstractOAuth { 81 | using QAbstractOAuth::generateRandomString; 82 | }; 83 | 84 | QFETCH(int, length); 85 | QByteArray random1 = Unprotected::generateRandomString(length); 86 | QCOMPARE(random1.size(), length); 87 | 88 | // Check that it is truly random by repeating and checking that it is 89 | // different. We don't try it for 1 and 2 characters because the chance of 90 | // random coincidence is too high: 1 in 2^(6*n), so 1 in 64 and 1 in 4096 91 | // respectively. For 3 characters, that decreases to 1 in 262,144. 92 | if (length <= 2) 93 | return; 94 | 95 | QByteArray random2 = Unprotected::generateRandomString(length); 96 | QCOMPARE_NE(random2, random1); 97 | 98 | // Generate a Base64 string using getRandomNumber() random bytes. Base64 99 | // encodes 6 bits per byte, so a 255-character string has 1530 bits of 100 | // data. 101 | char buf[192] = {}; 102 | int rawlen = (length * 6 + 7) / 8; 103 | for (int i = 0; i < rawlen; ++i) 104 | buf[i] = getRandomNumber(); 105 | QByteArray random3 = QByteArray(buf, rawlen).toBase64(QByteArray::Base64UrlEncoding); 106 | Q_ASSERT(random3.size() >= length); 107 | random3.truncate(length); 108 | QCOMPARE_NE(random3, random1); 109 | } 110 | 111 | QTEST_MAIN(tst_AbstractOAuth) 112 | #include "tst_abstractoauth.moc" 113 | -------------------------------------------------------------------------------- /src/oauth/qoauthoobreplyhandler.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | // Qt-Security score:critical reason:authorization-protocol 4 | 5 | #include "qoauthoobreplyhandler.h" 6 | #include "qoauthoobreplyhandler_p.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | using namespace Qt::StringLiterals; 19 | 20 | QOAuthOobReplyHandler::QOAuthOobReplyHandler(QObject *parent) 21 | : QAbstractOAuthReplyHandler(parent) 22 | {} 23 | 24 | /*! \internal */ 25 | QOAuthOobReplyHandler::QOAuthOobReplyHandler(QOAuthOobReplyHandlerPrivate &d, QObject *parent) 26 | : QAbstractOAuthReplyHandler(d, parent) 27 | {} 28 | 29 | QOAuthOobReplyHandler::~QOAuthOobReplyHandler() 30 | = default; // must be empty until Qt 7 (was inline until Qt 6.8) 31 | 32 | QString QOAuthOobReplyHandler::callback() const 33 | { 34 | return QStringLiteral("oob"); 35 | } 36 | 37 | void QOAuthOobReplyHandler::networkReplyFinished(QNetworkReply *reply) 38 | { 39 | QRestReply restReply(reply); 40 | 41 | if (restReply.hasError()) { 42 | emit tokenRequestErrorOccurred(QAbstractOAuth::Error::NetworkError, reply->errorString()); 43 | return; 44 | } 45 | if (!restReply.isHttpStatusSuccess()) { 46 | emit tokenRequestErrorOccurred(QAbstractOAuth::Error::ServerError, reply->errorString()); 47 | return; 48 | } 49 | if (reply->header(QNetworkRequest::ContentTypeHeader).isNull()) { 50 | emit tokenRequestErrorOccurred(QAbstractOAuth::Error::ServerError, 51 | u"Empty Content-type header"_s); 52 | return; 53 | } 54 | const QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).isNull() ? 55 | QStringLiteral("text/html") : 56 | reply->header(QNetworkRequest::ContentTypeHeader).toString(); 57 | const QByteArray data = reply->readAll(); 58 | if (data.isEmpty()) { 59 | emit tokenRequestErrorOccurred(QAbstractOAuth::Error::ServerError, u"No data received"_s); 60 | return; 61 | } 62 | 63 | Q_EMIT replyDataReceived(data); 64 | 65 | QVariantMap ret; 66 | 67 | if (contentType.startsWith(QStringLiteral("text/html")) || 68 | contentType.startsWith(QStringLiteral("application/x-www-form-urlencoded"))) { 69 | ret = parseResponse(data); 70 | } else if (contentType.startsWith(QStringLiteral("application/json")) 71 | || contentType.startsWith(QStringLiteral("text/javascript"))) { 72 | const QJsonDocument document = QJsonDocument::fromJson(data); 73 | if (!document.isObject()) { 74 | emit tokenRequestErrorOccurred(QAbstractOAuth::Error::ServerError, 75 | u"Received data is not a JSON object: %1"_s.arg(QString::fromUtf8(data))); 76 | return; 77 | } 78 | const QJsonObject object = document.object(); 79 | if (object.isEmpty()) { 80 | emit tokenRequestErrorOccurred(QAbstractOAuth::Error::ServerError, 81 | u"Received an empty JSON object"_s); 82 | return; 83 | } 84 | ret = object.toVariantMap(); 85 | } else { 86 | emit tokenRequestErrorOccurred(QAbstractOAuth::Error::ServerError, 87 | u"Unknown Content-type %1"_s.arg(contentType)); 88 | return; 89 | } 90 | 91 | Q_EMIT tokensReceived(ret); 92 | } 93 | 94 | QVariantMap QOAuthOobReplyHandler::parseResponse(const QByteArray &response) 95 | { 96 | QVariantMap ret; 97 | QUrlQuery query(QString::fromUtf8(response)); 98 | const auto queryItems = query.queryItems(QUrl::FullyDecoded); 99 | for (auto it = queryItems.begin(), end = queryItems.end(); it != end; ++it) 100 | ret.insert(it->first, it->second); 101 | return ret; 102 | } 103 | 104 | QT_END_NAMESPACE 105 | 106 | #include "moc_qoauthoobreplyhandler.cpp" 107 | -------------------------------------------------------------------------------- /src/oauth/doc/src/external-resources.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \externalpage https://datatracker.ietf.org/doc/html/rfc7636 6 | \title RFC 7636 7 | */ 8 | 9 | /*! 10 | \externalpage https://datatracker.ietf.org/doc/html/rfc6749 11 | \title RFC 6749 12 | */ 13 | 14 | /*! 15 | \externalpage https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.1 16 | \title RFC 6749 - Authorization Code 17 | */ 18 | 19 | /*! 20 | \externalpage https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.6 21 | \title RFC 6749 - redirect_uri Syntax 22 | */ 23 | 24 | /*! 25 | \externalpage https://datatracker.ietf.org/doc/html/rfc6749#section-1.5 26 | \title RFC 6749 - Refresh Token 27 | */ 28 | 29 | /*! 30 | \externalpage https://datatracker.ietf.org/doc/html/rfc6749#section-6 31 | \title RFC 6749 - Refreshing Access Tokens 32 | */ 33 | 34 | /*! 35 | \externalpage https://datatracker.ietf.org/doc/html/rfc8252 36 | \title RFC 8252 37 | */ 38 | 39 | /*! 40 | \externalpage https://datatracker.ietf.org/doc/html/rfc8252#section-6 41 | \title RFC 8252 - Authorization Request from a Native App 42 | */ 43 | 44 | /*! 45 | \externalpage https://datatracker.ietf.org/doc/html/rfc8252#section-7 46 | \title RFC 8252 - Authorization Response in a Native App 47 | */ 48 | 49 | /*! 50 | \externalpage https://datatracker.ietf.org/doc/html/rfc8252#section-7.1 51 | \title RFC 8252 - Private-Use URI Scheme Redirection 52 | */ 53 | 54 | /*! 55 | \externalpage https://datatracker.ietf.org/doc/html/rfc8252#section-7.2 56 | \title RFC 8252 - Claimed https Scheme URI Redirection 57 | */ 58 | 59 | /*! 60 | \externalpage https://datatracker.ietf.org/doc/html/rfc8252#section-7.3 61 | \title RFC 8252 - Loopback Interface Redirection 62 | */ 63 | 64 | /*! 65 | \externalpage https://datatracker.ietf.org/doc/html/rfc5849 66 | \title RFC 5849 67 | */ 68 | 69 | /*! 70 | \externalpage https://datatracker.ietf.org/doc/html/rfc8628 71 | \title RFC 8628 72 | */ 73 | 74 | /*! 75 | \externalpage https://datatracker.ietf.org/doc/html/rfc8628#section-3.3 76 | \title RFC 8628 - User Interaction 77 | */ 78 | 79 | /*! 80 | \externalpage https://oauth.net 81 | \title OAuth 82 | */ 83 | 84 | /*! 85 | \externalpage https://oauth.net/1/ 86 | \title OAuth 1 87 | */ 88 | /*! 89 | \externalpage https://oauth.net/2/ 90 | \title OAuth 2.0 91 | */ 92 | 93 | /*! 94 | \externalpage http://openid.net/ 95 | \title OpenID 96 | */ 97 | 98 | /*! 99 | \externalpage http://openid.net/connect/ 100 | \title OpenID Connect 101 | */ 102 | 103 | /*! 104 | \externalpage https://openid.net/specs/openid-connect-core-1_0-final.html 105 | \title OpenID Connect Core 106 | */ 107 | 108 | /*! 109 | \externalpage https://openid.net/specs/openid-connect-core-1_0-final.html#IDTokenValidation 110 | \title OpenID Connect ID Validation 111 | */ 112 | 113 | /*! 114 | \externalpage https://openid.net/specs/openid-connect-discovery-1_0.html 115 | \title OpenID Connect Discovery 116 | */ 117 | 118 | /*! 119 | \externalpage https://openid.net/specs/openid-connect-core-1_0-final.html#UserInfo 120 | \title OpenID Connect UserInfo Endpoint 121 | */ 122 | 123 | /*! 124 | \externalpage https://datatracker.ietf.org/doc/html/rfc6750 125 | \title RFC 6750 126 | */ 127 | 128 | /*! 129 | \externalpage https://datatracker.ietf.org/doc/html/rfc6750#section-2.1 130 | \title RFC 6750 - Header Field 131 | */ 132 | 133 | /*! 134 | \externalpage https://datatracker.ietf.org/doc/html/rfc7516 135 | \title JSON Web Encryption (JWE) 136 | */ 137 | 138 | /*! 139 | \externalpage https://datatracker.ietf.org/doc/html/rfc7517#section-5 140 | \title JSON Web Key (JWK) Set Format 141 | */ 142 | 143 | /*! 144 | \externalpage https://datatracker.ietf.org/doc/html/rfc7519 145 | \title JSON Web Token (JWT) 146 | */ 147 | 148 | /*! 149 | \externalpage https://jwt.io/libraries 150 | \title Third-party JWT Libraries 151 | */ 152 | 153 | /*! 154 | \externalpage https://github.com/Thalhammer/jwt-cpp 155 | \title jwt-cpp 156 | */ 157 | -------------------------------------------------------------------------------- /tests/auto/shared/tlswebserver.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #include "tlswebserver.h" 5 | 6 | #ifndef QT_NO_SSL 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | TlsWebServer::TlsWebServer(Handler h, const QSslConfiguration &config, QObject *parent) : 15 | QSslServer(parent), 16 | handler(h) 17 | { 18 | connect(this, &QSslServer::pendingConnectionAvailable, this, [this]() { 19 | auto socket = nextPendingConnection(); 20 | Q_ASSERT(socket); 21 | auto sslSocket = qobject_cast(socket); 22 | Q_ASSERT(sslSocket); 23 | connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater); 24 | connect(sslSocket, &QSslSocket::sslErrors, this, [sslSocket](const QList &errors) { 25 | qDebug() << errors; 26 | sslSocket->ignoreSslErrors(); 27 | }); 28 | connect(socket, &QTcpSocket::readyRead, this, [this, socket]() { 29 | if (!clients.contains(socket)) 30 | clients[socket].port = serverPort(); 31 | 32 | auto *request = &clients[socket]; 33 | auto ok = true; 34 | 35 | while (socket->bytesAvailable()) { 36 | if (Q_LIKELY(request->state == HttpRequest::State::ReadingMethod)) 37 | if (Q_UNLIKELY(!(ok = request->readMethod(socket)))) 38 | qWarning("Invalid Method"); 39 | 40 | if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingUrl)) 41 | if (Q_UNLIKELY(!(ok = request->readUrl(socket)))) 42 | qWarning("Invalid URL"); 43 | 44 | if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingStatus)) 45 | if (Q_UNLIKELY(!(ok = request->readStatus(socket)))) 46 | qWarning("Invalid Status"); 47 | 48 | if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingHeader)) 49 | if (Q_UNLIKELY(!(ok = request->readHeaders(socket)))) 50 | qWarning("Invalid Header"); 51 | 52 | if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingBody)) 53 | if (Q_UNLIKELY(!(ok = request->readBody(socket)))) 54 | qWarning("Invalid Body"); 55 | } 56 | if (Q_UNLIKELY(!ok)) { 57 | socket->disconnectFromHost(); 58 | clients.remove(socket); 59 | } else if (Q_LIKELY(request->state == HttpRequest::State::AllDone)) { 60 | Q_ASSERT(handler); 61 | if (request->headers.contains("Host")) { 62 | const auto parts = request->headers["Host"].split(':'); 63 | request->url.setHost(parts.at(0)); 64 | if (parts.size() == 2) 65 | request->url.setPort(parts.at(1).toUInt()); 66 | } 67 | handler(*request, socket); 68 | socket->disconnectFromHost(); 69 | clients.remove(socket); 70 | } 71 | }); 72 | }); 73 | connect(this, &QSslServer::sslErrors, this, [this](QSslSocket *s, const QList &errors) { 74 | bool hasOnlyExpectedErrors = true; 75 | for (const auto &err : errors) 76 | hasOnlyExpectedErrors &= expectedSslErrors.contains(err.error()); 77 | if (hasOnlyExpectedErrors) 78 | s->ignoreSslErrors(); 79 | else 80 | qWarning() << "Got unexpected SSL errors" << errors; 81 | }); 82 | 83 | setSslConfiguration(config); 84 | const bool ok = listen(QHostAddress::LocalHost); 85 | Q_ASSERT(ok); 86 | } 87 | 88 | QUrl TlsWebServer::url(const QString &path) 89 | { 90 | using namespace Qt::StringLiterals; 91 | return QUrl(u"https://127.0.0.1:%1%2"_s.arg(serverPort()).arg(path.startsWith('/') 92 | ? path : "/" + path)); 93 | } 94 | 95 | void TlsWebServer::setExpectedSslErrors(const QSet &errors) 96 | { 97 | expectedSslErrors = errors; 98 | } 99 | 100 | #endif // !QT_NO_SSL 101 | -------------------------------------------------------------------------------- /tests/auto/shared/oauthtestutils.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef OAUTHTESTUTILS_H 5 | #define OAUTHTESTUTILS_H 6 | 7 | #include "tlswebserver.h" 8 | #include "webserver.h" 9 | 10 | #include 11 | 12 | #ifndef QT_NO_SSL 13 | #include 14 | #endif 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | [[nodiscard]] inline auto useTemporaryKeychain() 25 | { 26 | #ifndef QT_NO_SSL 27 | // Set the same environment value as CI uses, so that it's possible 28 | // to run autotests locally without macOS asking for permission to use 29 | // a private key in keychain (with TLS sockets) 30 | auto value = qEnvironmentVariable("QT_SSL_USE_TEMPORARY_KEYCHAIN"); 31 | qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); 32 | auto envRollback = qScopeGuard([value](){ 33 | if (value.isEmpty()) 34 | qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); 35 | else 36 | qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", value.toUtf8()); 37 | }); 38 | return envRollback; 39 | #else 40 | // avoid maybe-unused warnings from callers 41 | return qScopeGuard([]{}); 42 | #endif // QT_NO_SSL 43 | } 44 | 45 | QString createSignedJWT(const QVariantMap &header = {}, const QVariantMap &payload = {}); 46 | 47 | #ifndef QT_NO_SSL 48 | QSslConfiguration createSslConfiguration(const QString &keyFileName, 49 | const QString &certificateFileName); 50 | #endif // QT_NO_SSL 51 | 52 | struct ServerResponses 53 | { 54 | QByteArray authBody; 55 | QByteArray authHttpStatus; 56 | QByteArray tokenBody; 57 | QByteArray tokenHttpStatus; 58 | }; 59 | 60 | template 61 | struct TestAuthorizationServer 62 | { 63 | std::unique_ptr server; 64 | QList receivedAuthorizationRequests; 65 | QList receivedTokenRequests; 66 | ServerResponses responses; 67 | 68 | QUrl authorizationEndpoint() 69 | { 70 | Q_ASSERT(server); 71 | return server->url(QStringLiteral("authorizationEndpoint")); 72 | } 73 | 74 | QUrl tokenEndpoint() 75 | { 76 | Q_ASSERT(server); 77 | return server->url(QStringLiteral("tokenEndpoint")); 78 | } 79 | }; 80 | 81 | // Creates a local http authorization server. 82 | // The provided ServerResponses are used as the initial values. The testcase 83 | // can modify individual response members during the testcase by modifying the returned 84 | // instance's TestAuthorizationServer::responses contents. 85 | // The template is used so that the function can return either WebServer* or TlsWebServer* 86 | template 87 | std::unique_ptr> createAuthorizationServer( 88 | ServerResponses responses, Args&&... args) 89 | { 90 | auto result = std::make_unique>(); 91 | result->responses = std::move(responses); 92 | 93 | auto handler = [raw = result.get()] 94 | (const WebServer::HttpRequest &request, QTcpSocket *socket) { 95 | QByteArray replyMessage; 96 | if (request.url.path() == QLatin1StringView("/authorizationEndpoint")) { 97 | // Set received request for test cases to check 98 | raw->receivedAuthorizationRequests.append(request); 99 | replyMessage = 100 | "HTTP/1.0 " + raw->responses.authHttpStatus + "\r\n" 101 | "Content-Type: application/json; charset=\"utf-8\"\r\n" 102 | "Content-Length: " + QByteArray::number(raw->responses.authBody.size()) 103 | + "\r\n\r\n" + raw->responses.authBody; 104 | } else if (request.url.path() == QLatin1StringView("/tokenEndpoint")) { 105 | // Set received request for test cases to check 106 | raw->receivedTokenRequests.append(request); 107 | replyMessage = 108 | "HTTP/1.0 " + raw->responses.tokenHttpStatus + "\r\n" 109 | "Content-Type: application/json; charset=\"utf-8\"\r\n" 110 | "Content-Length: " + QByteArray::number(raw->responses.tokenBody.size()) 111 | + "\r\n\r\n" + raw->responses.tokenBody; 112 | } else { 113 | qFatal() << "Unsupported URL:" << request.url; 114 | } 115 | socket->write(replyMessage); 116 | }; 117 | result->server.reset(new ServerType(handler, std::forward(args)...)); 118 | return result; 119 | } 120 | 121 | #endif // OAUTHTESTUTILS_H 122 | -------------------------------------------------------------------------------- /src/oauth/qoauth1.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QOAUTH1_H 5 | #define QOAUTH1_H 6 | 7 | #include 8 | 9 | #ifndef QT_NO_HTTP 10 | 11 | #include 12 | 13 | #include 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | // ### Qt 7 consider removing the support for OAuth1 (QTBUG-124329) 18 | class QOAuth1Private; 19 | class Q_OAUTH_EXPORT QOAuth1: public QAbstractOAuth 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | enum class SignatureMethod { 25 | Hmac_Sha1, 26 | Rsa_Sha1, 27 | PlainText 28 | }; 29 | 30 | Q_ENUM(SignatureMethod) 31 | 32 | explicit QOAuth1(QObject *parent = nullptr); 33 | explicit QOAuth1(QNetworkAccessManager *manager, 34 | QObject *parent = nullptr); 35 | 36 | QOAuth1(const QString &clientIdentifier, 37 | const QString &clientSharedSecret, 38 | QNetworkAccessManager *manager, 39 | QObject *parent = nullptr); 40 | 41 | QString clientSharedSecret() const; 42 | void setClientSharedSecret(const QString &clientSharedSecret); 43 | std::pair clientCredentials() const; 44 | void setClientCredentials(const std::pair &clientCredentials); 45 | void setClientCredentials(const QString &clientIdentifier, const QString &clientSharedSecret); 46 | 47 | // Token credentials: https://tools.ietf.org/html/rfc5849#section-2.3 48 | QString tokenSecret() const; 49 | void setTokenSecret(const QString &tokenSecret); 50 | std::pair tokenCredentials() const; 51 | void setTokenCredentials(const std::pair &tokenCredentials); 52 | void setTokenCredentials(const QString &token, const QString &tokenSecret); 53 | 54 | // Temporary Credentials: https://tools.ietf.org/html/rfc5849#section-2.1 55 | QUrl temporaryCredentialsUrl() const; 56 | void setTemporaryCredentialsUrl(const QUrl &url); 57 | 58 | // Token Credentials: https://tools.ietf.org/html/rfc5849#section-2.3 59 | QUrl tokenCredentialsUrl() const; 60 | void setTokenCredentialsUrl(const QUrl &url); 61 | 62 | // Signature method: https://tools.ietf.org/html/rfc5849#section-3.4 63 | SignatureMethod signatureMethod() const; 64 | void setSignatureMethod(SignatureMethod value); 65 | 66 | void prepareRequest(QNetworkRequest *request, const QByteArray &verb, 67 | const QByteArray &body = QByteArray()) override; 68 | 69 | QNetworkReply *head(const QUrl &url, const QVariantMap ¶meters = QVariantMap()) override; 70 | QNetworkReply *get(const QUrl &url, const QVariantMap ¶meters = QVariantMap()) override; 71 | 72 | QNetworkReply *post(const QUrl &url, const QVariantMap ¶meters = QVariantMap()) override; 73 | QNetworkReply *put(const QUrl &url, const QVariantMap ¶meters = QVariantMap()) override; 74 | QNetworkReply *deleteResource(const QUrl &url, 75 | const QVariantMap ¶meters = QVariantMap()) override; 76 | 77 | public Q_SLOTS: 78 | void grant() override; 79 | void continueGrantWithVerifier(const QString &verifier); 80 | 81 | Q_SIGNALS: 82 | void signatureMethodChanged(QOAuth1::SignatureMethod method); 83 | void clientSharedSecretChanged(const QString &credential); 84 | void tokenSecretChanged(const QString &token); 85 | void temporaryCredentialsUrlChanged(const QUrl &url); 86 | void tokenCredentialsUrlChanged(const QUrl &url); 87 | 88 | protected: 89 | QNetworkReply *requestTemporaryCredentials(QNetworkAccessManager::Operation operation, 90 | const QUrl &url, 91 | const QVariantMap ¶meters = QVariantMap()); 92 | 93 | QNetworkReply *requestTokenCredentials(QNetworkAccessManager::Operation operation, 94 | const QUrl &url, 95 | const std::pair &temporaryToken, 96 | const QVariantMap ¶meters = QVariantMap()); 97 | 98 | void setup(QNetworkRequest *request, 99 | const QVariantMap &signingParameters, 100 | QNetworkAccessManager::Operation operation); 101 | void setup(QNetworkRequest *request, 102 | const QVariantMap &signingParameters, 103 | const QByteArray &operationVerb); 104 | 105 | static QByteArray nonce(); 106 | static QByteArray generateAuthorizationHeader(const QVariantMap &oauthParams); 107 | 108 | private: 109 | Q_DISABLE_COPY(QOAuth1) 110 | Q_DECLARE_PRIVATE(QOAuth1) 111 | }; 112 | 113 | QT_END_NAMESPACE 114 | 115 | #endif // QT_NO_HTTP 116 | 117 | #endif // QOAUTH1_H 118 | -------------------------------------------------------------------------------- /licenseRule.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "comment": ["file_pattern_ending: strings matched against the end of a file name.", 4 | "location keys: regular expression matched against the beginning of", 5 | "the file path (relative to the git submodule root).", 6 | "spdx: list of SPDX-License-Expression's allowed in the matching files.", 7 | "-------------------------------------------------------", 8 | "Files with the following endings are Build System licensed,", 9 | "unless they are examples", 10 | "Files with other endings can also be build system files" 11 | ], 12 | "file_pattern_ending": ["CMakeLists.txt", ".cmake", ".pro", ".pri", ".prf", 13 | "configure", "configure.bat", "cmake.in", "plist.in", "CMakeLists.txt.in", 14 | ".cmake.conf", ".tag", "ci_config_linux.json", 15 | ".yaml"], 16 | "location": { 17 | "": { 18 | "comment": "Default", 19 | "file type": "build system", 20 | "spdx": ["BSD-3-Clause"] 21 | }, 22 | "(.*)(examples/|snippets/)": { 23 | "comment": "Example takes precedence", 24 | "file type": "examples and snippets", 25 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 26 | }, 27 | "tests/manual/examples/twittertimeline/": { 28 | "comment": "test, not example", 29 | "file type": "build system", 30 | "spdx": ["BSD-3-Clause"] 31 | } 32 | } 33 | }, 34 | { 35 | "comments": ["Files with the following endings are infrastructure licensed"], 36 | "file_pattern_ending": [".gitattributes", ".gitignore", ".gitmodules", ".gitreview", 37 | "_clang-format", "licenseRule.json", "REUSE.toml"], 38 | "location":{ 39 | "": { 40 | "comment": "Default", 41 | "file type": "infrastructure", 42 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 43 | } 44 | } 45 | }, 46 | { 47 | "comments": ["Files with the following endings are Tool licensed,", 48 | "unless they are examples.", 49 | "Files with other endings can also be tool files."], 50 | "file_pattern_ending": [".sh", ".py", ".pl", ".bat", ".ps1"], 51 | "location":{ 52 | "": { 53 | "comment": "Default", 54 | "file type": "tools and utils", 55 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0"] 56 | }, 57 | "(.*)(examples/|snippets/)": { 58 | "comment": "Example takes precedence", 59 | "file type": "examples and snippets", 60 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 61 | } 62 | } 63 | }, 64 | { 65 | "comment": "Files with the following endings are Documentation licensed.", 66 | "file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf", "README", "qt_attribution.json", 67 | ".webp"], 68 | "location":{ 69 | "": { 70 | "comment": "", 71 | "file type": "documentation", 72 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"] 73 | } 74 | } 75 | }, 76 | { 77 | "comment": ["All other files", 78 | "The licensing is defined only by the file location in the Qt module repository.", 79 | "NO key for this case!", 80 | "This needs to be the last entry of the file."], 81 | "location": { 82 | "": { 83 | "comment": "Default", 84 | "file type": "module and plugin", 85 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 86 | }, 87 | "dist/": { 88 | "comment": "Default", 89 | "file type": "documentation", 90 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"] 91 | }, 92 | "src/": { 93 | "comment": "Default", 94 | "file type": "module and plugin", 95 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 96 | }, 97 | "tests/": { 98 | "comment": "Default", 99 | "file type": "test", 100 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 101 | }, 102 | "tests/manual/examples/twittertimeline/twitterdialog.ui": { 103 | "comment": "Default", 104 | "file type": "test", 105 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 106 | }, 107 | "(.*)(examples/|snippets/)": { 108 | "comment": "Default", 109 | "file type": "examples and snippets", 110 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 111 | }, 112 | "(.*|examples).*/doc/images": { 113 | "comment": "Default", 114 | "file type": "documentation", 115 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"] 116 | } 117 | } 118 | } 119 | ] 120 | -------------------------------------------------------------------------------- /src/oauth/qabstractoauth.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QABSTRACTOAUTH_H 5 | #define QABSTRACTOAUTH_H 6 | 7 | #include 8 | 9 | #ifndef QT_NO_HTTP 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | QT_BEGIN_NAMESPACE 20 | 21 | class QString; 22 | class QByteArray; 23 | class QNetworkReply; 24 | class QNetworkRequest; 25 | class QNetworkAccessManager; 26 | class QAbstractOAuthReplyHandler; 27 | 28 | class QAbstractOAuthPrivate; 29 | class Q_OAUTH_EXPORT QAbstractOAuth : public QObject 30 | { 31 | Q_OBJECT 32 | 33 | Q_PROPERTY(QString clientIdentifier 34 | READ clientIdentifier 35 | WRITE setClientIdentifier 36 | NOTIFY clientIdentifierChanged) 37 | Q_PROPERTY(QString token READ token WRITE setToken NOTIFY tokenChanged) 38 | Q_PROPERTY(Status status READ status NOTIFY statusChanged) 39 | Q_PROPERTY(QVariantMap extraTokens READ extraTokens NOTIFY extraTokensChanged) 40 | Q_PROPERTY(QUrl authorizationUrl 41 | READ authorizationUrl 42 | WRITE setAuthorizationUrl 43 | NOTIFY authorizationUrlChanged) 44 | Q_PROPERTY(QAbstractOAuth::ContentType contentType 45 | READ contentType 46 | WRITE setContentType 47 | NOTIFY contentTypeChanged) 48 | 49 | public: 50 | enum class Status { 51 | NotAuthenticated, 52 | TemporaryCredentialsReceived, 53 | Granted, 54 | RefreshingToken 55 | }; 56 | Q_ENUM(Status) 57 | 58 | enum class Stage { 59 | RequestingTemporaryCredentials, 60 | RequestingAuthorization, 61 | RequestingAccessToken, 62 | RefreshingAccessToken 63 | }; 64 | Q_ENUM(Stage) 65 | 66 | enum class Error { 67 | NoError, 68 | NetworkError, 69 | ServerError, 70 | 71 | OAuthTokenNotFoundError, 72 | OAuthTokenSecretNotFoundError, 73 | OAuthCallbackNotVerified, 74 | 75 | ClientError, 76 | ExpiredError, 77 | }; 78 | Q_ENUM(Error) 79 | 80 | enum class ContentType { 81 | WwwFormUrlEncoded, 82 | Json 83 | }; 84 | 85 | typedef std::function*)> ModifyParametersFunction; 86 | 87 | virtual ~QAbstractOAuth(); 88 | 89 | QString clientIdentifier() const; 90 | void setClientIdentifier(const QString &clientIdentifier); 91 | 92 | QString token() const; 93 | void setToken(const QString &token); 94 | 95 | QNetworkAccessManager *networkAccessManager() const; 96 | void setNetworkAccessManager(QNetworkAccessManager *networkAccessManager); 97 | 98 | Status status() const; 99 | 100 | QUrl authorizationUrl() const; 101 | void setAuthorizationUrl(const QUrl &url); 102 | 103 | QVariantMap extraTokens() const; 104 | 105 | QAbstractOAuthReplyHandler *replyHandler() const; 106 | void setReplyHandler(QAbstractOAuthReplyHandler *handler); 107 | 108 | Q_INVOKABLE virtual QNetworkReply *head(const QUrl &url, 109 | const QVariantMap ¶meters = QVariantMap()) = 0; 110 | Q_INVOKABLE virtual QNetworkReply *get(const QUrl &url, 111 | const QVariantMap ¶meters = QVariantMap()) = 0; 112 | Q_INVOKABLE virtual QNetworkReply *post(const QUrl &url, 113 | const QVariantMap ¶meters = QVariantMap()) = 0; 114 | Q_INVOKABLE virtual QNetworkReply *put(const QUrl &url, 115 | const QVariantMap ¶meters = QVariantMap()) = 0; 116 | Q_INVOKABLE virtual QNetworkReply *deleteResource( 117 | const QUrl &url, const QVariantMap ¶meters = QVariantMap()) = 0; 118 | 119 | virtual void prepareRequest(QNetworkRequest *request, const QByteArray &verb, 120 | const QByteArray &body = QByteArray()) = 0; 121 | 122 | ModifyParametersFunction modifyParametersFunction() const; 123 | void setModifyParametersFunction(const ModifyParametersFunction &modifyParametersFunction); 124 | 125 | ContentType contentType() const; 126 | void setContentType(ContentType contentType); 127 | 128 | public Q_SLOTS: 129 | virtual void grant() = 0; 130 | 131 | Q_SIGNALS: 132 | void clientIdentifierChanged(const QString &clientIdentifier); 133 | void tokenChanged(const QString &token); 134 | void statusChanged(Status status); 135 | void authorizationUrlChanged(const QUrl &url); 136 | void extraTokensChanged(const QVariantMap &tokens); 137 | void contentTypeChanged(ContentType contentType); 138 | 139 | void requestFailed(const Error error); 140 | void authorizeWithBrowser(const QUrl &url); 141 | void granted(); 142 | void finished(QNetworkReply *reply); 143 | void replyDataReceived(const QByteArray &data); 144 | 145 | protected: 146 | explicit QAbstractOAuth(QAbstractOAuthPrivate &, QObject *parent = nullptr); 147 | 148 | void setStatus(Status status); 149 | 150 | QString callback() const; 151 | 152 | virtual void resourceOwnerAuthorization(const QUrl &url, const QMultiMap ¶meters); 153 | static QByteArray generateRandomString(quint8 length); 154 | 155 | private: 156 | Q_DISABLE_COPY(QAbstractOAuth) 157 | Q_DECLARE_PRIVATE(QAbstractOAuth) 158 | }; 159 | 160 | QT_END_NAMESPACE 161 | 162 | #endif // QT_NO_HTTP 163 | 164 | #endif // QABSTRACTOAUTH_H 165 | -------------------------------------------------------------------------------- /tests/manual/examples/twittertimeline/twittertimelinemodel.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "twittertimelinemodel.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | TwitterTimelineModel::TwitterTimelineModel(QObject *parent) : QAbstractTableModel(parent) 11 | { 12 | connect(&twitter, &Twitter::authenticated, this, &TwitterTimelineModel::authenticated); 13 | connect(&twitter, &Twitter::authenticated, this, &TwitterTimelineModel::updateTimeline); 14 | } 15 | 16 | int TwitterTimelineModel::rowCount(const QModelIndex &parent) const 17 | { 18 | #if defined(QT_DEBUG) 19 | Q_ASSERT(!parent.isValid()); 20 | #else 21 | Q_UNUSED(parent); 22 | #endif 23 | return tweets.size(); 24 | } 25 | 26 | QVariant TwitterTimelineModel::data(const QModelIndex &index, int role) const 27 | { 28 | if (role != Qt::DisplayRole) 29 | return QVariant(); 30 | 31 | auto it = tweets.begin(); 32 | std::advance(it, index.row()); 33 | switch (index.column()) 34 | { 35 | case 0: 36 | return QString::number(it->id); 37 | case 1: 38 | return it->createdAt.toString(Qt::ISODateWithMs); 39 | case 2: 40 | return it->user; 41 | case 3: 42 | return it->text; 43 | } 44 | return QVariant(); 45 | } 46 | 47 | int TwitterTimelineModel::columnCount(const QModelIndex &) const 48 | { 49 | return 4; 50 | } 51 | 52 | QVariant TwitterTimelineModel::headerData(int section, Qt::Orientation orientation, int role) const 53 | { 54 | if (role != Qt::DisplayRole) 55 | return QVariant(); 56 | 57 | if (orientation == Qt::Horizontal) { 58 | switch (section) { 59 | case 0: 60 | return QStringLiteral("Id"); 61 | case 1: 62 | return QStringLiteral("Created at"); 63 | case 2: 64 | return QStringLiteral("User"); 65 | case 3: 66 | return QStringLiteral("Text"); 67 | } 68 | } 69 | return section; 70 | } 71 | 72 | void TwitterTimelineModel::authenticate(const std::pair &clientCredentials) 73 | { 74 | twitter.setClientCredentials(clientCredentials); 75 | twitter.grant(); 76 | } 77 | 78 | QAbstractOAuth::Status TwitterTimelineModel::status() const 79 | { 80 | return twitter.status(); 81 | } 82 | 83 | void TwitterTimelineModel::updateTimeline() 84 | { 85 | if (twitter.status() != Twitter::Status::Granted) 86 | QMessageBox::warning(nullptr, qApp->applicationName(), "Not authenticated"); 87 | 88 | QUrl url("https://api.twitter.com/1.1/statuses/home_timeline.json"); 89 | QVariantMap parameters; 90 | if (tweets.size()) { 91 | // Tweets are time-ordered, newest first. Pass the most recent 92 | // ID we have to request everything more recent than it: 93 | parameters.insert("since_id", QString::number(tweets.first().id)); 94 | // From https://dev.twitter.com/rest/reference/get/search/tweets: 95 | // Returns results with an ID greater than (that is, more recent than) 96 | // the specified ID. There are limits to the number of Tweets which can 97 | // be accessed through the API. If the limit of Tweets has occurred 98 | // since the since_id, the since_id will be forced to the oldest ID 99 | // available. 100 | } 101 | QNetworkReply *reply = twitter.get(url, parameters); 102 | connect(reply, &QNetworkReply::finished, this, &TwitterTimelineModel::parseJson); 103 | } 104 | 105 | void TwitterTimelineModel::parseJson() 106 | { 107 | QJsonParseError parseError; 108 | auto reply = qobject_cast(sender()); 109 | Q_ASSERT(reply); 110 | const auto data = reply->readAll(); 111 | const auto document = QJsonDocument::fromJson(data, &parseError); 112 | if (parseError.error) { 113 | qCritical() << "TwitterTimelineModel::parseJson. Error at:" << parseError.offset 114 | << parseError.errorString(); 115 | return; 116 | } else if (document.isObject()) { 117 | // Error received :( 118 | const auto object = document.object(); 119 | const auto errorArray = object.value("errors").toArray(); 120 | Q_ASSERT_X(errorArray.size(), "parse", data); 121 | QStringList errors; 122 | for (const auto error : errorArray) { 123 | Q_ASSERT(error.isObject()); 124 | Q_ASSERT(error.toObject().contains("message")); 125 | errors.append(error.toObject().value("message").toString()); 126 | } 127 | QMessageBox::warning(nullptr, qApp->applicationName(), errors.join("
")); 128 | return; 129 | } 130 | 131 | Q_ASSERT_X(document.isArray(), "parse", data); 132 | const auto array = document.array(); 133 | if (array.size()) { 134 | beginInsertRows(QModelIndex(), 0, array.size() - 1); 135 | auto before = tweets.begin(); 136 | for (const auto &value : array) { 137 | Q_ASSERT(value.isObject()); 138 | const auto object = value.toObject(); 139 | const auto createdAt = QDateTime::fromString(object.value("created_at").toString(), 140 | "ddd MMM dd HH:mm:ss +0000 yyyy"); 141 | before = tweets.insert(before, Tweet{ 142 | object.value("id").toVariant().toULongLong(), 143 | createdAt, 144 | object.value("user").toObject().value("name").toString(), 145 | object.value("text").toString() 146 | }); 147 | std::advance(before, 1); 148 | } 149 | endInsertRows(); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/oauth/qabstractoauth2_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2017 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | // 5 | // W A R N I N G 6 | // ------------- 7 | // 8 | // This file is not part of the Qt API. It exists for the convenience 9 | // of the Network Access API. This header file may change from 10 | // version to version without notice, or even be removed. 11 | // 12 | // We mean it. 13 | // 14 | 15 | #ifndef QABSTRACTOAUTH2_P_H 16 | #define QABSTRACTOAUTH2_P_H 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | #include 34 | 35 | QT_BEGIN_NAMESPACE 36 | 37 | class QNetworkAccessManager; 38 | 39 | class QAbstractOAuth2Private : public QAbstractOAuthPrivate 40 | { 41 | Q_DECLARE_PUBLIC(QAbstractOAuth2) 42 | 43 | public: 44 | QAbstractOAuth2Private(const std::pair &clientCredentials, 45 | const QUrl &authorizationUrl, QNetworkAccessManager *manager = nullptr); 46 | ~QAbstractOAuth2Private(); 47 | 48 | void setExpiresAt(const QDateTime &expiration); 49 | void setGrantedScopeTokens(const QSet &tokens); 50 | static QString joinedScope(const QSet &scopeTokens); 51 | static QSet splitScope(QStringView scope); 52 | static bool checkRequestedScopeTokensValid(const QSet &tokens); 53 | static bool checkRequestedScopeTokenValid(QByteArrayView token); 54 | static void warnOnInvalidScopeToken(QStringView token); 55 | static QString generateRandomState(); 56 | static QString generateNonce(); 57 | QNetworkRequest createRequest(QUrl url, const QVariantMap *parameters = nullptr); 58 | bool authorizationShouldIncludeNonce() const; 59 | void setIdToken(const QString &token); 60 | void _q_tokenRequestFailed(QAbstractOAuth::Error error, const QString& errorString); 61 | void _q_tokenRequestFinished(const QVariantMap &values); 62 | bool handleRfcErrorResponseIfPresent(const QVariantMap &data); 63 | struct RequestAndBody 64 | { 65 | QNetworkRequest request; 66 | QByteArray body; 67 | }; 68 | [[nodiscard]] RequestAndBody createRefreshRequestAndBody(const QUrl &url); 69 | 70 | Q_DECL_COLD_FUNCTION 71 | void logAuthorizationStageWarning(QLatin1StringView message); 72 | Q_DECL_COLD_FUNCTION 73 | void logAuthorizationStageWarning(QLatin1StringView message, int detail); 74 | Q_DECL_COLD_FUNCTION 75 | void logTokenStageWarning(QLatin1StringView message); 76 | 77 | struct CallerInfo { 78 | QPointer contextObject = nullptr; 79 | QtPrivate::SlotObjUniquePtr slot; 80 | }; 81 | CallerInfo networkRequestModifier; 82 | void callNetworkRequestModifier(QNetworkRequest &request, QAbstractOAuth::Stage stage); 83 | bool verifyThreadAffinity(const QObject *contextObject); 84 | 85 | void initializeRefreshHandling(); 86 | void updateRefreshTimer(bool clientSideUpdate); 87 | 88 | QString clientIdentifierSharedKey; 89 | QSet requestedScopeTokens; 90 | QSet grantedScopeTokens; 91 | QString state = generateRandomState(); 92 | QString userAgent = QStringLiteral("QtOAuth/1.0 (+https://www.qt.io)"); 93 | QString responseType; 94 | const QString bearerFormat = QStringLiteral("Bearer %1"); // Case sensitive 95 | QDateTime expiresAtUtc; 96 | QString refreshToken; 97 | std::chrono::seconds refreshLeadTime = std::chrono::seconds::zero(); 98 | QChronoTimer refreshTimer; 99 | #ifndef QOAUTH2_NO_LEGACY_SCOPE 100 | QString legacyScope; 101 | bool legacyScopeWasSetByUser = false; 102 | #endif 103 | bool autoRefresh = false; 104 | QAbstractOAuth2::NonceMode nonceMode = QAbstractOAuth2::NonceMode::Automatic; 105 | QString nonce; 106 | QString idToken; 107 | QString tokenType; 108 | QUrl tokenUrl; 109 | // RFC (6749) doesn't state any maximum value for the lifetime, use long just in case 110 | qlonglong tokenLifetime = 0; 111 | #ifndef QT_NO_SSL 112 | std::optional sslConfiguration; 113 | #endif 114 | }; 115 | 116 | namespace QtOAuth2RfcKeywords 117 | { 118 | inline constexpr auto accessToken = QLatin1StringView("access_token"); 119 | inline constexpr auto apiKey = QLatin1StringView("api_key"); 120 | inline constexpr auto clientIdentifier = QLatin1StringView("client_id"); 121 | inline constexpr auto clientSharedSecret = QLatin1StringView("client_secret"); 122 | inline constexpr auto code = QLatin1StringView("code"); 123 | inline constexpr auto error = QLatin1StringView("error"); 124 | inline constexpr auto errorDescription = QLatin1StringView("error_description"); 125 | inline constexpr auto errorUri = QLatin1StringView("error_uri"); 126 | inline constexpr auto expiresIn = QLatin1StringView("expires_in"); 127 | inline constexpr auto grantType = QLatin1StringView("grant_type"); 128 | inline constexpr auto redirectUri = QLatin1StringView("redirect_uri"); 129 | inline constexpr auto refreshToken = QLatin1StringView("refresh_token"); 130 | inline constexpr auto responseType = QLatin1StringView("response_type"); 131 | inline constexpr auto scope = QLatin1StringView("scope"); 132 | inline constexpr auto state = QLatin1StringView("state"); 133 | inline constexpr auto tokenType = QLatin1StringView("token_type"); 134 | inline constexpr auto codeVerifier = QLatin1StringView("code_verifier"); 135 | inline constexpr auto codeChallenge = QLatin1StringView("code_challenge"); 136 | inline constexpr auto codeChallengeMethod = QLatin1StringView("code_challenge_method"); 137 | inline constexpr auto nonce = QLatin1StringView("nonce"); 138 | inline constexpr auto idToken = QLatin1StringView("id_token"); 139 | inline constexpr auto deviceCode = QLatin1StringView("device_code"); 140 | inline constexpr auto userCode = QLatin1StringView("user_code"); 141 | // RFC keyword is verification_uri[_complete], but some servers use 'url' (note L) 142 | // https://datatracker.ietf.org/doc/html/rfc8628#section-3.2 143 | inline constexpr auto verificationUri = QLatin1StringView("verification_uri"); 144 | inline constexpr auto verificationUrl = QLatin1StringView("verification_url"); 145 | inline constexpr auto completeVerificationUri = QLatin1StringView("verification_uri_complete"); 146 | inline constexpr auto completeVerificationUrl = QLatin1StringView("verification_url_complete"); 147 | inline constexpr auto interval = QLatin1StringView("interval"); 148 | } 149 | 150 | QT_END_NAMESPACE 151 | 152 | #endif // QABSTRACTOAUTH2_P_H 153 | -------------------------------------------------------------------------------- /src/oauth/doc/src/qtnetworkauth-security.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \page qtnetworkauth-security 6 | \title Qt Network Authorization Security Considerations 7 | \ingroup security-considerations 8 | \brief Access control, authorization, and authentication issues. 9 | 10 | This page covers security considerations for applications using 11 | \l{Qt Network Authorization}. Much of the content here focuses on 12 | OAuth 2.0 Authorization Framework and OpenID. 13 | 14 | Refer to \l{RFC 6749} for the OAuth 2.0 protocol flow and \l{RFC 8252} for 15 | security issues regarding native applications. 16 | 17 | \section1 Access control 18 | 19 | Access control involves provisioning resources to users using a system for 20 | checking identities and permissions. Access control then includes 21 | authorization, authentication, and logging services. Qt Network 22 | Authorization's API implements access control with focus on 23 | OAuth 2.0 Authorization Framework. Qt Network Authorization supports the 24 | Authorization Code flow (with PKCE) and the Device Authorization flow. 25 | 26 | For systems, a deliberate separation according to privileges and 27 | permissions is the first step of access control. User categories can 28 | dictate the groups that may access certain resources and services. 29 | Likewise, permissions on resources or services can dictate the available 30 | actions on them. Request only the OAuth scopes your application needs. 31 | Limiting scope reduces the potential impact if tokens are compromised. 32 | 33 | Systems also must implement access management for flexibility and for 34 | supervision. Provisioning access and services must be part of the system 35 | design so that it is easy to add or remove users and resources without 36 | compromising security. Activity logs aid audits and security 37 | analysis. 38 | 39 | A well known design is the \e {role-based access control} (RBAC). 40 | 41 | \section1 Authentication and single sign-on 42 | 43 | \e Authentication is checking for the identity of a user. Weak 44 | authentication methods lead to granting access to the wrong users and can 45 | result in private data exposure and execution of malicious actions. 46 | 47 | Connected applications need to verify the identities of users that use 48 | restricted resources. Typically, applications verify users by checking user 49 | credentials such as username and password in an existing database. This 50 | method is vulnerable to false authentications and data breaches. Many 51 | mitigation techniques are about user behavior and applications can 52 | enforce security policies such as requiring \e strong passwords. 53 | Applications can use Qt's validators and widgets to guide users with 54 | messages and by restricting the creation of weak passwords. 55 | 56 | Using a centralized authentication system such as a single sign-on (SSO) 57 | can minimize the mismanagement of passwords and identities. 58 | 59 | \l{Qt Network Authorization} can retrieve JSON Web Tokens (JWT) 60 | through OpenID Connect, an identity layer on top of OAuth 2.0. 61 | Often, authentication and authorization are part of the same system. 62 | Treat access tokens, refresh tokens, and ID tokens as sensitive data. 63 | Store them securely using platform secure storage or encryption. 64 | Do not store tokens in plain text. 65 | 66 | \section1 Authorization and resource provision 67 | 68 | \e Authorization is checking if a user has access to a resource based on 69 | the user privileges and permissions on that resource. Without proper 70 | authorization, users can access a resource and perform actions even though 71 | they do not have the permission. Attackers can modify and reduce the 72 | integrity of data or abuse resources, causing a denial of service. 73 | 74 | As basic precaution, perform authorization checks before executing actions 75 | that can lead to misuse of resources. This check can happen whenever users 76 | access server-side resources. The users' privileges and the permissions on 77 | the resources determine if the user may execute an action on the resource. 78 | Additional authorization checks may be necessary according to the resource. 79 | Revoke access and refresh tokens when users log out or when your 80 | application no longer needs them. 81 | 82 | \section1 Use an external user-agent 83 | 84 | According to \l{RFC 8252}, applications can use either an 85 | \e external or an \e embedded user-agent for the authorization 86 | endpoint, as defined in \l{RFC 6749}{OAuth 2.0}. Embedded 87 | user-agents are typically the webviews provided and controlled 88 | within the application. External user-agents are the 89 | system browsers or other applications not controlled by the 90 | requesting application. 91 | 92 | \l{RFC 8252} recommends using external user-agents rather than 93 | embedded web views for authorization. 94 | The application controls the embedded user-agent and fails to separate the 95 | privileged access between the application and authorization node. This 96 | setup is unsafe as the application can record keystrokes and can trick 97 | users with a false sense of security. However, properly configured 98 | embedded browsers like Qt WebEngine can also be used when external 99 | user-agents are not practical. 100 | 101 | Also, with the system browser as the external user-agent, browser 102 | tabs and stored credentials can simplify the user experience. For 103 | example, users can use their saved usernames and passwords in the 104 | browser. Similarly, using password managers as the external 105 | user-agent increases simplicity and trust. 106 | 107 | \section1 PKCE and state parameter 108 | 109 | \l{RFC 7636}{Proof Key for Code Exchange (PKCE)} protects against 110 | authorization code interception attacks in the Authorization Code flow. Qt 111 | Network Authorization enables PKCE by default. 112 | 113 | Qt Network Authorization generates random state values by default to 114 | prevent cross-site request forgery (CSRF) attacks. If you override 115 | the state parameter, avoid using hard-coded strings. 116 | 117 | \section1 Platform considerations 118 | 119 | Redirect URI handling varies by platform. On \l{Mobile Platforms} 120 | {mobile platforms}, HTTPS redirect URIs can be handled securely 121 | through app-claimed URLs. On \l{desktop platforms}, HTTP redirect 122 | URIs to localhost remain a valid option for native 123 | applications. 124 | 125 | \section1 Security resources for connected applications 126 | 127 | Here are resources for cybersecurity guidance: 128 | 129 | \list 130 | \li \l{https://cwe.mitre.org/index.html}{Common Weakness Enumeration} 131 | - A catalog of known issues and possible mitigation techniques. 132 | \li \l{https://cheatsheetseries.owasp.org}{OWASP Cheat Sheet Series} 133 | - A listing of various topics for securing applications. 134 | \li \l{RFC 6749} - OAuth 2.0 Authorization Framework 135 | \li \l{RFC 8252} - OAuth 2.0 for Native Apps 136 | \li \l{RFC 7636} - Proof Key for Code Exchange (PKCE) 137 | \endlist 138 | */ 139 | -------------------------------------------------------------------------------- /tests/auto/shared/webserver.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #include "webserver.h" 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | WebServer::WebServer(Handler h, QObject *parent) : 14 | QTcpServer(parent), 15 | handler(h) 16 | { 17 | connect(this, &QTcpServer::newConnection, this, [this]() { 18 | auto socket = nextPendingConnection(); 19 | connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater); 20 | connect(socket, &QTcpSocket::readyRead, this, [this, socket]() { 21 | if (!clients.contains(socket)) 22 | clients[socket].port = serverPort(); 23 | 24 | auto *request = &clients[socket]; 25 | auto ok = true; 26 | 27 | while (socket->bytesAvailable()) { 28 | if (Q_LIKELY(request->state == HttpRequest::State::ReadingMethod)) 29 | if (Q_UNLIKELY(!(ok = request->readMethod(socket)))) 30 | qWarning("Invalid Method"); 31 | 32 | if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingUrl)) 33 | if (Q_UNLIKELY(!(ok = request->readUrl(socket)))) 34 | qWarning("Invalid URL"); 35 | 36 | if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingStatus)) 37 | if (Q_UNLIKELY(!(ok = request->readStatus(socket)))) 38 | qWarning("Invalid Status"); 39 | 40 | if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingHeader)) 41 | if (Q_UNLIKELY(!(ok = request->readHeaders(socket)))) 42 | qWarning("Invalid Header"); 43 | 44 | if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingBody)) 45 | if (Q_UNLIKELY(!(ok = request->readBody(socket)))) 46 | qWarning("Invalid Body"); 47 | } 48 | if (Q_UNLIKELY(!ok)) { 49 | socket->disconnectFromHost(); 50 | clients.remove(socket); 51 | } else if (Q_LIKELY(request->state == HttpRequest::State::AllDone)) { 52 | Q_ASSERT(handler); 53 | if (request->headers.contains("host")) { 54 | const auto parts = request->headers["host"].split(':'); 55 | request->url.setHost(parts.at(0)); 56 | if (parts.size() == 2) 57 | request->url.setPort(parts.at(1).toUInt()); 58 | } 59 | handler(*request, socket); 60 | socket->disconnectFromHost(); 61 | clients.remove(socket); 62 | } 63 | }); 64 | }); 65 | 66 | const auto ok = listen(QHostAddress::LocalHost); 67 | Q_ASSERT(ok); 68 | } 69 | 70 | QUrl WebServer::url(const QString &path) 71 | { 72 | const QString format("http://127.0.0.1:%1%2"); 73 | return QUrl(format.arg(serverPort()).arg(path.startsWith('/') ? path : "/" + path)); 74 | } 75 | 76 | bool WebServer::HttpRequest::readMethod(QTcpSocket *socket) 77 | { 78 | bool finished = false; 79 | while (socket->bytesAvailable() && !finished) { 80 | const auto c = socket->read(1).at(0); 81 | if (std::isspace(c)) 82 | finished = true; 83 | else if (std::isupper(c) && fragment.size() < 8) 84 | fragment += c; 85 | else 86 | return false; 87 | } 88 | if (finished) { 89 | if (fragment == "HEAD") 90 | method = Method::Head; 91 | else if (fragment == "GET") 92 | method = Method::Get; 93 | else if (fragment == "PUT") 94 | method = Method::Put; 95 | else if (fragment == "POST") 96 | method = Method::Post; 97 | else if (fragment == "DELETE") 98 | method = Method::Delete; 99 | else 100 | qWarning("Invalid operation %s", fragment.data()); 101 | 102 | state = State::ReadingUrl; 103 | fragment.clear(); 104 | 105 | return method != Method::Unknown; 106 | } 107 | return true; 108 | } 109 | 110 | bool WebServer::HttpRequest::readUrl(QTcpSocket *socket) 111 | { 112 | bool finished = false; 113 | while (socket->bytesAvailable() && !finished) { 114 | const auto c = socket->read(1).at(0); 115 | if (std::isspace(c)) 116 | finished = true; 117 | else 118 | fragment += c; 119 | } 120 | if (finished) { 121 | if (!fragment.startsWith("/")) { 122 | qWarning("Invalid URL path %s", fragment.constData()); 123 | return false; 124 | } 125 | url.setUrl(QStringLiteral("http://127.0.0.1:") + QString::number(port) + 126 | QString::fromUtf8(fragment)); 127 | state = State::ReadingStatus; 128 | if (!url.isValid()) { 129 | qWarning("Invalid URL %s", fragment.constData()); 130 | return false; 131 | } 132 | fragment.clear(); 133 | } 134 | return true; 135 | } 136 | 137 | bool WebServer::HttpRequest::readStatus(QTcpSocket *socket) 138 | { 139 | bool finished = false; 140 | while (socket->bytesAvailable() && !finished) { 141 | fragment += socket->read(1); 142 | if (fragment.endsWith("\r\n")) { 143 | finished = true; 144 | fragment.resize(fragment.size() - 2); 145 | } 146 | } 147 | if (finished) { 148 | if (!std::isdigit(fragment.at(fragment.size() - 3)) || 149 | fragment.at(fragment.size() - 2) != '.' || 150 | !std::isdigit(fragment.at(fragment.size() - 1))) { 151 | qWarning("Invalid version"); 152 | return false; 153 | } 154 | version = std::make_pair(fragment.at(fragment.size() - 3) - '0', 155 | fragment.at(fragment.size() - 1) - '0'); 156 | state = State::ReadingHeader; 157 | fragment.clear(); 158 | } 159 | return true; 160 | } 161 | 162 | bool WebServer::HttpRequest::readHeaders(QTcpSocket *socket) 163 | { 164 | while (socket->bytesAvailable()) { 165 | fragment += socket->read(1); 166 | if (fragment.endsWith("\r\n")) { 167 | if (fragment == "\r\n") { 168 | state = State::ReadingBody; 169 | fragment.clear(); 170 | return true; 171 | } else { 172 | fragment.chop(2); 173 | const int index = fragment.indexOf(':'); 174 | if (index == -1) 175 | return false; 176 | 177 | const QByteArray key = fragment.mid(0, index).trimmed(); 178 | const QByteArray value = fragment.mid(index + 1).trimmed(); 179 | headers.insert(key.toLower(), value); 180 | fragment.clear(); 181 | } 182 | } 183 | } 184 | return true; 185 | } 186 | 187 | bool WebServer::HttpRequest::readBody(QTcpSocket *socket) 188 | { 189 | if (headers.contains("content-length")) { 190 | bool conversionResult; 191 | bytesLeft = headers["content-length"].toInt(&conversionResult); 192 | if (Q_UNLIKELY(!conversionResult)) 193 | return false; 194 | fragment.resize(bytesLeft); 195 | } 196 | while (bytesLeft) { 197 | int got = socket->read(&fragment.data()[fragment.size() - bytesLeft], bytesLeft); 198 | if (got < 0) 199 | return false; // error 200 | bytesLeft -= got; 201 | if (bytesLeft) 202 | qApp->processEvents(); 203 | } 204 | fragment.swap(body); 205 | state = State::AllDone; 206 | return true; 207 | } 208 | -------------------------------------------------------------------------------- /src/oauth/doc/src/qtnetworkauth-oauth2-browsersupport.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \page qt-oauth2-browsersupport.html 6 | 7 | \title Qt OAuth2 Browser Support 8 | \ingroup explanations-networkauth 9 | \brief An overview of QtNetworkAuth OAuth2 browser support 10 | 11 | \section1 OAuth2 User-Agents 12 | 13 | OAuth2 \l{OAuth 2.0 Overview}{Authorization stage} 14 | \l{https://datatracker.ietf.org/doc/html/rfc6749#section-9}{relies on a user-agent}, 15 | which is typically either the system browser or an embedded user-agent such as 16 | \l {Qt WebEngine Overview}{Qt WebEngine}. 17 | 18 | The choice between system browser and an embedded user-agent depends on several 19 | factors. The following describes few main considerations: 20 | \list 21 | \li System browser may already have active logins by the user. Therefore 22 | the user authentication during authorization stage may be more 23 | straightforward as the existing login can be used. In contrast with 24 | an embedded user-agent user typically needs to perform a new login. 25 | On the other hand, leaving a login session behind in the system 26 | browser may not always be desirable. System browsers may also 27 | share application usage data with other parties. 28 | \li System browser is typically familiar for the user, and provides a 29 | familiar user experience for logging in. On the other hand, while 30 | an embedded user-agent may provide less familiar look-and-feel, 31 | the application developer is able to embed the login interaction 32 | as part of the application window, rather than it occurring on a 33 | separate browser window. Furthermore the application developer can 34 | automate closing of the embedded user-agent when no longer needed. 35 | \li System browsers provide familiar security visuals, 36 | such as the address bar and certificate validation for the user. These 37 | may not be visible on an embedded user-agent. Furthermore the system 38 | browsers may better leverage security features of the underlying 39 | operating system. 40 | \li An embedded user-agent potentially has access to all security 41 | credentials the user enters. 42 | \li Not all platforms provide support for handling \c https or custom 43 | uri-scheme redirect URLs (see \l {QOAuthUriSchemeReplyHandler}). 44 | With these platforms an embedded user-agent can be used to work 45 | around the limitation. 46 | \li Including an embedded user-agent as part of the application is 47 | typically a large component, increasing the storage footprint 48 | of the application. On the other hand, all use cases may not have 49 | a system browser available, or the application may use an embedded 50 | user-agent already for other purposes. 51 | \endlist 52 | 53 | Given these considerations, using the system browser 54 | \l {https://www.rfc-editor.org/rfc/rfc8252#section-8.12} 55 | {is recommended for native applications}. 56 | But as hinted by some of the points above, there may still be valid 57 | use cases for using an embedded user-agent. 58 | 59 | \section2 Using System Browser 60 | 61 | Using the system browser requires opening it and navigating to the 62 | authorization URL configured by the application. Typical usage looks 63 | as follows: 64 | 65 | \snippet src_oauth_replyhandlers.cpp system-browser-usage 66 | 67 | The code connects \l {QAbstractOAuth::authorizeWithBrowser} signal and 68 | \l {QDesktopServices::openUrl} slot. This opens the 69 | system browser, where user performs the necessary authentication and 70 | authorization. The application or Qt libraries have no direct control over 71 | the system browser, and it typically remains open once the authorization is 72 | concluded. 73 | 74 | For further details and supported redirect URL schemes with 75 | system browser please see \l{OAuth 2.0 Overview}, 76 | \l {QOAuthHttpServerReplyHandler}, and \l {QOAuthUriSchemeReplyHandler}. 77 | 78 | \section2 Using Qt WebEngine 79 | 80 | \l {Qt WebEngine Overview}{Qt WebEngine} provides a web browser engine 81 | to embed web content directly into the Qt application. 82 | 83 | Along with core control features, it comes with easy-to-use views 84 | for both QtWidgets and QtQuick applications. These views can be used 85 | as the user-agent in an OAuth2 authorization. \l {Qt WebEngine} is 86 | a large and versatile module, and the focus of this documentation 87 | is on using it with OAuth2 authorization. 88 | 89 | There are many ways to embed the Qt WebEngine as part of the application. 90 | From practical point of view the main considerations are: 91 | \list 92 | \li QtQuick vs QtWidgets Applications. This impacts how to set up the 93 | necessary integration with QtNetworkAuth classes. 94 | \li Redirect URI scheme. This impacts which QtNetworkAuth reply handler 95 | classes to use, and how (see \l {OAuth 2.0 Overview}). 96 | \endlist 97 | 98 | \section3 QtQuick and QtWidgets Applications 99 | 100 | Qt WebEngine can be used with both QtQuick and QtWidgets applications 101 | for OAuth2 authorization. The main difference is in how set up the 102 | few necessary enablers. 103 | 104 | Following illustrates a simplified \l {QWebEngineView} (QtWidget) setup. 105 | Error handling and any potential \l {Qt WebEngine} configuration is 106 | omitted for brevity. 107 | 108 | Assuming following widgets: 109 | \snippet src_oauth_replyhandlers_p.h webengine-widget-variables 110 | 111 | Instead of opening the system browser, we use the QWebEngineView 112 | to perform the authorization: 113 | \snippet src_oauth_replyhandlers.cpp webengine-widget-authorization-start 114 | 115 | Once the authorization is finished, we close the view: 116 | \snippet src_oauth_replyhandlers.cpp webengine-widget-authorization-finish 117 | 118 | For QtQuick applications the flow is in principle the same, but instead of 119 | \l {QWebEngineView} widget we use \l {WebEngineView} QML element: 120 | 121 | \snippet MainWindow.qml webengine-qml-view 122 | 123 | This simplified example exposes needed APIs from C++ class 124 | \snippet src_oauth_replyhandlers_p.h webengine-qml-control 125 | 126 | Which are then used on the QML-side for invoking \l {WebEngineView} 127 | to handle the authorization: 128 | 129 | \snippet MainWindow.qml webengine-qml-authorization 130 | 131 | \section3 Redirect URI Schemes 132 | 133 | The choice of redirect URI scheme (\c http, \c https, or \c custom-uri scheme) 134 | has an impact how to use \l {Qt WebEngine}. 135 | 136 | \section4 http Loopback URIs 137 | 138 | With \c http loopback redirect URI and QOAuthHttpServerReplyHandler 139 | the handling works similarly as with system browser. Qt WebEngine 140 | redirects the authorization to the reply handler's localhost server 141 | similarly as the system browser. 142 | 143 | \section4 Custom scheme URIs 144 | 145 | With custom-scheme URIs (such as \c {com.example.myqtapp:/redirect}) and 146 | QOAuthUriSchemeReplyHandler the flow works also similarly as with 147 | system browser. 148 | 149 | The main difference is that the application does not need to be configured 150 | similarly as the 151 | \l {https://developer.apple.com/ios/universal-links/}{Universal Links on iOS/macOS} 152 | or \l {https://developer.android.com/training/app-links}{App Links on Android}, 153 | as described in QOAuthUriSchemeReplyHandler documentation. 154 | 155 | \snippet src_oauth_replyhandlers.cpp webengine-widgets-custom 156 | 157 | Technically this works so that \l {Qt WebEngine} calls the 158 | \l {QDesktopServices::openUrl()} for unhandled URI-schemes, 159 | whose counterpart QOAuthUriSchemeReplyHandler listens to. 160 | 161 | \section4 https URIs 162 | 163 | With \c {https} URIs and QOAuthUriSchemeReplyHandler the logic changes 164 | slightly. Similarly as with \l {Custom scheme URIs} the application 165 | doesn't need to be configured, but we need to supply the redirection 166 | at the end of authorization stage to the web engine. 167 | 168 | \snippet src_oauth_replyhandlers.cpp webengine-widgets-https 169 | 170 | This needs to be done because from \l {Qt WebEngine} point of view 171 | the redirect URL is a valid \c {https} URL, and by default will attempt to 172 | navigate to it. 173 | 174 | To prevent such navigation attempts and accidental authorization 175 | code exposure (consider the case the redirect URL domain isn't in 176 | your control), a more involved filtering should be used. Also the use 177 | of QOAuth2AuthorizationCodeFlow::PkceMethod is strongly recommended 178 | as it mitigates the impact of authorization code hijacking. 179 | 180 | For example: 181 | 182 | \snippet src_oauth_replyhandlers.cpp webengine-widget-https-filtering 183 | 184 | */ 185 | -------------------------------------------------------------------------------- /tests/auto/oauthurischemereplyhandler/tst_oauthurischemereplyhandler.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace Qt::StringLiterals; 18 | 19 | class tst_QOAuthUriSchemeReplyHandler : public QObject 20 | { 21 | Q_OBJECT 22 | 23 | private Q_SLOTS: 24 | void construction(); 25 | void redirectUrl(); 26 | void listenClose(); 27 | void authorization_data(); 28 | void authorization(); 29 | void callbackDataReceived_data(); 30 | void callbackDataReceived(); 31 | void handleAuthorizationRedirect(); 32 | 33 | private: 34 | const QUrl customUrlWithPath{"com.my.app:/somepath"_L1}; 35 | const QUrl customUrlWithoutPath{"com.my.app"_L1}; 36 | const QUrl customUrlWithHost{"com.my.app://some.host.org"_L1}; 37 | const QUrl customUrlWithExtra{"com.my.app:/somepath:1234?key=value"_L1}; 38 | const QUrl authorizationUrl{"https://example.foo.bar.com/api/authorize"_L1}; 39 | const QUrl accessTokenUrl{"idontexist"_L1}; // token acqusition is irrelevant for this test 40 | static constexpr auto state = "a_state"_L1; 41 | static constexpr auto code = "a_code"_L1; 42 | const QString stateCodeQuery = "?state="_L1 + state + "&code="_L1 + code; 43 | const QVariantMap stateCodeMap{{"state"_L1, state}, {"code"_L1, code}}; 44 | }; 45 | 46 | void tst_QOAuthUriSchemeReplyHandler::construction() 47 | { 48 | QOAuthUriSchemeReplyHandler rh1; 49 | QVERIFY(!rh1.isListening()); 50 | QVERIFY(rh1.callback().isEmpty()); 51 | QVERIFY(rh1.redirectUrl().isEmpty()); 52 | 53 | QOAuthUriSchemeReplyHandler rh2(customUrlWithPath); 54 | QVERIFY(rh2.isListening()); 55 | QCOMPARE(rh2.redirectUrl(), customUrlWithPath); 56 | QCOMPARE(rh2.callback(), customUrlWithPath.toString()); 57 | } 58 | 59 | void tst_QOAuthUriSchemeReplyHandler::redirectUrl() 60 | { 61 | QOAuthUriSchemeReplyHandler rh; 62 | QSignalSpy urlChangedSpy(&rh, &QOAuthUriSchemeReplyHandler::redirectUrlChanged); 63 | 64 | rh.setRedirectUrl(customUrlWithPath); 65 | QCOMPARE(rh.redirectUrl(), customUrlWithPath); 66 | QCOMPARE(rh.callback(), customUrlWithPath.toString()); 67 | QCOMPARE(urlChangedSpy.size(), 1); 68 | 69 | rh.setRedirectUrl(customUrlWithHost); 70 | QCOMPARE(rh.redirectUrl(), customUrlWithHost); 71 | QCOMPARE(rh.callback(), customUrlWithHost.toString()); 72 | QCOMPARE(urlChangedSpy.size(), 2); 73 | 74 | rh.setRedirectUrl(customUrlWithExtra); 75 | QCOMPARE(rh.redirectUrl(), customUrlWithExtra); 76 | QCOMPARE(rh.callback(), customUrlWithExtra.toString()); 77 | QCOMPARE(urlChangedSpy.size(), 3); 78 | 79 | rh.setRedirectUrl(customUrlWithExtra); // Same URL again 80 | QCOMPARE(urlChangedSpy.size(), 3); 81 | 82 | rh.setRedirectUrl({}); 83 | QVERIFY(rh.redirectUrl().isEmpty()); 84 | QVERIFY(rh.callback().isEmpty()); 85 | QCOMPARE(urlChangedSpy.size(), 4); 86 | } 87 | 88 | void tst_QOAuthUriSchemeReplyHandler::listenClose() 89 | { 90 | const QUrl scheme1{u"scheme1:/foo"_s}; 91 | const QUrl scheme2{u"scheme2:/foo"_s}; 92 | QOAuthUriSchemeReplyHandler rh; 93 | QSignalSpy callbackSpy(&rh, &QAbstractOAuthReplyHandler::callbackReceived); 94 | 95 | rh.setRedirectUrl(scheme1); 96 | QVERIFY(rh.listen()); 97 | QDesktopServices::openUrl(scheme1); 98 | QCOMPARE(callbackSpy.size(), 1); 99 | 100 | rh.setRedirectUrl(scheme2); 101 | QDesktopServices::openUrl(scheme2); 102 | QCOMPARE(callbackSpy.size(), 2); 103 | 104 | QDesktopServices::openUrl(scheme1); // Previous scheme should be unregistered 105 | QCOMPARE(callbackSpy.size(), 2); 106 | 107 | rh.close(); 108 | QDesktopServices::openUrl(scheme2); 109 | QCOMPARE(callbackSpy.size(), 2); 110 | } 111 | 112 | void tst_QOAuthUriSchemeReplyHandler::authorization_data() 113 | { 114 | QTest::addColumn("registered_redirect_uri"); 115 | QTest::addColumn("response_redirect_uri"); 116 | QTest::addColumn("matches"); 117 | QTest::addColumn("result_parameters"); 118 | 119 | QTest::newRow("match_with_path") 120 | << QUrl{"com.example:/cb"_L1} << QUrl{"com.example:/cb"_L1 + stateCodeQuery} 121 | << true << stateCodeMap; 122 | 123 | QTest::newRow("match_with_host") 124 | << QUrl{"com.example://cb.example.org"_L1} 125 | << QUrl{"com.example://cb.example.org"_L1 + stateCodeQuery} 126 | << true << stateCodeMap; 127 | 128 | QTest::newRow("match_with_host_and_path") 129 | << QUrl{"com.example://cb.example.org/a_path"_L1} 130 | << QUrl{"com.example://cb.example.org/a_path"_L1 + stateCodeQuery} 131 | << true << stateCodeMap; 132 | 133 | QVariantMap resultParameters = stateCodeMap; 134 | resultParameters.insert("lang"_L1, "de"); 135 | QTest::newRow("match_with_path_and_query") 136 | << QUrl{"com.example:/cb?lang=de"_L1} 137 | << QUrl{"com.example:/cb"_L1 + stateCodeQuery + "&lang=de"_L1} 138 | << true << resultParameters; 139 | 140 | QTest::newRow("mismatch_path") 141 | << QUrl{"com.example:/cb"_L1} << QUrl{"com.example:/wrong"_L1 + stateCodeQuery} 142 | << false << stateCodeMap; 143 | 144 | QTest::newRow("mismatch_parameters") 145 | << QUrl{"com.example:/cb?lang=de"_L1} << QUrl{"com.example:/cb?code=foo"_L1} 146 | << false << stateCodeMap; 147 | 148 | QTest::newRow("mismatch_parameter_value") 149 | << QUrl{"com.example:/cb?lang=de"_L1} << QUrl{"com.example:/cb?lang=wrong"_L1} 150 | << false << stateCodeMap; 151 | } 152 | 153 | void tst_QOAuthUriSchemeReplyHandler::authorization() 154 | { 155 | // The registered redirect URI is what is typically registered at the cloud 156 | QFETCH(const QUrl, registered_redirect_uri); 157 | // The response redirect URI is registered URI with additional parameters from server 158 | QFETCH(const QUrl, response_redirect_uri); 159 | QFETCH(const bool, matches); 160 | QFETCH(const QVariantMap, result_parameters); 161 | 162 | QOAuthUriSchemeReplyHandler rh; 163 | rh.setRedirectUrl(registered_redirect_uri); 164 | rh.listen(); 165 | 166 | QOAuth2AuthorizationCodeFlow oauth; 167 | oauth.setAuthorizationUrl(authorizationUrl); 168 | #if QT_DEPRECATED_SINCE(6, 13) 169 | QT_IGNORE_DEPRECATIONS(oauth.setAccessTokenUrl(accessTokenUrl);) 170 | #else 171 | oauth.setTokenUrl(accessTokenUrl); 172 | #endif 173 | oauth.setState(state); 174 | oauth.setReplyHandler(&rh); 175 | 176 | QSignalSpy openBrowserSpy(&oauth, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser); 177 | QSignalSpy redirectedSpy(&rh, &QAbstractOAuthReplyHandler::callbackReceived); 178 | 179 | oauth.grant(); 180 | 181 | // First step would be to open browser: catch the signal and verify correct redirect_uri 182 | QTRY_VERIFY(!openBrowserSpy.isEmpty()); 183 | const auto authParms = QUrlQuery{openBrowserSpy.takeFirst().at(0).toUrl()}; 184 | QVERIFY(authParms.hasQueryItem(u"redirect_uri"_s)); 185 | QCOMPARE(authParms.queryItemValue(u"redirect_uri"_s), registered_redirect_uri.toString()); 186 | 187 | // The failure is silent from API point of view (consider user just closing the browser, the 188 | // application would never know) => use log messages 189 | auto cleanup = qScopeGuard([]{ 190 | QLoggingCategory::setFilterRules(u"qt.networkauth.replyhandler=false"_s); 191 | }); 192 | QLoggingCategory::setFilterRules(u"qt.networkauth.replyhandler=true"_s); 193 | QRegularExpression re; 194 | if (matches) 195 | re.setPattern("Url handled*"_L1); 196 | else 197 | re.setPattern("Url ignored*"_L1); 198 | // Don't open the browser but mimic authorization completion by invoking the redirect_uri 199 | QTest::ignoreMessage(QtMsgType::QtDebugMsg, re); 200 | QDesktopServices::openUrl(response_redirect_uri); 201 | if (matches) { 202 | QTRY_VERIFY(!redirectedSpy.isEmpty()); 203 | QCOMPARE(redirectedSpy.takeFirst().at(0).toMap(), result_parameters); 204 | } 205 | } 206 | 207 | void tst_QOAuthUriSchemeReplyHandler::callbackDataReceived_data() 208 | { 209 | QTest::addColumn("response_redirect_uri"); 210 | 211 | QTest::addRow("base_url") << QUrl(u"io:/path"_s); 212 | QTest::addRow("query_parameters") << QUrl(u"io:/path?k1=v1"_s); 213 | } 214 | 215 | void tst_QOAuthUriSchemeReplyHandler::callbackDataReceived() 216 | { 217 | QFETCH(const QUrl, response_redirect_uri); 218 | 219 | QOAuthUriSchemeReplyHandler rh(QUrl{u"io:/path"_s}); 220 | QSignalSpy spy(&rh, &QOAuthUriSchemeReplyHandler::callbackDataReceived); 221 | QVERIFY(rh.isListening()); 222 | 223 | QDesktopServices::openUrl(response_redirect_uri); 224 | QTRY_COMPARE(spy.size(), 1); 225 | QCOMPARE(spy.at(0).at(0).toByteArray(), response_redirect_uri.toEncoded()); 226 | } 227 | 228 | void tst_QOAuthUriSchemeReplyHandler::handleAuthorizationRedirect() 229 | { 230 | QOAuthUriSchemeReplyHandler handler; 231 | QSignalSpy callbackReceivedSpy(&handler, &QOAuthUriSchemeReplyHandler::callbackReceived); 232 | const QUrl redirectUrl(u"com.example.myqtapp:/oauthredirect"_s); 233 | const QUrl validAuthorizationRedirect(u"com.example.myqtapp:/oauthredirect?code=foo"_s); 234 | const QUrl invalidAuthorizationRedirect(u"com.example.wrong.myqtapp:/oauthredirect?code=foo"_s); 235 | handler.setRedirectUrl(redirectUrl); 236 | QVERIFY(!handler.handleAuthorizationRedirect(invalidAuthorizationRedirect)); 237 | QVERIFY(callbackReceivedSpy.isEmpty()); 238 | QVERIFY(handler.handleAuthorizationRedirect(validAuthorizationRedirect)); 239 | QVERIFY(!callbackReceivedSpy.isEmpty()); 240 | QCOMPARE(callbackReceivedSpy.at(0).at(0).toMap().value("code").toString(), u"foo"_s); 241 | } 242 | 243 | QTEST_MAIN(tst_QOAuthUriSchemeReplyHandler) 244 | #include "tst_oauthurischemereplyhandler.moc" 245 | --------------------------------------------------------------------------------