From ae953060e49605ad3bc9c224b14cecd570b58199 Mon Sep 17 00:00:00 2001 From: DockedFerret800 Date: Thu, 25 Sep 2025 22:06:17 +0100 Subject: [PATCH 01/12] Initial support for modules --- .gitignore | 1 + CMakeLists.txt | 89 +++++++++++++++++++++++++++++++--------- example/CMakeLists.txt | 5 ++- example/print-claims.cpp | 5 +++ include/jwt-cpp/base.h | 4 ++ include/jwt-cpp/jwt.h | 5 +++ modules/jwt.ixx | 66 +++++++++++++++++++++++++++++ 7 files changed, 155 insertions(+), 20 deletions(-) create mode 100644 modules/jwt.ixx diff --git a/.gitignore b/.gitignore index a594c29b7..bc177edfd 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ +out/ # Visual Studio 2015 cache/options directory .vs/ diff --git a/CMakeLists.txt b/CMakeLists.txt index c22318810..30f70b642 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,8 @@ if(POLICY CMP0135) # DOWNLOAD_EXTRACT_TIMESTAMP cmake_policy(SET CMP0135 NEW) endif() +set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") + # HUNTER_ENABLED is always set if this package is included in a project using hunter (HunterGate sets it) In this case # we will use hunter as well to stay consistent. If not the use can supply it on configure to force using hunter. if(HUNTER_ENABLED) @@ -20,6 +22,8 @@ option(JWT_BUILD_TESTS "Configure CMake to build tests (or not)" OFF) option(JWT_BUILD_DOCS "Adds a target for building the doxygen documentation" OFF) option(JWT_ENABLE_COVERAGE "Enable code coverage testing" OFF) option(JWT_ENABLE_FUZZING "Enable fuzz testing" OFF) +option(JWT_ENABLE_MODULES "Build C++ modules" OFF) +option(JWT_USE_IMPORT_STD "Use import std" OFF) option(JWT_DISABLE_PICOJSON "Do not provide the picojson template specialiaze" OFF) option(JWT_DISABLE_BASE64 "Do not include the base64 implementation from this library" OFF) @@ -89,50 +93,94 @@ endif() set(JWT_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include) set(JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/jwt.h) +set(JWT_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/modules) foreach(traits ${JWT_JSON_TRAITS_OPTIONS}) list(APPEND JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/traits/${traits}/defaults.h ${JWT_INCLUDE_PATH}/jwt-cpp/traits/${traits}/traits.h) endforeach() if(NOT JWT_DISABLE_BASE64) - list(APPEND JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/base.h) + list(APPEND JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/base.h) endif() -add_library(jwt-cpp INTERFACE) +if (JWT_ENABLE_MODULES) + add_library(jwt-cpp STATIC) + set(JWT_LIBRARY_TYPE PUBLIC) +else() + add_library(jwt-cpp INTERFACE) + set(JWT_LIBRARY_TYPE INTERFACE) +endif() add_library(jwt-cpp::jwt-cpp ALIAS jwt-cpp) # To match export -target_compile_features(jwt-cpp INTERFACE cxx_std_11) + +if (JWT_ENABLE_MODULES) + if(CMAKE_VERSION VERSION_LESS "4.0") + message(FATAL_ERROR "CMake >= 4.0 is required to build with modules") + endif() + + set(CMAKE_CXX_SCAN_FOR_MODULES ON) + + if(JWT_USE_IMPORT_STD) + target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_23) + if (NOT CMAKE_GENERATOR MATCHES "Visual Studio") + set(CMAKE_CXX_MODULE_STD 1) + endif() + else() + target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_20) + endif() + + target_sources(jwt-cpp + PUBLIC + FILE_SET cxx_modules TYPE CXX_MODULES + BASE_DIRS ${JWT_MODULE_PATH} + FILES ${JWT_MODULE_PATH}/jwt.ixx + ) +else() + target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_11) +endif() + +if (JWT_USE_IMPORT_STD) + target_compile_definitions(jwt-cpp ${JWT_LIBRARY_TYPE} JWT_USE_IMPORT_STD) +endif() + if(JWT_DISABLE_BASE64) - target_compile_definitions(jwt-cpp INTERFACE JWT_DISABLE_BASE64) + target_compile_definitions(jwt-cpp ${JWT_LIBRARY_TYPE} JWT_DISABLE_BASE64) endif() if(JWT_DISABLE_PICOJSON) - target_compile_definitions(jwt-cpp INTERFACE JWT_DISABLE_PICOJSON) + target_compile_definitions(jwt-cpp ${JWT_LIBRARY_TYPE} JWT_DISABLE_PICOJSON) endif() + +source_group( + TREE "${JWT_INCLUDE_PATH}" + PREFIX "Implementation files" + FILES ${JWT_HEADER_FILES} +) + include(GNUInstallDirs) include(CMakePackageConfigHelpers) -target_include_directories(jwt-cpp INTERFACE $ +target_include_directories(jwt-cpp ${JWT_LIBRARY_TYPE} $ $) if(${JWT_SSL_LIBRARY} MATCHES "OpenSSL") - target_link_libraries(jwt-cpp INTERFACE OpenSSL::SSL OpenSSL::Crypto) + target_link_libraries(jwt-cpp ${JWT_LIBRARY_TYPE} OpenSSL::SSL OpenSSL::Crypto) endif() if(${JWT_SSL_LIBRARY} MATCHES "LibreSSL") - target_link_libraries(jwt-cpp INTERFACE LibreSSL::TLS) + target_link_libraries(jwt-cpp ${JWT_LIBRARY_TYPE} LibreSSL::TLS) endif() if(${JWT_SSL_LIBRARY} MATCHES "wolfSSL") - target_link_libraries(jwt-cpp INTERFACE PkgConfig::wolfssl) + target_link_libraries(jwt-cpp ${JWT_LIBRARY_TYPE} PkgConfig::wolfssl) # This is required to access OpenSSL compatibility API - target_include_directories(jwt-cpp INTERFACE ${wolfssl_INCLUDE_DIRS}) + target_include_directories(jwt-cpp ${JWT_LIBRARY_TYPE} ${wolfssl_INCLUDE_DIRS}) # This flag is required to have the mandatory header included automatically # https://github.com/Thalhammer/jwt-cpp/pull/352#discussion_r1627971786 # https://github.com/wolfSSL/wolfssl/blob/3b74a6402998a8b8839e25e31ba8ac74749aa9b0/wolfssl/wolfcrypt/settings.h#L58 - target_compile_definitions(jwt-cpp INTERFACE EXTERNAL_OPTS_OPENVPN) + target_compile_definitions(jwt-cpp ${JWT_LIBRARY_TYPE} EXTERNAL_OPTS_OPENVPN) endif() if(NOT JWT_DISABLE_PICOJSON AND JWT_EXTERNAL_PICOJSON) - target_link_libraries(jwt-cpp INTERFACE picojson::picojson) + target_link_libraries(jwt-cpp ${JWT_LIBRARY_TYPE} picojson::picojson) endif() # Hunter needs relative paths so the files are placed correctly @@ -143,18 +191,21 @@ endif() configure_package_config_file( ${CMAKE_CURRENT_LIST_DIR}/cmake/jwt-cpp-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config.cmake INSTALL_DESTINATION ${JWT_CMAKE_FILES_INSTALL_DIR}) -write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config-version.cmake VERSION 0.7.1 - COMPATIBILITY ExactVersion) - -install(TARGETS jwt-cpp EXPORT jwt-cpp-targets PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config-version.cmake VERSION 0.7.1 COMPATIBILITY ExactVersion) +if (JWT_ENABLE_MODULES) + install(TARGETS jwt-cpp EXPORT jwt-cpp-targets + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILE_SET cxx_modules DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/modules) +else() + install(TARGETS jwt-cpp EXPORT jwt-cpp-targets + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif() install(EXPORT jwt-cpp-targets NAMESPACE jwt-cpp:: FILE jwt-cpp-targets.cmake DESTINATION ${JWT_CMAKE_FILES_INSTALL_DIR}) install(DIRECTORY ${JWT_INCLUDE_PATH}/jwt-cpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) if(NOT JWT_EXTERNAL_PICOJSON AND NOT JWT_DISABLE_PICOJSON) install(FILES ${JWT_INCLUDE_PATH}/picojson/picojson.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/picojson) endif() -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config-version.cmake - DESTINATION ${JWT_CMAKE_FILES_INSTALL_DIR}) if(JWT_BUILD_EXAMPLES) add_subdirectory(example) @@ -171,4 +222,4 @@ endif() if(JWT_BUILD_DOCS) add_subdirectory(docs) -endif() +endif() \ No newline at end of file diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 3f87f424e..56dc3a2d9 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.15) project(jwt-cpp-examples) if(NOT TARGET jwt-cpp) @@ -14,6 +14,9 @@ endif() add_executable(print-claims print-claims.cpp) target_link_libraries(print-claims jwt-cpp::jwt-cpp) add_custom_target(print-claims-run COMMAND print-claims) +if (JWT_ENABLE_MODULES) + target_compile_definitions(print-claims PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(private-claims private-claims.cpp) target_link_libraries(private-claims jwt-cpp::jwt-cpp) diff --git a/example/print-claims.cpp b/example/print-claims.cpp index 15badcc9f..2f428e7fe 100644 --- a/example/print-claims.cpp +++ b/example/print-claims.cpp @@ -1,6 +1,11 @@ /// @file print-claims.cpp #include + +#ifndef JWT_ENABLE_MODULES #include +#else +import jwt_cpp; +#endif int main() { const std::string token = diff --git a/include/jwt-cpp/base.h b/include/jwt-cpp/base.h index 7258b2e70..912b84821 100644 --- a/include/jwt-cpp/base.h +++ b/include/jwt-cpp/base.h @@ -1,12 +1,16 @@ #ifndef JWT_CPP_BASE_H #define JWT_CPP_BASE_H +#ifdef JWT_USE_IMPORT_STD +import std; +#else #include #include #include #include #include #include +#endif #ifdef __has_cpp_attribute #if __has_cpp_attribute(fallthrough) diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index 80d8b95ef..65219b878 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -21,6 +21,9 @@ #include #include +#ifdef JWT_USE_IMPORT_STD +import std; +#else #include #include #include @@ -45,6 +48,8 @@ #endif #endif +#endif + #if OPENSSL_VERSION_NUMBER >= 0x30000000L // 3.0.0 #define JWT_OPENSSL_3_0 #include diff --git a/modules/jwt.ixx b/modules/jwt.ixx new file mode 100644 index 000000000..597eb5118 --- /dev/null +++ b/modules/jwt.ixx @@ -0,0 +1,66 @@ +module; + +#ifndef NOMINMAX +#define NOMINMAX 1 +#endif + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif + +#ifndef JWT_USE_IMPORT_STD +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#endif + +export module jwt_cpp; + +export { +#include "jwt-cpp/jwt.h" +} \ No newline at end of file From 1e4a461df45640c560e22e1c1462918b97ed3a5a Mon Sep 17 00:00:00 2001 From: DockedFerret800 Date: Thu, 25 Sep 2025 22:34:44 +0100 Subject: [PATCH 02/12] Wider modules coverage for examples --- example/CMakeLists.txt | 15 +++++++++++++++ example/es256k.cpp | 6 ++++++ example/jwks-verify.cpp | 6 ++++++ example/private-claims.cpp | 9 +++++++-- example/rsa-create.cpp | 6 ++++++ example/rsa-verify.cpp | 6 ++++++ 6 files changed, 46 insertions(+), 2 deletions(-) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 56dc3a2d9..ffd04118d 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -21,21 +21,36 @@ endif() add_executable(private-claims private-claims.cpp) target_link_libraries(private-claims jwt-cpp::jwt-cpp) add_custom_target(private-claims-run COMMAND private-claims) +if (JWT_ENABLE_MODULES) + target_compile_definitions(private-claims PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(rsa-create rsa-create.cpp) target_link_libraries(rsa-create jwt-cpp::jwt-cpp) add_custom_target(rsa-create-run COMMAND rsa-create) +if (JWT_ENABLE_MODULES) + target_compile_definitions(rsa-create PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(rsa-verify rsa-verify.cpp) target_link_libraries(rsa-verify jwt-cpp::jwt-cpp) add_custom_target(rsa-verify-run COMMAND rsa-verify) +if (JWT_ENABLE_MODULES) + target_compile_definitions(rsa-verify PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(jwks-verify jwks-verify.cpp) target_link_libraries(jwks-verify jwt-cpp::jwt-cpp) add_custom_target(jwks-verify-run COMMAND jwks-verify) +if (JWT_ENABLE_MODULES) + target_compile_definitions(jwks-verify PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(es256k es256k.cpp) target_link_libraries(es256k jwt-cpp::jwt-cpp) +if (JWT_ENABLE_MODULES) + target_compile_definitions(es256k PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(partial-claim-verifier partial-claim-verifier.cpp) target_link_libraries(partial-claim-verifier jwt-cpp::jwt-cpp nlohmann_json::nlohmann_json) diff --git a/example/es256k.cpp b/example/es256k.cpp index 0ba701927..3e8d8caf3 100644 --- a/example/es256k.cpp +++ b/example/es256k.cpp @@ -1,6 +1,12 @@ /// @file es256k.cpp #include +#include + +#ifndef JWT_ENABLE_MODULES #include +#else +import jwt_cpp; +#endif int main() { // openssl ecparam -name secp256k1 -genkey -noout -out ec-secp256k1-priv-key.pem diff --git a/example/jwks-verify.cpp b/example/jwks-verify.cpp index fa966e35a..38725c10d 100644 --- a/example/jwks-verify.cpp +++ b/example/jwks-verify.cpp @@ -5,7 +5,13 @@ * and using the corresponding x5c from the JWK to verify the token */ #include +#include + +#ifndef JWT_ENABLE_MODULES #include +#else +import jwt_cpp; +#endif #include int main() { diff --git a/example/private-claims.cpp b/example/private-claims.cpp index f2718989d..948dc2cd5 100644 --- a/example/private-claims.cpp +++ b/example/private-claims.cpp @@ -1,8 +1,13 @@ /// @file private-claims.cpp -#include - #include #include +#include + +#ifndef JWT_ENABLE_MODULES +#include +#else +import jwt_cpp; +#endif using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/rsa-create.cpp b/example/rsa-create.cpp index 2243f2689..b70501b59 100644 --- a/example/rsa-create.cpp +++ b/example/rsa-create.cpp @@ -1,6 +1,12 @@ /// @file rsa-create.cpp #include +#include + +#ifndef JWT_ENABLE_MODULES #include +#else +import jwt_cpp; +#endif int main() { std::string const rsa_priv_key = R"(-----BEGIN PRIVATE KEY----- diff --git a/example/rsa-verify.cpp b/example/rsa-verify.cpp index c8240b49f..e2ed79127 100644 --- a/example/rsa-verify.cpp +++ b/example/rsa-verify.cpp @@ -1,6 +1,12 @@ /// \file rsa-verify.cpp #include +#include + +#ifndef JWT_ENABLE_MODULES #include +#else +import jwt_cpp; +#endif int main() { const std::string rsa_pub_key = R"(-----BEGIN PUBLIC KEY----- From 4545447d723bb10eb9ecf05d953038fabaaa33f4 Mon Sep 17 00:00:00 2001 From: DockedFerret800 Date: Wed, 1 Oct 2025 22:02:53 +0100 Subject: [PATCH 03/12] Return missing installation instructions --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 30f70b642..4a501c6eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,6 +206,7 @@ install(DIRECTORY ${JWT_INCLUDE_PATH}/jwt-cpp DESTINATION ${CMAKE_INSTALL_INCLUD if(NOT JWT_EXTERNAL_PICOJSON AND NOT JWT_DISABLE_PICOJSON) install(FILES ${JWT_INCLUDE_PATH}/picojson/picojson.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/picojson) endif() +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config-version.cmake DESTINATION ${JWT_CMAKE_FILES_INSTALL_DIR}) if(JWT_BUILD_EXAMPLES) add_subdirectory(example) From bd4efd451fb254c544c2f0a93cc9deb0af0a16bb Mon Sep 17 00:00:00 2001 From: DockedFerret800 Date: Sat, 3 Jan 2026 18:59:18 +0000 Subject: [PATCH 04/12] Slightly change export approach --- include/jwt-cpp/traits/nlohmann-json/traits.h | 6 +- modules/jwt.ixx | 61 ++++++++++++++++++- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/include/jwt-cpp/traits/nlohmann-json/traits.h b/include/jwt-cpp/traits/nlohmann-json/traits.h index 272f3d331..c031ba6d0 100644 --- a/include/jwt-cpp/traits/nlohmann-json/traits.h +++ b/include/jwt-cpp/traits/nlohmann-json/traits.h @@ -1,7 +1,11 @@ #ifndef JWT_CPP_NLOHMANN_JSON_TRAITS_H #define JWT_CPP_NLOHMANN_JSON_TRAITS_H -#include "jwt-cpp/jwt.h" +#ifndef JWT_ENABLE_MODULES +#include +#else +import jwt_cpp; +#endif #include "nlohmann/json.hpp" namespace jwt { diff --git a/modules/jwt.ixx b/modules/jwt.ixx index 597eb5118..31b91e092 100644 --- a/modules/jwt.ixx +++ b/modules/jwt.ixx @@ -59,8 +59,65 @@ module; #include #endif +#include "jwt-cpp/jwt.h" + export module jwt_cpp; -export { -#include "jwt-cpp/jwt.h" +export using ::operator>>; +export using ::operator<<; + +export namespace jwt { + using jwt::verify; + using jwt::decode; + using jwt::create; + using jwt::claim; + using jwt::date; + using jwt::parse_jwk; + using jwt::parse_jwks; +} + +export namespace jwt::algorithm { + using jwt::algorithm::ecdsa; + using jwt::algorithm::ed25519; + using jwt::algorithm::ed448; + using jwt::algorithm::eddsa; + using jwt::algorithm::es256; + using jwt::algorithm::es256k; + using jwt::algorithm::es384; + using jwt::algorithm::es512; + using jwt::algorithm::hmacsha; + using jwt::algorithm::hs256; + using jwt::algorithm::hs384; + using jwt::algorithm::hs512; + using jwt::algorithm::none; + using jwt::algorithm::ps256; + using jwt::algorithm::ps384; + using jwt::algorithm::ps512; + using jwt::algorithm::pss; + using jwt::algorithm::rs256; + using jwt::algorithm::rs384; + using jwt::algorithm::rs512; + using jwt::algorithm::rsa; +} + +export namespace jwt::base { + using jwt::base::encode; +} + +export namespace jwt::alphabet { + using jwt::alphabet::base64url; +} + +export namespace jwt::helper { + using jwt::helper::convert_base64_der_to_pem; + using jwt::helper::create_public_key_from_rsa_components; +} + +export namespace jwt::error { + using jwt::error::make_error_code; + using jwt::error::invalid_json_exception; + using jwt::error::claim_not_present_exception; + using jwt::error::token_verification_error; + using jwt::error::token_verification_exception; + using jwt::error::token_verification_error_category; } \ No newline at end of file From 4c110bae03c1a756c71af462ad0fe3062c00010e Mon Sep 17 00:00:00 2001 From: DockedFerret800 Date: Tue, 24 Mar 2026 23:29:01 +0000 Subject: [PATCH 05/12] Use ABI-Breaking style for modules wrapper --- CMakeLists.txt | 49 ++++++------ example/es256k.cpp | 10 ++- example/jwks-verify.cpp | 12 ++- example/partial-claim-verifier.cpp | 4 +- example/print-claims.cpp | 7 +- example/private-claims.cpp | 17 ++-- example/rsa-create.cpp | 10 ++- example/rsa-verify.cpp | 10 ++- example/traits/boost-json.cpp | 4 +- example/traits/danielaparker-jsoncons.cpp | 4 +- example/traits/kazuho-picojson.cpp | 4 +- example/traits/nlohmann-json.cpp | 4 +- .../traits/open-source-parsers-jsoncpp.cpp | 4 +- include/jwt-cpp/base.h | 77 +++++++++--------- include/jwt-cpp/jwt.h | 5 +- include/jwt-cpp/traits/boost-json/traits.h | 4 + .../traits/danielaparker-jsoncons/traits.h | 4 + .../jwt-cpp/traits/kazuho-picojson/traits.h | 4 + include/jwt-cpp/traits/nlohmann-json/traits.h | 6 +- .../open-source-parsers-jsoncpp/traits.h | 4 + include/picojson/picojson.h | 19 ++++- modules/jwt.ixx | 78 +++++-------------- tests/CMakeLists.txt | 4 + tests/ClaimTest.cpp | 6 +- tests/HelperTest.cpp | 6 +- tests/JwksTest.cpp | 6 +- tests/OpenSSLErrorTest.cpp | 7 +- tests/TokenFormatTest.cpp | 8 +- tests/TokenTest.cpp | 8 +- tests/traits/BoostJsonTest.cpp | 4 +- tests/traits/JsonconsTest.cpp | 4 +- tests/traits/NlohmannTest.cpp | 4 +- tests/traits/OspJsoncppTest.cpp | 4 +- tests/traits/TraitsTest.cpp.mustache | 4 +- 34 files changed, 234 insertions(+), 171 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a501c6eb..ccc2a3c1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ if(POLICY CMP0135) # DOWNLOAD_EXTRACT_TIMESTAMP cmake_policy(SET CMP0135 NEW) endif() -set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") +set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "451f2fe2-a8a2-47c3-bc32-94786d8fc91b") # HUNTER_ENABLED is always set if this package is included in a project using hunter (HunterGate sets it) In this case # we will use hunter as well to stay consistent. If not the use can supply it on configure to force using hunter. @@ -103,6 +103,20 @@ if(NOT JWT_DISABLE_BASE64) list(APPEND JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/base.h) endif() +if (JWT_ENABLE_MODULES) + if(CMAKE_VERSION VERSION_LESS "4.3") + message(FATAL_ERROR "CMake >= 4.3 is required to build with modules") + endif() + + set(CMAKE_CXX_SCAN_FOR_MODULES ON) + + if(JWT_USE_IMPORT_STD) + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio") + set(CMAKE_CXX_MODULE_STD 1) + endif() + endif() +endif() + if (JWT_ENABLE_MODULES) add_library(jwt-cpp STATIC) set(JWT_LIBRARY_TYPE PUBLIC) @@ -112,34 +126,21 @@ else() endif() add_library(jwt-cpp::jwt-cpp ALIAS jwt-cpp) # To match export -if (JWT_ENABLE_MODULES) - if(CMAKE_VERSION VERSION_LESS "4.0") - message(FATAL_ERROR "CMake >= 4.0 is required to build with modules") - endif() - - set(CMAKE_CXX_SCAN_FOR_MODULES ON) - - if(JWT_USE_IMPORT_STD) - target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_23) - if (NOT CMAKE_GENERATOR MATCHES "Visual Studio") - set(CMAKE_CXX_MODULE_STD 1) - endif() +if(NOT JWT_ENABLE_MODULES) + target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_11) +else() + if(NOT JWT_USE_IMPORT_STD) + target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_20) else() - target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_20) + target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_23) + target_compile_definitions(jwt-cpp PRIVATE JWT_USE_IMPORT_STD) endif() - - target_sources(jwt-cpp + target_sources(jwt-cpp PUBLIC FILE_SET cxx_modules TYPE CXX_MODULES BASE_DIRS ${JWT_MODULE_PATH} FILES ${JWT_MODULE_PATH}/jwt.ixx - ) -else() - target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_11) -endif() - -if (JWT_USE_IMPORT_STD) - target_compile_definitions(jwt-cpp ${JWT_LIBRARY_TYPE} JWT_USE_IMPORT_STD) + ) endif() if(JWT_DISABLE_BASE64) @@ -223,4 +224,4 @@ endif() if(JWT_BUILD_DOCS) add_subdirectory(docs) -endif() \ No newline at end of file +endif() diff --git a/example/es256k.cpp b/example/es256k.cpp index 3e8d8caf3..c8d599095 100644 --- a/example/es256k.cpp +++ b/example/es256k.cpp @@ -1,10 +1,16 @@ /// @file es256k.cpp -#include -#include #ifndef JWT_ENABLE_MODULES +#include +#include #include #else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include +#include +#endif import jwt_cpp; #endif diff --git a/example/jwks-verify.cpp b/example/jwks-verify.cpp index 38725c10d..5918ee02b 100644 --- a/example/jwks-verify.cpp +++ b/example/jwks-verify.cpp @@ -4,15 +4,21 @@ * Novel example using a JWT's "key ID" to match with a JWK Set * and using the corresponding x5c from the JWK to verify the token */ -#include -#include +#include #ifndef JWT_ENABLE_MODULES +#include +#include #include #else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include +#include +#endif import jwt_cpp; #endif -#include int main() { std::string raw_jwks = diff --git a/example/partial-claim-verifier.cpp b/example/partial-claim-verifier.cpp index 0ca427b17..a347a3fd3 100644 --- a/example/partial-claim-verifier.cpp +++ b/example/partial-claim-verifier.cpp @@ -1,8 +1,8 @@ /// @file partial-claim-verifier.cpp -#include "jwt-cpp/traits/nlohmann-json/defaults.h" - #include +#include "jwt-cpp/traits/nlohmann-json/defaults.h" + int main() { std::string const rsa_priv_key = R"(-----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4ZtdaIrd1BPIJ diff --git a/example/print-claims.cpp b/example/print-claims.cpp index 2f428e7fe..56ae1038d 100644 --- a/example/print-claims.cpp +++ b/example/print-claims.cpp @@ -1,9 +1,14 @@ /// @file print-claims.cpp -#include #ifndef JWT_ENABLE_MODULES +#include #include #else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include +#endif import jwt_cpp; #endif diff --git a/example/private-claims.cpp b/example/private-claims.cpp index 948dc2cd5..068ea01f1 100644 --- a/example/private-claims.cpp +++ b/example/private-claims.cpp @@ -1,11 +1,18 @@ /// @file private-claims.cpp -#include -#include -#include #ifndef JWT_ENABLE_MODULES +#include +#include +#include #include #else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include +#include +#include +#endif import jwt_cpp; #endif @@ -18,7 +25,7 @@ int main() { iss >> from_raw_json; jwt::claim::set_t list{"once", "twice"}; - std::vector big_numbers{727663072ULL, 770979831ULL, 427239169ULL, 525936436ULL}; + std::vector big_numbers{727663072ULL, 770979831ULL, 427239169ULL, 525936436ULL}; const auto time = jwt::date::clock::now(); const auto token = jwt::create() @@ -29,7 +36,7 @@ int main() { .set_not_before(time - sec{15}) .set_expires_at(time + sec{15} + min{2}) .set_payload_claim("boolean", picojson::value(true)) - .set_payload_claim("integer", picojson::value(int64_t{12345})) + .set_payload_claim("integer", picojson::value(std::int64_t{12345})) .set_payload_claim("precision", picojson::value(12.345)) .set_payload_claim("strings", jwt::claim(list)) .set_payload_claim("array", jwt::claim(big_numbers.begin(), big_numbers.end())) diff --git a/example/rsa-create.cpp b/example/rsa-create.cpp index b70501b59..fb1df648b 100644 --- a/example/rsa-create.cpp +++ b/example/rsa-create.cpp @@ -1,10 +1,16 @@ /// @file rsa-create.cpp -#include -#include #ifndef JWT_ENABLE_MODULES +#include +#include #include #else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include +#include +#endif import jwt_cpp; #endif diff --git a/example/rsa-verify.cpp b/example/rsa-verify.cpp index e2ed79127..787784630 100644 --- a/example/rsa-verify.cpp +++ b/example/rsa-verify.cpp @@ -1,10 +1,16 @@ /// \file rsa-verify.cpp -#include -#include #ifndef JWT_ENABLE_MODULES +#include +#include #include #else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include +#include +#endif import jwt_cpp; #endif diff --git a/example/traits/boost-json.cpp b/example/traits/boost-json.cpp index 6f6399db6..25912b5c7 100644 --- a/example/traits/boost-json.cpp +++ b/example/traits/boost-json.cpp @@ -1,9 +1,9 @@ -#include "jwt-cpp/traits/boost-json/traits.h" - // #include // You may require this if you are not building it elsewhere #include #include +#include "jwt-cpp/traits/boost-json/traits.h" + int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/danielaparker-jsoncons.cpp b/example/traits/danielaparker-jsoncons.cpp index 61043deb0..c3a5dda8f 100644 --- a/example/traits/danielaparker-jsoncons.cpp +++ b/example/traits/danielaparker-jsoncons.cpp @@ -1,8 +1,8 @@ -#include "jwt-cpp/traits/danielaparker-jsoncons/traits.h" - #include #include +#include "jwt-cpp/traits/danielaparker-jsoncons/traits.h" + int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/kazuho-picojson.cpp b/example/traits/kazuho-picojson.cpp index 4bdf4a078..fade710c0 100644 --- a/example/traits/kazuho-picojson.cpp +++ b/example/traits/kazuho-picojson.cpp @@ -1,8 +1,8 @@ -#include "jwt-cpp/traits/kazuho-picojson/traits.h" - #include #include +#include "jwt-cpp/traits/kazuho-picojson/traits.h" + int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/nlohmann-json.cpp b/example/traits/nlohmann-json.cpp index f0bb1d5d7..f4147f115 100644 --- a/example/traits/nlohmann-json.cpp +++ b/example/traits/nlohmann-json.cpp @@ -1,8 +1,8 @@ -#include "jwt-cpp/traits/nlohmann-json/traits.h" - #include #include +#include "jwt-cpp/traits/nlohmann-json/traits.h" + int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/open-source-parsers-jsoncpp.cpp b/example/traits/open-source-parsers-jsoncpp.cpp index 523925c10..eb503efc6 100644 --- a/example/traits/open-source-parsers-jsoncpp.cpp +++ b/example/traits/open-source-parsers-jsoncpp.cpp @@ -1,8 +1,8 @@ -#include "jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h" - #include #include +#include "jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h" + int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/include/jwt-cpp/base.h b/include/jwt-cpp/base.h index 912b84821..17c800147 100644 --- a/include/jwt-cpp/base.h +++ b/include/jwt-cpp/base.h @@ -1,11 +1,12 @@ #ifndef JWT_CPP_BASE_H #define JWT_CPP_BASE_H -#ifdef JWT_USE_IMPORT_STD +#if !defined(JWT_CPP_MODULE_INTERFACE_BUILD) && defined(JWT_USE_IMPORT_STD) import std; -#else +#elif !defined(JWT_CPP_MODULE_INTERFACE_BUILD) #include #include +#include #include #include #include @@ -42,8 +43,8 @@ namespace jwt { 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}}; return data; } - static const std::array& rdata() { - static constexpr std::array rdata{{ + static const std::array& rdata() { + static constexpr std::array rdata{{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, @@ -81,8 +82,8 @@ namespace jwt { 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}}; return data; } - static const std::array& rdata() { - static constexpr std::array rdata{{ + static const std::array& rdata() { + static constexpr std::array rdata{{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, @@ -118,8 +119,8 @@ namespace jwt { 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}}; return data; } - static const std::array& rdata() { - static constexpr std::array rdata{{ + static const std::array& rdata() { + static constexpr std::array rdata{{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, @@ -141,10 +142,10 @@ namespace jwt { }; } // namespace helper - inline uint32_t index(const std::array& rdata, char symbol) { + inline std::uint32_t index(const std::array& rdata, char symbol) { auto index = rdata[static_cast(symbol)]; if (index <= -1) { throw std::runtime_error("Invalid input: not within alphabet"); } - return static_cast(index); + return static_cast(index); } } // namespace alphabet @@ -154,11 +155,11 @@ namespace jwt { namespace base { namespace details { struct padding { - size_t count = 0; - size_t length = 0; + std::size_t count = 0; + std::size_t length = 0; padding() = default; - padding(size_t count, size_t length) : count(count), length(length) {} + padding(std::size_t count, std::size_t length) : count(count), length(length) {} padding operator+(const padding& p) { return padding(count + p.count, length + p.length); } @@ -182,17 +183,17 @@ namespace jwt { inline std::string encode(const std::string& bin, const std::array& alphabet, const std::string& fill) { - size_t size = bin.size(); + std::size_t size = bin.size(); std::string res; // clear incomplete bytes - size_t fast_size = size - size % 3; - for (size_t i = 0; i < fast_size;) { - uint32_t octet_a = static_cast(bin[i++]); - uint32_t octet_b = static_cast(bin[i++]); - uint32_t octet_c = static_cast(bin[i++]); + std::size_t fast_size = size - size % 3; + for (std::size_t i = 0; i < fast_size;) { + std::uint32_t octet_a = static_cast(bin[i++]); + std::uint32_t octet_b = static_cast(bin[i++]); + std::uint32_t octet_c = static_cast(bin[i++]); - uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + std::uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; res += alphabet[(triple >> 3 * 6) & 0x3F]; res += alphabet[(triple >> 2 * 6) & 0x3F]; @@ -202,13 +203,13 @@ namespace jwt { if (fast_size == size) return res; - size_t mod = size % 3; + std::size_t mod = size % 3; - uint32_t octet_a = fast_size < size ? static_cast(bin[fast_size++]) : 0; - uint32_t octet_b = fast_size < size ? static_cast(bin[fast_size++]) : 0; - uint32_t octet_c = fast_size < size ? static_cast(bin[fast_size++]) : 0; + std::uint32_t octet_a = fast_size < size ? static_cast(bin[fast_size++]) : 0; + std::uint32_t octet_b = fast_size < size ? static_cast(bin[fast_size++]) : 0; + std::uint32_t octet_c = fast_size < size ? static_cast(bin[fast_size++]) : 0; - uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + std::uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; switch (mod) { case 1: @@ -229,28 +230,28 @@ namespace jwt { return res; } - inline std::string decode(const std::string& base, const std::array& rdata, + inline std::string decode(const std::string& base, const std::array& rdata, const std::vector& fill) { const auto pad = count_padding(base, fill); if (pad.count > 2) throw std::runtime_error("Invalid input: too much fill"); - const size_t size = base.size() - pad.length; + const std::size_t size = base.size() - pad.length; if ((size + pad.count) % 4 != 0) throw std::runtime_error("Invalid input: incorrect total size"); - size_t out_size = size / 4 * 3; + std::size_t out_size = size / 4 * 3; std::string res; res.reserve(out_size); - auto get_sextet = [&](size_t offset) { return alphabet::index(rdata, base[offset]); }; + auto get_sextet = [&](std::size_t offset) { return alphabet::index(rdata, base[offset]); }; - size_t fast_size = size - size % 4; - for (size_t i = 0; i < fast_size;) { - uint32_t sextet_a = get_sextet(i++); - uint32_t sextet_b = get_sextet(i++); - uint32_t sextet_c = get_sextet(i++); - uint32_t sextet_d = get_sextet(i++); + std::size_t fast_size = size - size % 4; + for (std::size_t i = 0; i < fast_size;) { + std::uint32_t sextet_a = get_sextet(i++); + std::uint32_t sextet_b = get_sextet(i++); + std::uint32_t sextet_c = get_sextet(i++); + std::uint32_t sextet_d = get_sextet(i++); - uint32_t triple = + std::uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6); res += static_cast((triple >> 2 * 8) & 0xFFU); @@ -260,7 +261,7 @@ namespace jwt { if (pad.count == 0) return res; - uint32_t triple = (get_sextet(fast_size) << 3 * 6) + (get_sextet(fast_size + 1) << 2 * 6); + std::uint32_t triple = (get_sextet(fast_size) << 3 * 6) + (get_sextet(fast_size + 1) << 2 * 6); switch (pad.count) { case 1: @@ -275,7 +276,7 @@ namespace jwt { return res; } - inline std::string decode(const std::string& base, const std::array& rdata, + inline std::string decode(const std::string& base, const std::array& rdata, const std::string& fill) { return decode(base, rdata, std::vector{fill}); } diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index 65219b878..04010f149 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -12,6 +12,7 @@ #include "base.h" #endif +#ifndef JWT_CPP_MODULE_INTERFACE_BUILD #include #include #include @@ -47,12 +48,14 @@ import std; #endif #endif #endif - +#endif #endif #if OPENSSL_VERSION_NUMBER >= 0x30000000L // 3.0.0 #define JWT_OPENSSL_3_0 +#ifndef JWT_CPP_MODULE_INTERFACE_BUILD #include +#endif #elif OPENSSL_VERSION_NUMBER >= 0x10101000L // 1.1.1 #define JWT_OPENSSL_1_1_1 #elif OPENSSL_VERSION_NUMBER >= 0x10100000L // 1.1.0 diff --git a/include/jwt-cpp/traits/boost-json/traits.h b/include/jwt-cpp/traits/boost-json/traits.h index a421bfd09..a3c6989f1 100644 --- a/include/jwt-cpp/traits/boost-json/traits.h +++ b/include/jwt-cpp/traits/boost-json/traits.h @@ -2,7 +2,11 @@ #define JWT_CPP_BOOSTJSON_TRAITS_H #define JWT_DISABLE_PICOJSON +#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +import jwt_cpp; +#else #include "jwt-cpp/jwt.h" +#endif #include // if not boost JSON standalone then error... diff --git a/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h b/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h index 6ae8977a6..2f544eabf 100644 --- a/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h +++ b/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h @@ -5,7 +5,11 @@ #define JSONCONS_NO_DEPRECATED #include "jsoncons/json.hpp" +#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +import jwt_cpp; +#else #include "jwt-cpp/jwt.h" +#endif #include diff --git a/include/jwt-cpp/traits/kazuho-picojson/traits.h b/include/jwt-cpp/traits/kazuho-picojson/traits.h index 27a11df4d..2e759cd42 100644 --- a/include/jwt-cpp/traits/kazuho-picojson/traits.h +++ b/include/jwt-cpp/traits/kazuho-picojson/traits.h @@ -9,7 +9,11 @@ #ifndef JWT_DISABLE_PICOJSON #define JWT_DISABLE_PICOJSON #endif +#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +import jwt_cpp; +#else #include "jwt-cpp/jwt.h" +#endif namespace jwt { /** diff --git a/include/jwt-cpp/traits/nlohmann-json/traits.h b/include/jwt-cpp/traits/nlohmann-json/traits.h index c031ba6d0..50485aab7 100644 --- a/include/jwt-cpp/traits/nlohmann-json/traits.h +++ b/include/jwt-cpp/traits/nlohmann-json/traits.h @@ -1,10 +1,10 @@ #ifndef JWT_CPP_NLOHMANN_JSON_TRAITS_H #define JWT_CPP_NLOHMANN_JSON_TRAITS_H -#ifndef JWT_ENABLE_MODULES -#include -#else +#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) import jwt_cpp; +#else +#include #endif #include "nlohmann/json.hpp" diff --git a/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h b/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h index 400206e4e..2b297f914 100644 --- a/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h +++ b/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h @@ -1,7 +1,11 @@ #ifndef JWT_CPP_JSONCPP_TRAITS_H #define JWT_CPP_JSONCPP_TRAITS_H +#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +import jwt_cpp; +#else #include "jwt-cpp/jwt.h" +#endif #include "json/json.h" namespace jwt { diff --git a/include/picojson/picojson.h b/include/picojson/picojson.h index 76742fe06..ed1cce8cd 100644 --- a/include/picojson/picojson.h +++ b/include/picojson/picojson.h @@ -28,6 +28,13 @@ #ifndef picojson_h #define picojson_h +#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) && defined(JWT_USE_IMPORT_STD) +#define PICOJSON_USE_IMPORTED_STD 1 +#else +#define PICOJSON_USE_IMPORTED_STD 0 +#endif + +#if PICOJSON_USE_IMPORTED_STD #include #include #include @@ -41,10 +48,13 @@ #include #include #include +#endif // for isnan/isinf #if __cplusplus >= 201103L +#if !PICOJSON_USE_IMPORTED_STD #include +#endif #else extern "C" { #ifdef _MSC_VER @@ -76,6 +86,7 @@ extern "C" { // experimental support for int64_t (see README.mkdn for detail) #ifdef PICOJSON_USE_INT64 #define __STDC_FORMAT_MACROS +#if !PICOJSON_USE_IMPORTED_STD #include #if __cplusplus >= 201103L #include @@ -85,12 +96,13 @@ extern "C" { } #endif #endif +#endif // to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0 #ifndef PICOJSON_USE_LOCALE #define PICOJSON_USE_LOCALE 1 #endif -#if PICOJSON_USE_LOCALE +#if PICOJSON_USE_LOCALE && !PICOJSON_USE_IMPORTED_STD extern "C" { #include } @@ -493,7 +505,8 @@ inline std::string value::to_str() const { case number_type: { char buf[256]; double tmp; - SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_); + SNPRINTF(buf, sizeof(buf), std::fabs(u_.number_) < (1ULL << 53) && std::modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", + u_.number_); #if PICOJSON_USE_LOCALE char *decimal_point = localeconv()->decimal_point; if (strcmp(decimal_point, ".") != 0) { @@ -1197,4 +1210,6 @@ inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) { #pragma warning(pop) #endif +#undef PICOJSON_USE_IMPORTED_STD + #endif diff --git a/modules/jwt.ixx b/modules/jwt.ixx index 31b91e092..77fb4ac1a 100644 --- a/modules/jwt.ixx +++ b/modules/jwt.ixx @@ -44,6 +44,15 @@ module; #include #include #include +#else +#include +#include +#include +#include +#include +#include +#include +#include #endif #include @@ -59,65 +68,18 @@ module; #include #endif -#include "jwt-cpp/jwt.h" - export module jwt_cpp; -export using ::operator>>; -export using ::operator<<; - -export namespace jwt { - using jwt::verify; - using jwt::decode; - using jwt::create; - using jwt::claim; - using jwt::date; - using jwt::parse_jwk; - using jwt::parse_jwks; -} - -export namespace jwt::algorithm { - using jwt::algorithm::ecdsa; - using jwt::algorithm::ed25519; - using jwt::algorithm::ed448; - using jwt::algorithm::eddsa; - using jwt::algorithm::es256; - using jwt::algorithm::es256k; - using jwt::algorithm::es384; - using jwt::algorithm::es512; - using jwt::algorithm::hmacsha; - using jwt::algorithm::hs256; - using jwt::algorithm::hs384; - using jwt::algorithm::hs512; - using jwt::algorithm::none; - using jwt::algorithm::ps256; - using jwt::algorithm::ps384; - using jwt::algorithm::ps512; - using jwt::algorithm::pss; - using jwt::algorithm::rs256; - using jwt::algorithm::rs384; - using jwt::algorithm::rs512; - using jwt::algorithm::rsa; -} - -export namespace jwt::base { - using jwt::base::encode; -} - -export namespace jwt::alphabet { - using jwt::alphabet::base64url; -} +#ifdef JWT_USE_IMPORT_STD +// Keep std private to jwt_cpp. Re-exporting it makes mixed consumers +// (gtest, iostream, third-party JSON headers) collide with the MSVC std module. +import std; +#endif -export namespace jwt::helper { - using jwt::helper::convert_base64_der_to_pem; - using jwt::helper::create_public_key_from_rsa_components; +// Build the public headers in module purview so imported declarations are +// attached to jwt_cpp instead of the global module. +#define JWT_CPP_MODULE_INTERFACE_BUILD 1 +export { +#include "jwt-cpp/jwt.h" } - -export namespace jwt::error { - using jwt::error::make_error_code; - using jwt::error::invalid_json_exception; - using jwt::error::claim_not_present_exception; - using jwt::error::token_verification_error; - using jwt::error::token_verification_exception; - using jwt::error::token_verification_error_category; -} \ No newline at end of file +#undef JWT_CPP_MODULE_INTERFACE_BUILD diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6c7b75504..a47ee12cc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -45,6 +45,10 @@ if(TARGET jsoncpp_static) endif() add_executable(jwt-cpp-test ${TEST_SOURCES}) +if(JWT_ENABLE_MODULES AND NOT JWT_USE_IMPORT_STD) + target_compile_definitions(jwt-cpp-test PRIVATE JWT_ENABLE_MODULES) + set_property(TARGET jwt-cpp-test PROPERTY CXX_SCAN_FOR_MODULES ON) +endif() # NOTE: Don't use space inside a generator expression here, because the function prematurely breaks the expression into # multiple lines. https://cmake.org/pipermail/cmake/2018-April/067422.html diff --git a/tests/ClaimTest.cpp b/tests/ClaimTest.cpp index cd7806742..e3ccf4a24 100644 --- a/tests/ClaimTest.cpp +++ b/tests/ClaimTest.cpp @@ -1,5 +1,9 @@ -#include "jwt-cpp/jwt.h" #include +#ifdef JWT_ENABLE_MODULES +import jwt_cpp; +#else +#include +#endif TEST(ClaimTest, AudienceAsString) { std::string const token = diff --git a/tests/HelperTest.cpp b/tests/HelperTest.cpp index dfcc0b0e0..a6a3f05d7 100644 --- a/tests/HelperTest.cpp +++ b/tests/HelperTest.cpp @@ -1,5 +1,9 @@ -#include "jwt-cpp/jwt.h" #include +#ifdef JWT_ENABLE_MODULES +import jwt_cpp; +#else +#include +#endif namespace { extern std::string google_cert; diff --git a/tests/JwksTest.cpp b/tests/JwksTest.cpp index 6ef370e62..e3f7f485d 100644 --- a/tests/JwksTest.cpp +++ b/tests/JwksTest.cpp @@ -1,5 +1,9 @@ -#include "jwt-cpp/jwt.h" #include +#ifdef JWT_ENABLE_MODULES +import jwt_cpp; +#else +#include +#endif TEST(JwksTest, OneKeyParse) { std::string public_key = R"({ diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index 71440b389..1db92fdab 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -2,10 +2,15 @@ #ifndef HUNTER_ENABLED // Static linking (which hunter always? does) breaks the tests (duplicate definition), so skip them -#include "jwt-cpp/jwt.h" #include #include + +#ifdef JWT_ENABLE_MODULES +import jwt_cpp; +#else +#include "jwt-cpp/jwt.h" +#endif // TODO: Figure out why the tests fail on older openssl versions #ifndef JWT_OPENSSL_1_0_0 // It fails on < 1.1 but no idea why. // LibreSSL has different return codes but was already outside of the effective scope diff --git a/tests/TokenFormatTest.cpp b/tests/TokenFormatTest.cpp index 2925b0653..b782a7690 100644 --- a/tests/TokenFormatTest.cpp +++ b/tests/TokenFormatTest.cpp @@ -1,5 +1,9 @@ -#include "jwt-cpp/jwt.h" #include +#include "jwt-cpp/traits/nlohmann-json/traits.h" + +#ifndef JWT_ENABLE_MODULES +#include "jwt-cpp/jwt.h" +#endif TEST(TokenFormatTest, MissingDot) { ASSERT_THROW(jwt::decode("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0.eyJpc3MiOiJhdXRoMCJ9"), std::invalid_argument); @@ -15,8 +19,6 @@ TEST(TokenFormatTest, InvalidJSON) { ASSERT_THROW(jwt::decode("YXsiYWxnIjoibm9uZSIsInR5cCI6IkpXUyJ9YQ.eyJpc3MiOiJhdXRoMCJ9."), std::runtime_error); } -#include "jwt-cpp/traits/nlohmann-json/traits.h" - TEST(TokenFormatTest, GitHubIssue341) { std::string const token = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjYXV0aDAiLCJleHAiOjE3MTMzODgxNjgsInN1YiI6InRlc3RfdXNlciJ9." diff --git a/tests/TokenTest.cpp b/tests/TokenTest.cpp index 8cf89d80c..0f7811f80 100644 --- a/tests/TokenTest.cpp +++ b/tests/TokenTest.cpp @@ -1,5 +1,11 @@ -#include "jwt-cpp/jwt.h" #include +#include + +#ifdef JWT_ENABLE_MODULES +import jwt_cpp; +#else +#include "jwt-cpp/jwt.h" +#endif inline namespace test_keys { extern std::string rsa_priv_key; diff --git a/tests/traits/BoostJsonTest.cpp b/tests/traits/BoostJsonTest.cpp index 82c3810b3..81e09a80c 100644 --- a/tests/traits/BoostJsonTest.cpp +++ b/tests/traits/BoostJsonTest.cpp @@ -1,7 +1,7 @@ -#include "jwt-cpp/traits/boost-json/traits.h" - #include +#include "jwt-cpp/traits/boost-json/traits.h" + TEST(BoostJsonTest, BasicClaims) { const auto string = jwt::basic_claim(jwt::traits::boost_json::string_type("string")); ASSERT_EQ(string.get_type(), jwt::json::type::string); diff --git a/tests/traits/JsonconsTest.cpp b/tests/traits/JsonconsTest.cpp index 7d0f1ade4..c62e8b689 100644 --- a/tests/traits/JsonconsTest.cpp +++ b/tests/traits/JsonconsTest.cpp @@ -1,7 +1,7 @@ -#include "jwt-cpp/traits/danielaparker-jsoncons/traits.h" - #include +#include "jwt-cpp/traits/danielaparker-jsoncons/traits.h" + TEST(JsonconsTest, BasicClaims) { const auto string = jwt::basic_claim( jwt::traits::danielaparker_jsoncons::string_type("string")); diff --git a/tests/traits/NlohmannTest.cpp b/tests/traits/NlohmannTest.cpp index 616b622d7..1c06d45fc 100644 --- a/tests/traits/NlohmannTest.cpp +++ b/tests/traits/NlohmannTest.cpp @@ -1,7 +1,7 @@ -#include "jwt-cpp/traits/nlohmann-json/traits.h" - #include +#include "jwt-cpp/traits/nlohmann-json/traits.h" + TEST(NlohmannTest, BasicClaims) { const auto string = jwt::basic_claim(jwt::traits::nlohmann_json::string_type("string")); ASSERT_EQ(string.get_type(), jwt::json::type::string); diff --git a/tests/traits/OspJsoncppTest.cpp b/tests/traits/OspJsoncppTest.cpp index 39a6df2ff..29d9efb77 100644 --- a/tests/traits/OspJsoncppTest.cpp +++ b/tests/traits/OspJsoncppTest.cpp @@ -1,7 +1,7 @@ -#include "jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h" - #include +#include "jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h" + TEST(OspJsoncppTest, BasicClaims) { const auto string = jwt::basic_claim( jwt::traits::open_source_parsers_jsoncpp::string_type("string")); diff --git a/tests/traits/TraitsTest.cpp.mustache b/tests/traits/TraitsTest.cpp.mustache index 84ae8fceb..1aae77817 100644 --- a/tests/traits/TraitsTest.cpp.mustache +++ b/tests/traits/TraitsTest.cpp.mustache @@ -1,7 +1,7 @@ -#include "jwt-cpp/traits/{{traits_dir}}/traits.h" - #include +#include "jwt-cpp/traits/{{traits_dir}}/traits.h" + TEST({{test_suite_name}}, BasicClaims) { const auto string = jwt::basic_claim( jwt::traits::{{traits_name}}::string_type("string")); From 1bd1f26467330a1ea0a18e4348ae502e4bc6077c Mon Sep 17 00:00:00 2001 From: DockedFerret800 Date: Mon, 20 Apr 2026 23:01:56 +0100 Subject: [PATCH 06/12] Address comments --- CMakeLists.txt | 6 +++--- include/jwt-cpp/jwt.h | 20 ++++++++++++++++---- include/picojson/picojson.h | 2 +- modules/{jwt.ixx => jwt.cppm} | 0 4 files changed, 20 insertions(+), 8 deletions(-) rename modules/{jwt.ixx => jwt.cppm} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index ccc2a3c1e..5e12d00c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,8 +22,8 @@ option(JWT_BUILD_TESTS "Configure CMake to build tests (or not)" OFF) option(JWT_BUILD_DOCS "Adds a target for building the doxygen documentation" OFF) option(JWT_ENABLE_COVERAGE "Enable code coverage testing" OFF) option(JWT_ENABLE_FUZZING "Enable fuzz testing" OFF) -option(JWT_ENABLE_MODULES "Build C++ modules" OFF) -option(JWT_USE_IMPORT_STD "Use import std" OFF) +option(JWT_ENABLE_MODULES "Build C++ modules" ON) +option(JWT_USE_IMPORT_STD "Use import std" ON) option(JWT_DISABLE_PICOJSON "Do not provide the picojson template specialiaze" OFF) option(JWT_DISABLE_BASE64 "Do not include the base64 implementation from this library" OFF) @@ -139,7 +139,7 @@ else() PUBLIC FILE_SET cxx_modules TYPE CXX_MODULES BASE_DIRS ${JWT_MODULE_PATH} - FILES ${JWT_MODULE_PATH}/jwt.ixx + FILES ${JWT_MODULE_PATH}/jwt.cppm ) endif() diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index 04010f149..80e4086e3 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -1,6 +1,22 @@ #ifndef JWT_CPP_JWT_H #define JWT_CPP_JWT_H +#if !defined(JWT_CPP_MODULE_INTERFACE_BUILD) || !defined(JWT_USE_IMPORT_STD) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + #ifndef JWT_DISABLE_PICOJSON #ifndef PICOJSON_USE_INT64 #define PICOJSON_USE_INT64 @@ -22,9 +38,6 @@ #include #include -#ifdef JWT_USE_IMPORT_STD -import std; -#else #include #include #include @@ -49,7 +62,6 @@ import std; #endif #endif #endif -#endif #if OPENSSL_VERSION_NUMBER >= 0x30000000L // 3.0.0 #define JWT_OPENSSL_3_0 diff --git a/include/picojson/picojson.h b/include/picojson/picojson.h index ed1cce8cd..711188990 100644 --- a/include/picojson/picojson.h +++ b/include/picojson/picojson.h @@ -34,7 +34,7 @@ #define PICOJSON_USE_IMPORTED_STD 0 #endif -#if PICOJSON_USE_IMPORTED_STD +#if !PICOJSON_USE_IMPORTED_STD #include #include #include diff --git a/modules/jwt.ixx b/modules/jwt.cppm similarity index 100% rename from modules/jwt.ixx rename to modules/jwt.cppm From 46b4ea657b3134aacc76e9d84087ecb5cf5fd286 Mon Sep 17 00:00:00 2001 From: DockedFerret800 Date: Fri, 24 Apr 2026 18:06:28 +0100 Subject: [PATCH 07/12] Don't export everything --- CMakeLists.txt | 4 +- include/jwt-cpp/base.h | 24 +- include/jwt-cpp/jwt.h | 254 ++++++++++-------- .../jwt-cpp/traits/kazuho-picojson/defaults.h | 24 +- .../jwt-cpp/traits/kazuho-picojson/traits.h | 10 +- include/picojson/picojson.h | 23 +- modules/jwt.cppm | 6 - 7 files changed, 195 insertions(+), 150 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 851cca738..31e313fd1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,8 +22,8 @@ option(JWT_BUILD_TESTS "Configure CMake to build tests (or not)" OFF) option(JWT_BUILD_DOCS "Adds a target for building the doxygen documentation" OFF) option(JWT_ENABLE_COVERAGE "Enable code coverage testing" OFF) option(JWT_ENABLE_FUZZING "Enable fuzz testing" OFF) -option(JWT_ENABLE_MODULES "Build C++ modules" ON) -option(JWT_USE_IMPORT_STD "Use import std" ON) +option(JWT_ENABLE_MODULES "Build C++ modules" OFF) +option(JWT_USE_IMPORT_STD "Use import std" OFF) option(JWT_DISABLE_PICOJSON "Do not provide the picojson template specialiaze" OFF) option(JWT_DISABLE_BASE64 "Do not include the base64 implementation from this library" OFF) diff --git a/include/jwt-cpp/base.h b/include/jwt-cpp/base.h index 17c800147..80ba58b70 100644 --- a/include/jwt-cpp/base.h +++ b/include/jwt-cpp/base.h @@ -1,6 +1,14 @@ #ifndef JWT_CPP_BASE_H #define JWT_CPP_BASE_H +#ifndef JWT_CPP_EXPORT +#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) +#define JWT_CPP_EXPORT export +#else +#define JWT_CPP_EXPORT +#endif +#endif + #if !defined(JWT_CPP_MODULE_INTERFACE_BUILD) && defined(JWT_USE_IMPORT_STD) import std; #elif !defined(JWT_CPP_MODULE_INTERFACE_BUILD) @@ -34,7 +42,7 @@ namespace jwt { * As directed in [X.509 Parameter](https://datatracker.ietf.org/doc/html/rfc7517#section-4.7) certificate chains are * base64-encoded as per [Section 4 of RFC4648](https://datatracker.ietf.org/doc/html/rfc4648#section-4) */ - struct base64 { + JWT_CPP_EXPORT struct base64 { static const std::array& data() { static constexpr std::array data{ {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', @@ -73,7 +81,7 @@ namespace jwt { * > Base64 encoding using the URL- and filename-safe character set defined in * > [Section 5 of RFC 4648 RFC4648](https://tools.ietf.org/html/rfc4648#section-5), with all trailing '=' characters omitted */ - struct base64url { + JWT_CPP_EXPORT struct base64url { static const std::array& data() { static constexpr std::array data{ {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', @@ -110,7 +118,7 @@ namespace jwt { * * This is useful in situations outside of JWT encoding/decoding and is provided as a helper */ - struct base64url_percent_encoding { + JWT_CPP_EXPORT struct base64url_percent_encoding { static const std::array& data() { static constexpr std::array data{ {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', @@ -142,7 +150,7 @@ namespace jwt { }; } // namespace helper - inline std::uint32_t index(const std::array& rdata, char symbol) { + JWT_CPP_EXPORT inline std::uint32_t index(const std::array& rdata, char symbol) { auto index = rdata[static_cast(symbol)]; if (index <= -1) { throw std::runtime_error("Invalid input: not within alphabet"); } return static_cast(index); @@ -309,7 +317,7 @@ namespace jwt { * const auto b64 = jwt::base::encode("example_data") * \endcode */ - template + JWT_CPP_EXPORT template std::string encode(const std::string& bin) { return details::encode(bin, T::data(), T::fill()); } @@ -323,7 +331,7 @@ namespace jwt { * const auto b64 = jwt::base::decode("ZXhhbXBsZV9kYXRh") * \endcode */ - template + JWT_CPP_EXPORT template std::string decode(const std::string& base) { return details::decode(base, T::rdata(), T::fill()); } @@ -337,7 +345,7 @@ namespace jwt { * const auto b64 = jwt::base::pad("ZXhhbXBsZV9kYQ") * \endcode */ - template + JWT_CPP_EXPORT template std::string pad(const std::string& base) { return details::pad(base, T::fill()); } @@ -351,7 +359,7 @@ namespace jwt { * const auto b64 = jwt::base::trim("ZXhhbXBsZV9kYQ==") * \endcode */ - template + JWT_CPP_EXPORT template std::string trim(const std::string& base) { return details::trim(base, T::fill()); } diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index 1fad7d822..e4bbd7ac8 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -1,6 +1,14 @@ #ifndef JWT_CPP_JWT_H #define JWT_CPP_JWT_H +#ifndef JWT_CPP_EXPORT +#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) +#define JWT_CPP_EXPORT export +#else +#define JWT_CPP_EXPORT +#endif +#endif + #if !defined(JWT_CPP_MODULE_INTERFACE_BUILD) || !defined(JWT_USE_IMPORT_STD) #include #include @@ -105,31 +113,31 @@ namespace jwt { /** * Default system time point in UTC */ - using date = std::chrono::system_clock::time_point; + JWT_CPP_EXPORT using date = std::chrono::system_clock::time_point; /** * \brief Everything related to error codes issued by the library */ namespace error { - struct signature_verification_exception : public std::system_error { + JWT_CPP_EXPORT struct signature_verification_exception : public std::system_error { using system_error::system_error; }; - struct signature_generation_exception : public std::system_error { + JWT_CPP_EXPORT struct signature_generation_exception : public std::system_error { using system_error::system_error; }; - struct rsa_exception : public std::system_error { + JWT_CPP_EXPORT struct rsa_exception : public std::system_error { using system_error::system_error; }; - struct ecdsa_exception : public std::system_error { + JWT_CPP_EXPORT struct ecdsa_exception : public std::system_error { using system_error::system_error; }; - struct token_verification_exception : public std::system_error { + JWT_CPP_EXPORT struct token_verification_exception : public std::system_error { using system_error::system_error; }; /** * \brief Errors related to processing of RSA signatures */ - enum class rsa_error { + JWT_CPP_EXPORT enum class rsa_error { ok = 0, cert_load_failed = 10, get_key_failed, @@ -146,7 +154,7 @@ namespace jwt { /** * \brief Error category for RSA errors */ - inline std::error_category& rsa_error_category() { + JWT_CPP_EXPORT inline std::error_category& rsa_error_category() { class rsa_error_cat : public std::error_category { public: const char* name() const noexcept override { return "rsa_error"; }; @@ -174,11 +182,13 @@ namespace jwt { /** * \brief Converts JWT-CPP errors into generic STL error_codes */ - inline std::error_code make_error_code(rsa_error e) { return {static_cast(e), rsa_error_category()}; } + JWT_CPP_EXPORT inline std::error_code make_error_code(rsa_error e) { + return {static_cast(e), rsa_error_category()}; + } /** * \brief Errors related to processing of RSA signatures */ - enum class ecdsa_error { + JWT_CPP_EXPORT enum class ecdsa_error { ok = 0, load_key_bio_write = 10, load_key_bio_read, @@ -198,7 +208,7 @@ namespace jwt { /** * \brief Error category for ECDSA errors */ - inline std::error_category& ecdsa_error_category() { + JWT_CPP_EXPORT inline std::error_category& ecdsa_error_category() { class ecdsa_error_cat : public std::error_category { public: const char* name() const noexcept override { return "ecdsa_error"; }; @@ -230,12 +240,14 @@ namespace jwt { /** * \brief Converts JWT-CPP errors into generic STL error_codes */ - inline std::error_code make_error_code(ecdsa_error e) { return {static_cast(e), ecdsa_error_category()}; } + JWT_CPP_EXPORT inline std::error_code make_error_code(ecdsa_error e) { + return {static_cast(e), ecdsa_error_category()}; + } /** * \brief Errors related to verification of signatures */ - enum class signature_verification_error { + JWT_CPP_EXPORT enum class signature_verification_error { ok = 0, invalid_signature = 10, create_context_failed, @@ -249,7 +261,7 @@ namespace jwt { /** * \brief Error category for verification errors */ - inline std::error_category& signature_verification_error_category() { + JWT_CPP_EXPORT inline std::error_category& signature_verification_error_category() { class verification_error_cat : public std::error_category { public: const char* name() const noexcept override { return "signature_verification_error"; }; @@ -281,14 +293,14 @@ namespace jwt { /** * \brief Converts JWT-CPP errors into generic STL error_codes */ - inline std::error_code make_error_code(signature_verification_error e) { + JWT_CPP_EXPORT inline std::error_code make_error_code(signature_verification_error e) { return {static_cast(e), signature_verification_error_category()}; } /** * \brief Errors related to signature generation errors */ - enum class signature_generation_error { + JWT_CPP_EXPORT enum class signature_generation_error { ok = 0, hmac_failed = 10, create_context_failed, @@ -308,7 +320,7 @@ namespace jwt { /** * \brief Error category for signature generation errors */ - inline std::error_category& signature_generation_error_category() { + JWT_CPP_EXPORT inline std::error_category& signature_generation_error_category() { class signature_generation_error_cat : public std::error_category { public: const char* name() const noexcept override { return "signature_generation_error"; }; @@ -351,14 +363,14 @@ namespace jwt { /** * \brief Converts JWT-CPP errors into generic STL error_codes */ - inline std::error_code make_error_code(signature_generation_error e) { + JWT_CPP_EXPORT inline std::error_code make_error_code(signature_generation_error e) { return {static_cast(e), signature_generation_error_category()}; } /** * \brief Errors related to token verification errors */ - enum class token_verification_error { + JWT_CPP_EXPORT enum class token_verification_error { ok = 0, wrong_algorithm = 10, missing_claim, @@ -370,7 +382,7 @@ namespace jwt { /** * \brief Error category for token verification errors */ - inline std::error_category& token_verification_error_category() { + JWT_CPP_EXPORT inline std::error_category& token_verification_error_category() { class token_verification_error_cat : public std::error_category { public: const char* name() const noexcept override { return "token_verification_error"; }; @@ -396,13 +408,13 @@ namespace jwt { /** * \brief Converts JWT-CPP errors into generic STL error_codes */ - inline std::error_code make_error_code(token_verification_error e) { + JWT_CPP_EXPORT inline std::error_code make_error_code(token_verification_error e) { return {static_cast(e), token_verification_error_category()}; } /** * \brief Raises an exception if any JWT-CPP error codes are active */ - inline void throw_if_error(std::error_code ec) { + JWT_CPP_EXPORT inline void throw_if_error(std::error_code ec) { if (ec) { if (ec.category() == rsa_error_category()) throw rsa_exception(ec); if (ec.category() == ecdsa_error_category()) throw ecdsa_exception(ec); @@ -416,15 +428,15 @@ namespace jwt { } // namespace jwt namespace std { - template<> + JWT_CPP_EXPORT template<> struct is_error_code_enum : true_type {}; - template<> + JWT_CPP_EXPORT template<> struct is_error_code_enum : true_type {}; - template<> + JWT_CPP_EXPORT template<> struct is_error_code_enum : true_type {}; - template<> + JWT_CPP_EXPORT template<> struct is_error_code_enum : true_type {}; - template<> + JWT_CPP_EXPORT template<> struct is_error_code_enum : true_type {}; } // namespace std @@ -444,7 +456,7 @@ namespace jwt { * jwt-cpp to leverage that and thus safe an allocation for the control block in std::shared_ptr. * The handle uses shared_ptr as a fallback on older versions. The behaviour should be identical between both. */ - class evp_pkey_handle { + JWT_CPP_EXPORT class evp_pkey_handle { public: /** * \brief Creates a null key pointer. @@ -518,11 +530,11 @@ namespace jwt { #endif }; - inline std::unique_ptr make_mem_buf_bio() { + JWT_CPP_EXPORT inline std::unique_ptr make_mem_buf_bio() { return std::unique_ptr(BIO_new(BIO_s_mem()), BIO_free_all); } - inline std::unique_ptr make_mem_buf_bio(const std::string& data) { + JWT_CPP_EXPORT inline std::unique_ptr make_mem_buf_bio(const std::string& data) { return std::unique_ptr( #if OPENSSL_VERSION_NUMBER <= 0x10100003L BIO_new_mem_buf(const_cast(data.data()), static_cast(data.size())), BIO_free_all @@ -532,7 +544,7 @@ namespace jwt { ); } - template + JWT_CPP_EXPORT template std::string write_bio_to_string(std::unique_ptr& bio_out, std::error_code& ec) { char* ptr = nullptr; auto len = BIO_get_mem_data(bio_out.get(), &ptr); @@ -543,7 +555,7 @@ namespace jwt { return {ptr, static_cast(len)}; } - inline std::unique_ptr make_evp_md_ctx() { + JWT_CPP_EXPORT inline std::unique_ptr make_evp_md_ctx() { return #ifdef JWT_OPENSSL_1_0_0 std::unique_ptr(EVP_MD_CTX_create(), &EVP_MD_CTX_destroy); @@ -560,7 +572,7 @@ namespace jwt { * \param pw Password used to decrypt certificate (leave empty if not encrypted) * \param ec error_code for error_detection (gets cleared if no error occurred) */ - template + JWT_CPP_EXPORT template std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw, std::error_code& ec) { ec.clear(); auto certbio = make_mem_buf_bio(certstr); @@ -597,7 +609,7 @@ namespace jwt { * \param pw Password used to decrypt certificate (leave empty if not encrypted) * \throw templated error_category's type exception if an error occurred */ - template + JWT_CPP_EXPORT template std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw = "") { std::error_code ec; auto res = extract_pubkey_from_cert(certstr, pw, ec); @@ -611,7 +623,7 @@ namespace jwt { * \param cert_der_str String containing the certificate encoded as base64 DER * \param ec error_code for error_detection (gets cleared if no error occurs) */ - inline std::string convert_der_to_pem(const std::string& cert_der_str, std::error_code& ec) { + JWT_CPP_EXPORT inline std::string convert_der_to_pem(const std::string& cert_der_str, std::error_code& ec) { ec.clear(); auto c_str = reinterpret_cast(cert_der_str.c_str()); @@ -646,7 +658,7 @@ namespace jwt { * \param decode The function to decode the cert * \param ec error_code for error_detection (gets cleared if no error occurs) */ - template + JWT_CPP_EXPORT template std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, Decode decode, std::error_code& ec) { ec.clear(); @@ -668,7 +680,7 @@ namespace jwt { * \param decode The function to decode the cert * \throw rsa_exception if an error occurred */ - template + JWT_CPP_EXPORT template std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, Decode decode) { std::error_code ec; auto res = convert_base64_der_to_pem(cert_base64_der_str, std::move(decode), ec); @@ -682,7 +694,7 @@ namespace jwt { * \param cert_der_str String containing the DER certificate * \throw rsa_exception if an error occurred */ - inline std::string convert_der_to_pem(const std::string& cert_der_str) { + JWT_CPP_EXPORT inline std::string convert_der_to_pem(const std::string& cert_der_str) { std::error_code ec; auto res = convert_der_to_pem(cert_der_str, ec); error::throw_if_error(ec); @@ -699,7 +711,8 @@ namespace jwt { * \param cert_base64_der_str String containing the certificate encoded as base64 DER * \param ec error_code for error_detection (gets cleared if no error occurs) */ - inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, std::error_code& ec) { + JWT_CPP_EXPORT inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, + std::error_code& ec) { auto decode = [](const std::string& token) { return base::decode(base::pad(token)); }; @@ -715,7 +728,7 @@ namespace jwt { * \param cert_base64_der_str String containing the certificate encoded as base64 DER * \throw rsa_exception if an error occurred */ - inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str) { + JWT_CPP_EXPORT inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str) { std::error_code ec; auto res = convert_base64_der_to_pem(cert_base64_der_str, ec); error::throw_if_error(ec); @@ -732,7 +745,7 @@ namespace jwt { * \param password Password used to decrypt certificate (leave empty if not encrypted) * \param ec error_code for error_detection (gets cleared if no error occurs) */ - template + JWT_CPP_EXPORT template evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password, std::error_code& ec) { ec.clear(); @@ -784,7 +797,7 @@ namespace jwt { * \param password Password used to decrypt certificate (leave empty if not encrypted) * \throw Templated error_category's type exception if an error occurred */ - template + JWT_CPP_EXPORT template inline evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password = "") { std::error_code ec; auto res = load_public_key_from_string(key, password, ec); @@ -800,7 +813,7 @@ namespace jwt { * \param password Password used to decrypt key (leave empty if not encrypted) * \param ec error_code for error_detection (gets cleared if no error occurs) */ - template + JWT_CPP_EXPORT template inline evp_pkey_handle load_private_key_from_string(const std::string& key, const std::string& password, std::error_code& ec) { ec.clear(); @@ -828,7 +841,7 @@ namespace jwt { * \param password Password used to decrypt key (leave empty if not encrypted) * \throw Templated error_category's type exception if an error occurred */ - template + JWT_CPP_EXPORT template inline evp_pkey_handle load_private_key_from_string(const std::string& key, const std::string& password = "") { std::error_code ec; auto res = load_private_key_from_string(key, password, ec); @@ -847,8 +860,9 @@ namespace jwt { * \param password Password used to decrypt certificate (leave empty if not encrypted) * \param ec error_code for error_detection (gets cleared if no error occurs) */ - inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, const std::string& password, - std::error_code& ec) { + JWT_CPP_EXPORT inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, + const std::string& password, + std::error_code& ec) { return load_public_key_from_string(key, password, ec); } @@ -876,7 +890,8 @@ namespace jwt { * \param ec error_code for error_detection (gets cleared if no error occurs) * \return BIGNUM representation */ - inline std::unique_ptr raw2bn(const std::string& raw, std::error_code& ec) { + JWT_CPP_EXPORT inline std::unique_ptr raw2bn(const std::string& raw, + std::error_code& ec) { auto bn = BN_bin2bn(reinterpret_cast(raw.data()), static_cast(raw.size()), nullptr); // https://www.openssl.org/docs/man1.1.1/man3/BN_bin2bn.html#RETURN-VALUES @@ -891,7 +906,7 @@ namespace jwt { * \param raw String to convert * \return BIGNUM representation */ - inline std::unique_ptr raw2bn(const std::string& raw) { + JWT_CPP_EXPORT inline std::unique_ptr raw2bn(const std::string& raw) { std::error_code ec; auto res = raw2bn(raw, ec); error::throw_if_error(ec); @@ -909,8 +924,8 @@ namespace jwt { * \param password Password used to decrypt certificate or key (leave empty if not encrypted) * \throw ecdsa_exception if an error occurred */ - inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, - const std::string& password = "") { + JWT_CPP_EXPORT inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, + const std::string& password = "") { std::error_code ec; auto res = load_public_key_from_string(key, password, ec); error::throw_if_error(ec); @@ -926,8 +941,9 @@ namespace jwt { * \param password Password used to decrypt key (leave empty if not encrypted) * \param ec error_code for error_detection (gets cleared if no error occurs) */ - inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, const std::string& password, - std::error_code& ec) { + JWT_CPP_EXPORT inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, + const std::string& password, + std::error_code& ec) { return load_private_key_from_string(key, password, ec); } @@ -945,7 +961,7 @@ namespace jwt { * \param ec error_code for error_detection (gets cleared if no error occur * \return public key in PEM format */ - template + JWT_CPP_EXPORT template std::string create_public_key_from_rsa_components(const std::string& modulus, const std::string& exponent, Decode decode, std::error_code& ec) { ec.clear(); @@ -1061,7 +1077,7 @@ namespace jwt { * \param decode The function to decode the RSA parameters * \return public key in PEM format */ - template + JWT_CPP_EXPORT template std::string create_public_key_from_rsa_components(const std::string& modulus, const std::string& exponent, Decode decode) { std::error_code ec; @@ -1081,8 +1097,9 @@ namespace jwt { * \param ec error_code for error_detection (gets cleared if no error occur * \return public key in PEM format */ - inline std::string create_public_key_from_rsa_components(const std::string& modulus, - const std::string& exponent, std::error_code& ec) { + JWT_CPP_EXPORT inline std::string create_public_key_from_rsa_components(const std::string& modulus, + const std::string& exponent, + std::error_code& ec) { auto decode = [](const std::string& token) { return base::decode(base::pad(token)); }; @@ -1097,8 +1114,8 @@ namespace jwt { * \param exponent string containing base64url encoded exponent * \return public key in PEM format */ - inline std::string create_public_key_from_rsa_components(const std::string& modulus, - const std::string& exponent) { + JWT_CPP_EXPORT inline std::string create_public_key_from_rsa_components(const std::string& modulus, + const std::string& exponent) { std::error_code ec; auto res = create_public_key_from_rsa_components(modulus, exponent, ec); error::throw_if_error(ec); @@ -1114,8 +1131,8 @@ namespace jwt { * \param password Password used to decrypt key (leave empty if not encrypted) * \throw ecdsa_exception if an error occurred */ - inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, - const std::string& password = "") { + JWT_CPP_EXPORT inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, + const std::string& password = "") { std::error_code ec; auto res = load_private_key_from_string(key, password, ec); error::throw_if_error(ec); @@ -1131,7 +1148,7 @@ namespace jwt { * \param ec error_code for error_detection * \return group name */ - inline std::string curve2group(const std::string curve, std::error_code& ec) { + JWT_CPP_EXPORT inline std::string curve2group(const std::string curve, std::error_code& ec) { if (curve == "P-256") { return "prime256v1"; } else if (curve == "P-384") { @@ -1153,7 +1170,7 @@ namespace jwt { * \param ec error_code for error_detection * \return ID */ - inline int curve2nid(const std::string curve, std::error_code& ec) { + JWT_CPP_EXPORT inline int curve2nid(const std::string curve, std::error_code& ec) { if (curve == "P-256") { return NID_X9_62_prime256v1; } else if (curve == "P-384") { @@ -1183,7 +1200,7 @@ namespace jwt { * \param ec error_code for error_detection (gets cleared if no error occur * \return public key in PEM format */ - template + JWT_CPP_EXPORT template std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x, const std::string& y, Decode decode, std::error_code& ec) { ec.clear(); @@ -1311,7 +1328,7 @@ namespace jwt { * \param decode The function to decode the RSA parameters * \return public key in PEM format */ - template + JWT_CPP_EXPORT template std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x, const std::string& y, Decode decode) { std::error_code ec; @@ -1332,8 +1349,10 @@ namespace jwt { * \param ec error_code for error_detection (gets cleared if no error occur * \return public key in PEM format */ - inline std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x, - const std::string& y, std::error_code& ec) { + JWT_CPP_EXPORT inline std::string create_public_key_from_ec_components(const std::string& curve, + const std::string& x, + const std::string& y, + std::error_code& ec) { auto decode = [](const std::string& token) { return base::decode(base::pad(token)); }; @@ -1349,8 +1368,9 @@ namespace jwt { * \param y string containing base64url encoded y coordinate * \return public key in PEM format */ - inline std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x, - const std::string& y) { + JWT_CPP_EXPORT inline std::string create_public_key_from_ec_components(const std::string& curve, + const std::string& x, + const std::string& y) { std::error_code ec; auto res = create_public_key_from_ec_components(curve, x, y, ec); error::throw_if_error(ec); @@ -1376,7 +1396,7 @@ namespace jwt { * See [RFC 7518 Section 3.6](https://datatracker.ietf.org/doc/html/rfc7518#section-3.6) * for more information. */ - struct none { + JWT_CPP_EXPORT struct none { /** * \brief Return an empty string */ @@ -1401,7 +1421,7 @@ namespace jwt { /** * \brief Base class for HMAC family of algorithms */ - struct hmacsha { + JWT_CPP_EXPORT struct hmacsha { /** * Construct new hmac algorithm * @@ -1471,7 +1491,7 @@ namespace jwt { /** * \brief Base class for RSA family of algorithms */ - struct rsa { + JWT_CPP_EXPORT struct rsa { /** * Construct new rsa algorithm * @@ -1582,7 +1602,7 @@ namespace jwt { /** * \brief Base class for ECDSA family of algorithms */ - struct ecdsa { + JWT_CPP_EXPORT struct ecdsa { /** * Construct new ecdsa algorithm * @@ -1830,7 +1850,7 @@ namespace jwt { * so these algorithms are only available when building against this version or higher. * LibreSSL added EdDSA (Ed25519) functionality in [LibreSSL 3.7.1](https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.7.1-relnotes.txt) */ - struct eddsa { + JWT_CPP_EXPORT struct eddsa { /** * Construct new eddsa algorithm * \param public_key EdDSA public key in PEM format @@ -1954,7 +1974,7 @@ namespace jwt { /** * \brief Base class for PSS-RSA family of algorithms */ - struct pss { + JWT_CPP_EXPORT struct pss { /** * Construct new pss algorithm * \param public_key RSA public key in PEM format @@ -2082,7 +2102,7 @@ namespace jwt { /** * HS256 algorithm */ - struct hs256 : public hmacsha { + JWT_CPP_EXPORT struct hs256 : public hmacsha { /** * Construct new instance of algorithm * \param key HMAC signing key @@ -2092,7 +2112,7 @@ namespace jwt { /** * HS384 algorithm */ - struct hs384 : public hmacsha { + JWT_CPP_EXPORT struct hs384 : public hmacsha { /** * Construct new instance of algorithm * \param key HMAC signing key @@ -2102,7 +2122,7 @@ namespace jwt { /** * HS512 algorithm */ - struct hs512 : public hmacsha { + JWT_CPP_EXPORT struct hs512 : public hmacsha { /** * Construct new instance of algorithm * \param key HMAC signing key @@ -2114,7 +2134,7 @@ namespace jwt { * * This data structure is used to describe the RSA256 and can be used to verify JWTs */ - struct rs256 : public rsa { + JWT_CPP_EXPORT struct rs256 : public rsa { /** * \brief Construct new instance of algorithm * @@ -2130,7 +2150,7 @@ namespace jwt { /** * RS384 algorithm */ - struct rs384 : public rsa { + JWT_CPP_EXPORT struct rs384 : public rsa { /** * Construct new instance of algorithm * \param public_key RSA public key in PEM format @@ -2145,7 +2165,7 @@ namespace jwt { /** * RS512 algorithm */ - struct rs512 : public rsa { + JWT_CPP_EXPORT struct rs512 : public rsa { /** * Construct new instance of algorithm * \param public_key RSA public key in PEM format @@ -2160,7 +2180,7 @@ namespace jwt { /** * ES256 algorithm */ - struct es256 : public ecdsa { + JWT_CPP_EXPORT struct es256 : public ecdsa { /** * Construct new instance of algorithm * \param public_key ECDSA public key in PEM format @@ -2177,7 +2197,7 @@ namespace jwt { /** * ES384 algorithm */ - struct es384 : public ecdsa { + JWT_CPP_EXPORT struct es384 : public ecdsa { /** * Construct new instance of algorithm * \param public_key ECDSA public key in PEM format @@ -2194,7 +2214,7 @@ namespace jwt { /** * ES512 algorithm */ - struct es512 : public ecdsa { + JWT_CPP_EXPORT struct es512 : public ecdsa { /** * Construct new instance of algorithm * \param public_key ECDSA public key in PEM format @@ -2211,7 +2231,7 @@ namespace jwt { /** * ES256K algorithm */ - struct es256k : public ecdsa { + JWT_CPP_EXPORT struct es256k : public ecdsa { /** * Construct new instance of algorithm * \param public_key ECDSA public key in PEM format @@ -2233,7 +2253,7 @@ namespace jwt { * * Requires at least OpenSSL 1.1.1 or LibreSSL 3.7.1. */ - struct ed25519 : public eddsa { + JWT_CPP_EXPORT struct ed25519 : public eddsa { /** * Construct new instance of algorithm * \param public_key Ed25519 public key in PEM format @@ -2256,7 +2276,7 @@ namespace jwt { * * Requires at least OpenSSL 1.1.1. Note: Not supported by LibreSSL. */ - struct ed448 : public eddsa { + JWT_CPP_EXPORT struct ed448 : public eddsa { /** * Construct new instance of algorithm * \param public_key Ed448 public key in PEM format @@ -2276,7 +2296,7 @@ namespace jwt { /** * PS256 algorithm */ - struct ps256 : public pss { + JWT_CPP_EXPORT struct ps256 : public pss { /** * Construct new instance of algorithm * \param public_key RSA public key in PEM format @@ -2291,7 +2311,7 @@ namespace jwt { /** * PS384 algorithm */ - struct ps384 : public pss { + JWT_CPP_EXPORT struct ps384 : public pss { /** * Construct new instance of algorithm * \param public_key RSA public key in PEM format @@ -2306,7 +2326,7 @@ namespace jwt { /** * PS512 algorithm */ - struct ps512 : public pss { + JWT_CPP_EXPORT struct ps512 : public pss { /** * Construct new instance of algorithm * \param public_key RSA public key in PEM format @@ -2331,7 +2351,7 @@ namespace jwt { * to identify the different structures and reason about them without needing a "concept" * to capture that defintion to compare against a concrete type. */ - enum class type { boolean, integer, number, string, array, object }; + JWT_CPP_EXPORT enum class type { boolean, integer, number, string, array, object }; } // namespace json namespace details { @@ -2613,7 +2633,7 @@ namespace jwt { * * \see [RFC 7519: JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) */ - template + JWT_CPP_EXPORT template class basic_claim { /** * The reason behind this is to provide an expressive abstraction without @@ -2757,13 +2777,13 @@ namespace jwt { /** * Attempt to parse JSON was unsuccessful */ - struct invalid_json_exception : public std::runtime_error { + JWT_CPP_EXPORT struct invalid_json_exception : public std::runtime_error { invalid_json_exception() : runtime_error("invalid json") {} }; /** * Attempt to access claim was unsuccessful */ - struct claim_not_present_exception : public std::out_of_range { + JWT_CPP_EXPORT struct claim_not_present_exception : public std::out_of_range { claim_not_present_exception() : out_of_range("claim not found") {} }; } // namespace error @@ -2832,7 +2852,7 @@ namespace jwt { * Base class that represents a token payload. * Contains Convenience accessors for common claims. */ - template + JWT_CPP_EXPORT template class payload { protected: details::map_of_claims payload_claims; @@ -2950,7 +2970,7 @@ namespace jwt { * Base class that represents a token header. * Contains Convenience accessors for common claims. */ - template + JWT_CPP_EXPORT template class header { protected: details::map_of_claims header_claims; @@ -3025,7 +3045,7 @@ namespace jwt { /** * Class containing all information about a decoded token */ - template + JWT_CPP_EXPORT template class decoded_jwt : public header, public payload { protected: /// Unmodified token, as passed to constructor @@ -3160,7 +3180,7 @@ namespace jwt { * Builder class to build and sign a new token * Use jwt::create() to get an instance of this class. */ - template + JWT_CPP_EXPORT template class builder { typename json_traits::object_type header_claims; typename json_traits::object_type payload_claims; @@ -3412,7 +3432,7 @@ namespace jwt { /** * This is the base container which holds the token that need to be verified */ - template + JWT_CPP_EXPORT template struct verify_context { verify_context(date ctime, const decoded_jwt& j, size_t l) : current_time(ctime), jwt(j), default_leeway(l) {} @@ -3483,7 +3503,7 @@ namespace jwt { /** * This is the default operation and does case sensitive matching */ - template + JWT_CPP_EXPORT template struct equals_claim { const basic_claim expected; void operator()(const verify_context& ctx, std::error_code& ec) const { @@ -3512,7 +3532,7 @@ namespace jwt { * Checks that the current time is before the time specified in the given * claim. This is identical to how the "exp" check works. */ - template + JWT_CPP_EXPORT template struct date_before_claim { const size_t leeway; void operator()(const verify_context& ctx, std::error_code& ec) const { @@ -3529,7 +3549,7 @@ namespace jwt { * Checks that the current time is after the time specified in the given * claim. This is identical to how the "nbf" and "iat" check works. */ - template + JWT_CPP_EXPORT template struct date_after_claim { const size_t leeway; void operator()(const verify_context& ctx, std::error_code& ec) const { @@ -3547,7 +3567,7 @@ namespace jwt { * If the token value is a string it is treated as a set with a single element. * The comparison is case sensitive. */ - template + JWT_CPP_EXPORT template struct is_subset_claim { const typename basic_claim::set_t expected; void operator()(const verify_context& ctx, std::error_code& ec) const { @@ -3576,7 +3596,7 @@ namespace jwt { /** * Checks if the claim is a string and does an case insensitive comparison. */ - template + JWT_CPP_EXPORT template struct insensitive_string_claim { const typename json_traits::string_type expected; std::locale locale; @@ -3631,7 +3651,7 @@ namespace jwt { * Verifier class used to check if a decoded token contains all claims required by your application and has a valid * signature. */ - template + JWT_CPP_EXPORT template class verifier { public: using basic_claim_t = basic_claim; @@ -3894,7 +3914,7 @@ namespace jwt { * A JSON object that represents a cryptographic key. The members of * the object represent properties of the key, including its value. */ - template + JWT_CPP_EXPORT template class jwk { using basic_claim_t = basic_claim; const details::map_of_claims jwk_claims; @@ -4105,7 +4125,7 @@ namespace jwt { * * This container takes a JWKs and simplifies it to a vector of JWKs */ - template + JWT_CPP_EXPORT template class jwks { public: /// JWK instance template specialization @@ -4180,7 +4200,7 @@ namespace jwt { * \param c Clock instance to use * \return verifier instance */ - template + JWT_CPP_EXPORT template verifier verify(Clock c) { return verifier(c); } @@ -4190,7 +4210,7 @@ namespace jwt { * \param c Clock instance to use * \return builder instance */ - template + JWT_CPP_EXPORT template builder create(Clock c) { return builder(c); } @@ -4198,7 +4218,7 @@ namespace jwt { /** * Default clock class using std::chrono::system_clock as a backend. */ - struct default_clock { + JWT_CPP_EXPORT struct default_clock { /** * Gets the current system time * \return time_point of the host system @@ -4214,7 +4234,7 @@ namespace jwt { * \param c Clock instance to use * \return verifier instance */ - template + JWT_CPP_EXPORT template verifier verify(default_clock c = {}) { return verifier(c); } @@ -4222,7 +4242,7 @@ namespace jwt { /** * Return a builder instance to create a new token */ - template + JWT_CPP_EXPORT template builder create(default_clock c = {}) { return builder(c); } @@ -4241,7 +4261,7 @@ namespace jwt { * \throw std::invalid_argument Token is not in correct format * \throw std::runtime_error Base64 decoding failed or invalid json */ - template + JWT_CPP_EXPORT template decoded_jwt decode(const typename json_traits::string_type& token, Decode decode) { return decoded_jwt(token, decode); } @@ -4256,7 +4276,7 @@ namespace jwt { * \throw std::invalid_argument Token is not in correct format * \throw std::runtime_error Base64 decoding failed or invalid json */ - template + JWT_CPP_EXPORT template decoded_jwt decode(const typename json_traits::string_type& token) { return decoded_jwt(token); } @@ -4266,7 +4286,7 @@ namespace jwt { * \param jwk_ string buffer containing the JSON object * \return Decoded jwk */ - template + JWT_CPP_EXPORT template jwk parse_jwk(const typename json_traits::string_type& jwk_) { return jwk(jwk_); } @@ -4280,18 +4300,18 @@ namespace jwt { * \return Parsed JSON object containing the data of the JWK SET string * \throw std::runtime_error Token is not in correct format */ - template + JWT_CPP_EXPORT template jwks parse_jwks(const typename json_traits::string_type& jwks_) { return jwks(jwks_); } } // namespace jwt -template +JWT_CPP_EXPORT template std::istream& operator>>(std::istream& is, jwt::basic_claim& c) { return c.operator>>(is); } -template +JWT_CPP_EXPORT template std::ostream& operator<<(std::ostream& os, const jwt::basic_claim& c) { return os << c.to_json(); } diff --git a/include/jwt-cpp/traits/kazuho-picojson/defaults.h b/include/jwt-cpp/traits/kazuho-picojson/defaults.h index eae9789ae..b4de2f4e8 100644 --- a/include/jwt-cpp/traits/kazuho-picojson/defaults.h +++ b/include/jwt-cpp/traits/kazuho-picojson/defaults.h @@ -1,6 +1,14 @@ #ifndef JWT_CPP_KAZUHO_PICOJSON_DEFAULTS_H #define JWT_CPP_KAZUHO_PICOJSON_DEFAULTS_H +#ifndef JWT_CPP_EXPORT +#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) +#define JWT_CPP_EXPORT export +#else +#define JWT_CPP_EXPORT +#endif +#endif + #include "traits.h" namespace jwt { @@ -10,13 +18,13 @@ namespace jwt { * This type is the specialization of the \ref basic_claim class which * uses the standard template types. */ - using claim = basic_claim; + JWT_CPP_EXPORT using claim = basic_claim; /** * Create a verifier using the default clock * \return verifier instance */ - inline verifier verify() { + JWT_CPP_EXPORT inline verifier verify() { return verify(default_clock{}); } @@ -24,7 +32,7 @@ namespace jwt { * Create a builder using the default clock * \return builder instance to create a new token */ - inline builder create() { + JWT_CPP_EXPORT inline builder create() { return builder(default_clock{}); } @@ -36,7 +44,7 @@ namespace jwt { * \throw std::invalid_argument Token is not in correct format * \throw std::runtime_error Base64 decoding failed or invalid json */ - inline decoded_jwt decode(const std::string& token) { + JWT_CPP_EXPORT inline decoded_jwt decode(const std::string& token) { return decoded_jwt(token); } #endif @@ -52,7 +60,7 @@ namespace jwt { * \throw std::invalid_argument Token is not in correct format * \throw std::runtime_error Base64 decoding failed or invalid json */ - template + JWT_CPP_EXPORT template decoded_jwt decode(const std::string& token, Decode decode) { return decoded_jwt(token, decode); } @@ -63,7 +71,7 @@ namespace jwt { * \return Parsed JWK * \throw std::runtime_error Token is not in correct format */ - inline jwk parse_jwk(const traits::kazuho_picojson::string_type& token) { + JWT_CPP_EXPORT inline jwk parse_jwk(const traits::kazuho_picojson::string_type& token) { return jwk(token); } @@ -73,7 +81,7 @@ namespace jwt { * \return Parsed JWKs * \throw std::runtime_error Token is not in correct format */ - inline jwks parse_jwks(const traits::kazuho_picojson::string_type& token) { + JWT_CPP_EXPORT inline jwks parse_jwks(const traits::kazuho_picojson::string_type& token) { return jwks(token); } @@ -81,7 +89,7 @@ namespace jwt { * This type is the specialization of the \ref verify_ops::verify_context class which * uses the standard template types. */ - using verify_context = verify_ops::verify_context; + JWT_CPP_EXPORT using verify_context = verify_ops::verify_context; } // namespace jwt #endif // JWT_CPP_KAZUHO_PICOJSON_DEFAULTS_H diff --git a/include/jwt-cpp/traits/kazuho-picojson/traits.h b/include/jwt-cpp/traits/kazuho-picojson/traits.h index 2e759cd42..22cf32dad 100644 --- a/include/jwt-cpp/traits/kazuho-picojson/traits.h +++ b/include/jwt-cpp/traits/kazuho-picojson/traits.h @@ -1,6 +1,14 @@ #ifndef JWT_CPP_PICOJSON_TRAITS_H #define JWT_CPP_PICOJSON_TRAITS_H +#ifndef JWT_CPP_EXPORT +#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) +#define JWT_CPP_EXPORT export +#else +#define JWT_CPP_EXPORT +#endif +#endif + #ifndef PICOJSON_USE_INT64 #define PICOJSON_USE_INT64 #endif @@ -21,7 +29,7 @@ namespace jwt { */ namespace traits { /// basic_claim's JSON trait implementation for picojson - struct kazuho_picojson { + JWT_CPP_EXPORT struct kazuho_picojson { using value_type = picojson::value; using object_type = picojson::object; using array_type = picojson::array; diff --git a/include/picojson/picojson.h b/include/picojson/picojson.h index 711188990..ddea5aad9 100644 --- a/include/picojson/picojson.h +++ b/include/picojson/picojson.h @@ -28,6 +28,12 @@ #ifndef picojson_h #define picojson_h +#ifdef JWT_CPP_EXPORT +#define PICOJSON_JWT_CPP_EXPORT JWT_CPP_EXPORT +#else +#define PICOJSON_JWT_CPP_EXPORT +#endif + #if defined(JWT_CPP_MODULE_INTERFACE_BUILD) && defined(JWT_USE_IMPORT_STD) #define PICOJSON_USE_IMPORTED_STD 1 #else @@ -144,9 +150,9 @@ enum { enum { INDENT_WIDTH = 2, DEFAULT_MAX_DEPTHS = 100 }; -struct null {}; +PICOJSON_JWT_CPP_EXPORT struct null {}; -class value { +PICOJSON_JWT_CPP_EXPORT class value { public: typedef std::vector array; typedef std::map object; @@ -218,8 +224,8 @@ class value { void clear(); }; -typedef value::array array; -typedef value::object object; +PICOJSON_JWT_CPP_EXPORT typedef value::array array; +PICOJSON_JWT_CPP_EXPORT typedef value::object object; inline value::value() : type_(null_type), u_() { } @@ -1160,7 +1166,7 @@ inline const std::string &get_last_error() { return last_error_t::s; } -inline bool operator==(const value &x, const value &y) { +PICOJSON_JWT_CPP_EXPORT inline bool operator==(const value &x, const value &y) { if (x.is()) return y.is(); #define PICOJSON_CMP(type) \ @@ -1179,7 +1185,7 @@ inline bool operator==(const value &x, const value &y) { return false; } -inline bool operator!=(const value &x, const value &y) { +PICOJSON_JWT_CPP_EXPORT inline bool operator!=(const value &x, const value &y) { return !(x == y); } } @@ -1192,7 +1198,7 @@ template <> inline void swap(picojson::value &x, picojson::value &y) { } #endif -inline std::istream &operator>>(std::istream &is, picojson::value &x) { +PICOJSON_JWT_CPP_EXPORT inline std::istream &operator>>(std::istream &is, picojson::value &x) { picojson::set_last_error(std::string()); const std::string err(picojson::parse(x, is)); if (!err.empty()) { @@ -1202,7 +1208,7 @@ inline std::istream &operator>>(std::istream &is, picojson::value &x) { return is; } -inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) { +PICOJSON_JWT_CPP_EXPORT inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) { x.serialize(std::ostream_iterator(os)); return os; } @@ -1210,6 +1216,7 @@ inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) { #pragma warning(pop) #endif +#undef PICOJSON_JWT_CPP_EXPORT #undef PICOJSON_USE_IMPORTED_STD #endif diff --git a/modules/jwt.cppm b/modules/jwt.cppm index 77fb4ac1a..061c522b6 100644 --- a/modules/jwt.cppm +++ b/modules/jwt.cppm @@ -71,15 +71,9 @@ module; export module jwt_cpp; #ifdef JWT_USE_IMPORT_STD -// Keep std private to jwt_cpp. Re-exporting it makes mixed consumers -// (gtest, iostream, third-party JSON headers) collide with the MSVC std module. import std; #endif -// Build the public headers in module purview so imported declarations are -// attached to jwt_cpp instead of the global module. #define JWT_CPP_MODULE_INTERFACE_BUILD 1 -export { #include "jwt-cpp/jwt.h" -} #undef JWT_CPP_MODULE_INTERFACE_BUILD From c5d5e0ff44d9566cc9623c0b44ff2e3d39fa4747 Mon Sep 17 00:00:00 2001 From: DockedFerret800 Date: Fri, 24 Apr 2026 18:24:48 +0100 Subject: [PATCH 08/12] Update documentation --- README.md | 9 +++++++++ docs/install.md | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/README.md b/README.md index 6412ada0f..452810ccb 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,15 @@ If you are looking to issue or verify more unique tokens, checkout out the [exam Building on the goal of providing flexibility. +#### Modules support +jwt-cpp supports C++20/23 modules. There are two configuration options `JWT_ENABLE_MODULES` to enable modules (С++20) and `JWT_USE_IMPORT_STD` to use `import std` (С++23). +CMake example: +```cmake +set(JWT_ENABLE_MODULES ON) +set(JWT_USE_IMPORT_STD ON) +``` +You can now `import jwt_cpp;`. + #### SSL Compatibility jwt-cpp supports [OpenSSL](https://github.com/openssl/openssl), [LibreSSL](https://github.com/libressl-portable/portable), and [wolfSSL](https://github.com/wolfSSL/wolfssl). For a listed of tested versions, check [this page](docs/ssl.md) for more details. diff --git a/docs/install.md b/docs/install.md index 3266e29ff..5215045ea 100644 --- a/docs/install.md +++ b/docs/install.md @@ -8,6 +8,15 @@ It's strongly recommended to use a package manager, as JWT-CPP has dependencies When manually adding this dependency, and the dependencies this has, check the GitHub Actions and Workflows for some inspiration about how to go about it. +#### Modules support +jwt-cpp supports C++20/23 modules. There are two configuration options `JWT_ENABLE_MODULES` to enable modules (С++20) and `JWT_USE_IMPORT_STD` to use `import std` (С++23). +CMake example: +```cmake +set(JWT_ENABLE_MODULES ON) +set(JWT_USE_IMPORT_STD ON) +``` +You can now `import jwt_cpp;`. + ### Package Manager - Conan: From 9dea9dfac891eb6a07532607d0e4c44021ab213f Mon Sep 17 00:00:00 2001 From: Yan Romao Date: Fri, 24 Apr 2026 19:12:12 +0100 Subject: [PATCH 09/12] Modules CI (#1) --- .github/workflows/modules.yml | 56 ++++++++++++++++++++++++++++++++++ CMakePresets.json | 57 +++++++++++++++++++++++++++++++++++ README.md | 2 +- docs/install.md | 2 +- 4 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/modules.yml diff --git a/.github/workflows/modules.yml b/.github/workflows/modules.yml new file mode 100644 index 000000000..361e5689c --- /dev/null +++ b/.github/workflows/modules.yml @@ -0,0 +1,56 @@ +name: Build & Test with modules + +on: + push: + branches: [master] + pull_request: + branches: [master] + paths: + - "CMakeLists.txt" + - "cmake/**" + - "include/jwt-cpp/**" + - "tests/cmake/**" + - ".github/actions/**" + - ".github/workflows/cmake.yml" + +jobs: + build: + name: ${{ matrix.runs_on }}-${{ matrix.compiler }}-${{ matrix.configure_preset }} + runs-on: ${{ matrix.runs_on }} + strategy: + fail-fast: false + matrix: + include: + - runs_on: windows-2025-vs2026 + compiler: msvc-14.50 + configure_preset: "x64-vs-modules" + build_preset: "x64-vs-modules-build" + test_preset : "x64-vs-modules-test" + # To be uncommented once GitHub Actions adds GCC 15 with Ubuntu 26 + # - runs_on: ubuntu-latest + # compiler: gcc-15 + # configure_preset: "linux-debug" + # build_preset: "linux-debug-build" + # test_preset : "linux-debug-test" + # - runs_on: ubuntu-latest + # compiler: clang-18 + # cc: clang + # cxx: clang++ + # configure_preset: "linux-debug-modules" + # build_preset: "linux-debug-modules-build" + # test_preset : "linux-debug-modules-test" + steps: + + - uses: actions/checkout@v6 + + - uses: lukka/get-cmake@latest + + - name: "Build & Test" + uses: lukka/run-cmake@v10 + env: + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + with: + configurePreset: ${{ matrix.configure_preset }} + buildPreset: ${{ matrix.build_preset }} + testPreset: ${{ matrix.test_preset }} \ No newline at end of file diff --git a/CMakePresets.json b/CMakePresets.json index acac67081..8463236f1 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -21,6 +21,47 @@ "JWT_BUILD_EXAMPLES": "ON", "JWT_BUILD_TESTS": "ON" } + }, + { + "name": "windows-vs-base", + "hidden": true, + "generator": "Visual Studio 18 2026", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "x64-vs-modules", + "displayName": "x64 (VS generator) with Modules", + "inherits": "windows-vs-base", + "architecture": "x64", + "cacheVariables": { + "JWT_ENABLE_MODULES": "ON", + "JWT_USE_IMPORT_STD": "ON", + "JWT_BUILD_EXAMPLES": "ON" + } + }, + { + "name": "linux-debug-modules", + "displayName": "Linux Debug with Modules", + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "JWT_ENABLE_MODULES": "ON", + "JWT_USE_IMPORT_STD": "ON", + "JWT_BUILD_EXAMPLES": "ON" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + } } ], "buildPresets": [ @@ -28,6 +69,14 @@ "name": "dev", "configurePreset": "dev", "configuration": "Debug" + }, + { + "name": "x64-vs-modules-build", + "configurePreset": "x64-vs-modules" + }, + { + "name": "linux-debug-modules-build", + "configurePreset": "linux-debug-modules" } ], "testPresets": [ @@ -35,6 +84,14 @@ "name": "dev", "displayName": "Run all tests", "configurePreset": "dev" + }, + { + "name": "x64-vs-modules-test", + "configurePreset": "x64-vs-modules" + }, + { + "name": "linux-debug-modules-test", + "configurePreset": "linux-debug-modules" } ] } \ No newline at end of file diff --git a/README.md b/README.md index 452810ccb..80aa26dc2 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ If you are looking to issue or verify more unique tokens, checkout out the [exam Building on the goal of providing flexibility. #### Modules support -jwt-cpp supports C++20/23 modules. There are two configuration options `JWT_ENABLE_MODULES` to enable modules (С++20) and `JWT_USE_IMPORT_STD` to use `import std` (С++23). +jwt-cpp supports C++20/23 modules. There are two configuration options: `JWT_ENABLE_MODULES` to enable modules (С++20) and `JWT_USE_IMPORT_STD` to use `import std` (С++23). CMake example: ```cmake set(JWT_ENABLE_MODULES ON) diff --git a/docs/install.md b/docs/install.md index 5215045ea..28220b2f6 100644 --- a/docs/install.md +++ b/docs/install.md @@ -9,7 +9,7 @@ It's strongly recommended to use a package manager, as JWT-CPP has dependencies When manually adding this dependency, and the dependencies this has, check the GitHub Actions and Workflows for some inspiration about how to go about it. #### Modules support -jwt-cpp supports C++20/23 modules. There are two configuration options `JWT_ENABLE_MODULES` to enable modules (С++20) and `JWT_USE_IMPORT_STD` to use `import std` (С++23). +jwt-cpp supports C++20/23 modules. There are two configuration options: `JWT_ENABLE_MODULES` to enable modules (С++20) and `JWT_USE_IMPORT_STD` to use `import std` (С++23). CMake example: ```cmake set(JWT_ENABLE_MODULES ON) From d8cbf1a9c9301eb2f00ccdd847b6fe957f513dcb Mon Sep 17 00:00:00 2001 From: DockedFerret800 Date: Sat, 13 Jun 2026 14:41:49 +0100 Subject: [PATCH 10/12] clang 22 and gcc 15 modules CI --- .github/workflows/modules.yml | 29 +++++++++++++++-------------- CMakePresets.json | 16 +++++++--------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/.github/workflows/modules.yml b/.github/workflows/modules.yml index 361e5689c..44c78ff2f 100644 --- a/.github/workflows/modules.yml +++ b/.github/workflows/modules.yml @@ -15,7 +15,7 @@ on: jobs: build: - name: ${{ matrix.runs_on }}-${{ matrix.compiler }}-${{ matrix.configure_preset }} + name: ${{ matrix.runs_on }}-${{ matrix.compiler }} runs-on: ${{ matrix.runs_on }} strategy: fail-fast: false @@ -26,19 +26,20 @@ jobs: configure_preset: "x64-vs-modules" build_preset: "x64-vs-modules-build" test_preset : "x64-vs-modules-test" - # To be uncommented once GitHub Actions adds GCC 15 with Ubuntu 26 - # - runs_on: ubuntu-latest - # compiler: gcc-15 - # configure_preset: "linux-debug" - # build_preset: "linux-debug-build" - # test_preset : "linux-debug-test" - # - runs_on: ubuntu-latest - # compiler: clang-18 - # cc: clang - # cxx: clang++ - # configure_preset: "linux-debug-modules" - # build_preset: "linux-debug-modules-build" - # test_preset : "linux-debug-modules-test" + - runs_on: ubuntu-26.04 + compiler: gcc-15 + cc: gcc-15 + cxx: g++-15 + configure_preset: "linux-modules" + build_preset: "linux-modules-build" + test_preset : "linux-modules-test" + - runs_on: ubuntu-26.04 + compiler: clang-22 + cc: clang-22 + cxx: clang++-22 + configure_preset: "linux-modules" + build_preset: "linux-modules-build" + test_preset : "linux-modules-test" steps: - uses: actions/checkout@v6 diff --git a/CMakePresets.json b/CMakePresets.json index 8463236f1..f69fbf807 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -36,25 +36,23 @@ }, { "name": "x64-vs-modules", - "displayName": "x64 (VS generator) with Modules", + "displayName": "x64 (VS generator) with Modules (CI)", "inherits": "windows-vs-base", "architecture": "x64", "cacheVariables": { "JWT_ENABLE_MODULES": "ON", - "JWT_USE_IMPORT_STD": "ON", "JWT_BUILD_EXAMPLES": "ON" } }, { - "name": "linux-debug-modules", - "displayName": "Linux Debug with Modules", + "name": "linux-modules", + "displayName": "Linux Debug with Modules (CI)", "generator": "Ninja", "binaryDir": "${sourceDir}/out/build/${presetName}", "installDir": "${sourceDir}/out/install/${presetName}", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", "JWT_ENABLE_MODULES": "ON", - "JWT_USE_IMPORT_STD": "ON", "JWT_BUILD_EXAMPLES": "ON" }, "condition": { @@ -75,8 +73,8 @@ "configurePreset": "x64-vs-modules" }, { - "name": "linux-debug-modules-build", - "configurePreset": "linux-debug-modules" + "name": "linux-modules-build", + "configurePreset": "linux-modules" } ], "testPresets": [ @@ -90,8 +88,8 @@ "configurePreset": "x64-vs-modules" }, { - "name": "linux-debug-modules-test", - "configurePreset": "linux-debug-modules" + "name": "linux-modules-test", + "configurePreset": "linux-modules" } ] } \ No newline at end of file From ac919bdf2877f252ef55eebecfbb246efadefb62 Mon Sep 17 00:00:00 2001 From: DockedFerret800 Date: Sat, 13 Jun 2026 14:42:03 +0100 Subject: [PATCH 11/12] Address feedback --- CMakeLists.txt | 14 ++----- README.md | 3 +- docs/install.md | 3 +- example/es256k.cpp | 5 --- example/jwks-verify.cpp | 5 --- example/print-claims.cpp | 4 -- example/private-claims.cpp | 6 --- example/rsa-create.cpp | 5 --- example/rsa-verify.cpp | 5 --- include/jwt-cpp/base.h | 4 +- include/jwt-cpp/jwt.h | 2 +- include/jwt-cpp/traits/boost-json/traits.h | 2 +- .../traits/danielaparker-jsoncons/traits.h | 2 +- .../jwt-cpp/traits/kazuho-picojson/traits.h | 2 +- include/jwt-cpp/traits/nlohmann-json/traits.h | 2 +- .../open-source-parsers-jsoncpp/traits.h | 2 +- include/picojson/picojson.h | 2 +- modules/jwt.cppm | 40 ------------------- tests/CMakeLists.txt | 2 +- 19 files changed, 14 insertions(+), 96 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 31e313fd1..3dc47614c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ if(POLICY CMP0135) # DOWNLOAD_EXTRACT_TIMESTAMP cmake_policy(SET CMP0135 NEW) endif() -set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "451f2fe2-a8a2-47c3-bc32-94786d8fc91b") +set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "451f2fe2-a8a2-47c3-bc32-94786d8fc91b" CACHE STRING "") # HUNTER_ENABLED is always set if this package is included in a project using hunter (HunterGate sets it) In this case # we will use hunter as well to stay consistent. If not the use can supply it on configure to force using hunter. @@ -23,7 +23,6 @@ option(JWT_BUILD_DOCS "Adds a target for building the doxygen documentation" OFF option(JWT_ENABLE_COVERAGE "Enable code coverage testing" OFF) option(JWT_ENABLE_FUZZING "Enable fuzz testing" OFF) option(JWT_ENABLE_MODULES "Build C++ modules" OFF) -option(JWT_USE_IMPORT_STD "Use import std" OFF) option(JWT_DISABLE_PICOJSON "Do not provide the picojson template specialiaze" OFF) option(JWT_DISABLE_BASE64 "Do not include the base64 implementation from this library" OFF) @@ -113,10 +112,8 @@ if (JWT_ENABLE_MODULES) set(CMAKE_CXX_SCAN_FOR_MODULES ON) - if(JWT_USE_IMPORT_STD) - if(NOT CMAKE_GENERATOR MATCHES "Visual Studio") + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio") set(CMAKE_CXX_MODULE_STD 1) - endif() endif() endif() @@ -132,12 +129,7 @@ add_library(jwt-cpp::jwt-cpp ALIAS jwt-cpp) # To match export if(NOT JWT_ENABLE_MODULES) target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_11) else() - if(NOT JWT_USE_IMPORT_STD) - target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_20) - else() - target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_23) - target_compile_definitions(jwt-cpp PRIVATE JWT_USE_IMPORT_STD) - endif() + target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_23) target_sources(jwt-cpp PUBLIC FILE_SET cxx_modules TYPE CXX_MODULES diff --git a/README.md b/README.md index 80aa26dc2..c74959472 100644 --- a/README.md +++ b/README.md @@ -101,11 +101,10 @@ If you are looking to issue or verify more unique tokens, checkout out the [exam Building on the goal of providing flexibility. #### Modules support -jwt-cpp supports C++20/23 modules. There are two configuration options: `JWT_ENABLE_MODULES` to enable modules (С++20) and `JWT_USE_IMPORT_STD` to use `import std` (С++23). +jwt-cpp supports modules. Use `JWT_ENABLE_MODULES` to enable modules. This requires C++23, because modules are used in combination with `import std`. CMake example: ```cmake set(JWT_ENABLE_MODULES ON) -set(JWT_USE_IMPORT_STD ON) ``` You can now `import jwt_cpp;`. diff --git a/docs/install.md b/docs/install.md index 28220b2f6..361fc0043 100644 --- a/docs/install.md +++ b/docs/install.md @@ -9,11 +9,10 @@ It's strongly recommended to use a package manager, as JWT-CPP has dependencies When manually adding this dependency, and the dependencies this has, check the GitHub Actions and Workflows for some inspiration about how to go about it. #### Modules support -jwt-cpp supports C++20/23 modules. There are two configuration options: `JWT_ENABLE_MODULES` to enable modules (С++20) and `JWT_USE_IMPORT_STD` to use `import std` (С++23). +jwt-cpp supports modules. Use `JWT_ENABLE_MODULES` to enable modules. This requires C++23, because modules are used in combination with `import std`. CMake example: ```cmake set(JWT_ENABLE_MODULES ON) -set(JWT_USE_IMPORT_STD ON) ``` You can now `import jwt_cpp;`. diff --git a/example/es256k.cpp b/example/es256k.cpp index c8d599095..984fcbd0c 100644 --- a/example/es256k.cpp +++ b/example/es256k.cpp @@ -5,12 +5,7 @@ #include #include #else -#ifdef JWT_USE_IMPORT_STD import std; -#else -#include -#include -#endif import jwt_cpp; #endif diff --git a/example/jwks-verify.cpp b/example/jwks-verify.cpp index 5918ee02b..612da712b 100644 --- a/example/jwks-verify.cpp +++ b/example/jwks-verify.cpp @@ -11,12 +11,7 @@ #include #include #else -#ifdef JWT_USE_IMPORT_STD import std; -#else -#include -#include -#endif import jwt_cpp; #endif diff --git a/example/print-claims.cpp b/example/print-claims.cpp index 56ae1038d..2dd1222c7 100644 --- a/example/print-claims.cpp +++ b/example/print-claims.cpp @@ -4,11 +4,7 @@ #include #include #else -#ifdef JWT_USE_IMPORT_STD import std; -#else -#include -#endif import jwt_cpp; #endif diff --git a/example/private-claims.cpp b/example/private-claims.cpp index 068ea01f1..09a0d6966 100644 --- a/example/private-claims.cpp +++ b/example/private-claims.cpp @@ -6,13 +6,7 @@ #include #include #else -#ifdef JWT_USE_IMPORT_STD import std; -#else -#include -#include -#include -#endif import jwt_cpp; #endif diff --git a/example/rsa-create.cpp b/example/rsa-create.cpp index b7fb7a1ec..2fc22ca2f 100644 --- a/example/rsa-create.cpp +++ b/example/rsa-create.cpp @@ -5,12 +5,7 @@ #include #include #else -#ifdef JWT_USE_IMPORT_STD import std; -#else -#include -#include -#endif import jwt_cpp; #endif diff --git a/example/rsa-verify.cpp b/example/rsa-verify.cpp index 787784630..e20e3cc0c 100644 --- a/example/rsa-verify.cpp +++ b/example/rsa-verify.cpp @@ -5,12 +5,7 @@ #include #include #else -#ifdef JWT_USE_IMPORT_STD import std; -#else -#include -#include -#endif import jwt_cpp; #endif diff --git a/include/jwt-cpp/base.h b/include/jwt-cpp/base.h index 80ba58b70..07cb55c43 100644 --- a/include/jwt-cpp/base.h +++ b/include/jwt-cpp/base.h @@ -9,9 +9,7 @@ #endif #endif -#if !defined(JWT_CPP_MODULE_INTERFACE_BUILD) && defined(JWT_USE_IMPORT_STD) -import std; -#elif !defined(JWT_CPP_MODULE_INTERFACE_BUILD) +#if !defined(JWT_CPP_MODULE_INTERFACE_BUILD) #include #include #include diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index e4bbd7ac8..caba0ed31 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -9,7 +9,7 @@ #endif #endif -#if !defined(JWT_CPP_MODULE_INTERFACE_BUILD) || !defined(JWT_USE_IMPORT_STD) +#if !defined(JWT_CPP_MODULE_INTERFACE_BUILD) #include #include #include diff --git a/include/jwt-cpp/traits/boost-json/traits.h b/include/jwt-cpp/traits/boost-json/traits.h index a3c6989f1..a7af51bae 100644 --- a/include/jwt-cpp/traits/boost-json/traits.h +++ b/include/jwt-cpp/traits/boost-json/traits.h @@ -2,7 +2,7 @@ #define JWT_CPP_BOOSTJSON_TRAITS_H #define JWT_DISABLE_PICOJSON -#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +#if defined(JWT_ENABLE_MODULES) import jwt_cpp; #else #include "jwt-cpp/jwt.h" diff --git a/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h b/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h index b133e4552..965b21229 100644 --- a/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h +++ b/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h @@ -5,7 +5,7 @@ #define JSONCONS_NO_DEPRECATED #include "jsoncons/json.hpp" -#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +#if defined(JWT_ENABLE_MODULES) import jwt_cpp; #else #include "jwt-cpp/jwt.h" diff --git a/include/jwt-cpp/traits/kazuho-picojson/traits.h b/include/jwt-cpp/traits/kazuho-picojson/traits.h index 22cf32dad..9d800ff59 100644 --- a/include/jwt-cpp/traits/kazuho-picojson/traits.h +++ b/include/jwt-cpp/traits/kazuho-picojson/traits.h @@ -17,7 +17,7 @@ #ifndef JWT_DISABLE_PICOJSON #define JWT_DISABLE_PICOJSON #endif -#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +#if defined(JWT_ENABLE_MODULES) import jwt_cpp; #else #include "jwt-cpp/jwt.h" diff --git a/include/jwt-cpp/traits/nlohmann-json/traits.h b/include/jwt-cpp/traits/nlohmann-json/traits.h index 50485aab7..43a228dc9 100644 --- a/include/jwt-cpp/traits/nlohmann-json/traits.h +++ b/include/jwt-cpp/traits/nlohmann-json/traits.h @@ -1,7 +1,7 @@ #ifndef JWT_CPP_NLOHMANN_JSON_TRAITS_H #define JWT_CPP_NLOHMANN_JSON_TRAITS_H -#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +#if defined(JWT_ENABLE_MODULES) import jwt_cpp; #else #include diff --git a/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h b/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h index 63e54ce8d..5419194d0 100644 --- a/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h +++ b/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h @@ -1,7 +1,7 @@ #ifndef JWT_CPP_JSONCPP_TRAITS_H #define JWT_CPP_JSONCPP_TRAITS_H -#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +#if defined(JWT_ENABLE_MODULES) import jwt_cpp; #else #include "jwt-cpp/jwt.h" diff --git a/include/picojson/picojson.h b/include/picojson/picojson.h index ddea5aad9..a93426206 100644 --- a/include/picojson/picojson.h +++ b/include/picojson/picojson.h @@ -34,7 +34,7 @@ #define PICOJSON_JWT_CPP_EXPORT #endif -#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) && defined(JWT_USE_IMPORT_STD) +#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) #define PICOJSON_USE_IMPORTED_STD 1 #else #define PICOJSON_USE_IMPORTED_STD 0 diff --git a/modules/jwt.cppm b/modules/jwt.cppm index 061c522b6..d2f58a8fb 100644 --- a/modules/jwt.cppm +++ b/modules/jwt.cppm @@ -8,43 +8,6 @@ module; #define WIN32_LEAN_AND_MEAN 1 #endif -#ifndef JWT_USE_IMPORT_STD -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#else #include #include #include @@ -53,7 +16,6 @@ module; #include #include #include -#endif #include #include @@ -70,9 +32,7 @@ module; export module jwt_cpp; -#ifdef JWT_USE_IMPORT_STD import std; -#endif #define JWT_CPP_MODULE_INTERFACE_BUILD 1 #include "jwt-cpp/jwt.h" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 31d0adf26..bd833c164 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -145,7 +145,7 @@ if(TARGET reflectcpp::reflectcpp) endif() add_executable(jwt-cpp-test ${TEST_SOURCES}) -if(JWT_ENABLE_MODULES AND NOT JWT_USE_IMPORT_STD) +if(JWT_ENABLE_MODULES) target_compile_definitions(jwt-cpp-test PRIVATE JWT_ENABLE_MODULES) set_property(TARGET jwt-cpp-test PROPERTY CXX_SCAN_FOR_MODULES ON) endif() From 333c2e00c87b3210941aa78d9a9297031d6cd46b Mon Sep 17 00:00:00 2001 From: DockedFerret800 Date: Sat, 13 Jun 2026 15:06:02 +0100 Subject: [PATCH 12/12] Examples include order --- example/traits/boost-json.cpp | 4 ++-- example/traits/danielaparker-jsoncons.cpp | 4 ++-- example/traits/kazuho-picojson.cpp | 4 ++-- example/traits/nlohmann-json.cpp | 4 ++-- example/traits/open-source-parsers-jsoncpp.cpp | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/example/traits/boost-json.cpp b/example/traits/boost-json.cpp index 25912b5c7..6f6399db6 100644 --- a/example/traits/boost-json.cpp +++ b/example/traits/boost-json.cpp @@ -1,9 +1,9 @@ +#include "jwt-cpp/traits/boost-json/traits.h" + // #include // You may require this if you are not building it elsewhere #include #include -#include "jwt-cpp/traits/boost-json/traits.h" - int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/danielaparker-jsoncons.cpp b/example/traits/danielaparker-jsoncons.cpp index c3a5dda8f..61043deb0 100644 --- a/example/traits/danielaparker-jsoncons.cpp +++ b/example/traits/danielaparker-jsoncons.cpp @@ -1,8 +1,8 @@ +#include "jwt-cpp/traits/danielaparker-jsoncons/traits.h" + #include #include -#include "jwt-cpp/traits/danielaparker-jsoncons/traits.h" - int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/kazuho-picojson.cpp b/example/traits/kazuho-picojson.cpp index fade710c0..4bdf4a078 100644 --- a/example/traits/kazuho-picojson.cpp +++ b/example/traits/kazuho-picojson.cpp @@ -1,8 +1,8 @@ +#include "jwt-cpp/traits/kazuho-picojson/traits.h" + #include #include -#include "jwt-cpp/traits/kazuho-picojson/traits.h" - int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/nlohmann-json.cpp b/example/traits/nlohmann-json.cpp index f4147f115..f0bb1d5d7 100644 --- a/example/traits/nlohmann-json.cpp +++ b/example/traits/nlohmann-json.cpp @@ -1,8 +1,8 @@ +#include "jwt-cpp/traits/nlohmann-json/traits.h" + #include #include -#include "jwt-cpp/traits/nlohmann-json/traits.h" - int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/open-source-parsers-jsoncpp.cpp b/example/traits/open-source-parsers-jsoncpp.cpp index eb503efc6..523925c10 100644 --- a/example/traits/open-source-parsers-jsoncpp.cpp +++ b/example/traits/open-source-parsers-jsoncpp.cpp @@ -1,8 +1,8 @@ +#include "jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h" + #include #include -#include "jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h" - int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes;