jwt-cpp

repository·master·Indexed 22 days ago

https://github.com/thalhammer/jwt-cpp

A header-only C++11 library for creating, parsing, and verifying JSON Web Tokens (JWT) according to RFC 7519. It supports a wide range of signature algorithms including HMAC (HS256, HS384, HS512), RSA (RS256, RS384, RS512), ECDSA, PSS, and EdDSA, with the ability to implement custom algorithms. The library is designed to be JSON-library agnostic via a traits system and is compatible with OpenSSL, LibreSSL, and wolfSSL.

Tokens
5.4K
Snippets
12
Records
24
Agent score
78%

What's inside jwt-cpp

  1. Overview of jwt-cpp

    master
    jwt-cpp is a header-only C++11 library designed for creating and validating JSON Web Tokens (JWT) according to RFC 7519. It is designed to be versatile and easily integrated with other libraries through a modular architecture.
  2. How JSON Traits work in jwt-cpp

    master

    JSON Traits define the compatibility mapping between jwt-cpp and a specific JSON library implementation. Because jwt-cpp is designed to be library-agnostic, it uses these traits to understand how to interact with your chosen JSON library's types, how to parse strings into JSON objects, and how to serialize JSON objects back into strings.

    When using jwt-cpp, you must pass the traits class as a template parameter to core functions like jwt::create<traits>(), jwt::decode<traits>(), and jwt::verify<traits>().

    using traits = jwt::traits::nlohmann_json;
    
    const auto token = jwt::create<traits>()
                           .set_issuer("auth.mydomain.io")
                           .sign(jwt::algorithm::hs256{"secret"});
    
    const auto decoded = jwt::decode<traits>(token);
  3. Security considerations for JWT claims

    master

    JWTs generated by this library are encoded but not encrypted. While the signature ensures integrity (preventing unauthorized modification), the payload is readable by anyone who has the token.

    Do not store confidential or sensitive information directly in JWT claims.

    If you need to include sensitive data, the recommended pattern is to generate a random ID, store the sensitive data on your server, and include only that ID in the JWT claims to look up the data when needed.

  4. Configure JSON library via Traits

    master

    jwt-cpp does not force a specific JSON library. Instead, it uses a templated jwt::basic_claim that relies on a type trait to map semantic JSON types (objects, arrays, strings, etc.). You can use provided traits or implement your own to integrate your preferred JSON library.

    To use your own JSON library, pass your custom traits to jwt::basic_claim:

    jwt::basic_claim<my_favorite_json_library_traits> claim(json::object({{"json", true},{"example", 0}}));
  5. Implement custom signature algorithms

    master

    The jwt-cpp library allows you to implement and use your own signature algorithms by defining a struct that satisfies a specific interface. Your implementation must provide sign, verify, and name methods.

    To implement a custom algorithm:

    1. Define a struct containing:
      • std::string sign(const std::string& /*unused*/, std::error_code& ec) const: Performs the signing logic. You must clear the error code (ec.clear()) before performing your operation.
      • void verify(const std::string& /*unused*/, const std::string& signature, std::error_code& ec) const: Validates the signature. If verification fails, set ec to an appropriate error code.
      • std::string name() const: Returns the unique string identifier for your algorithm.
    2. Pass an instance of your struct to the .sign() method during token creation.
    struct your_algorithm{
        std::string sign(const std::string& /*unused*/, std::error_code& ec) const {
            ec.clear();
            // CALL YOUR METHOD HERE
            return {};
        }
        void verify(const std::string& /*unused*/, const std::string& signature, std::error_code& ec) const {
            ec.clear();
            if (!signature.empty()) { ec = error::signature_verification_error::invalid_signature; }
            
            // CALL YOUR METHOD HERE
        }
        std::string name() const { return "your_algorithm"; }
    };
    
    // Usage:
    auto token = jwt::create()
                    .set_id("custom-algo-example")
                    .set_issued_now()
                    .set_expires_in(std::chrono::seconds{36000})
                    .set_payload_claim("sample", jwt::claim(std::string{"test"}))
                    .sign(your_algorithm{/* parameters */});
  6. Install jwt-cpp dependencies

    master

    To use jwt-cpp, ensure your environment meets the following requirements:

    • libcrypto (OpenSSL or compatible)
    • libssl-dev (for header files)
    • A compiler supporting at least C++11
    • Basic STL support

    If you are building the included test cases, you also need:

    • gtest
    • pthread
  7. Use jwt-cpp as a header-only library

    master

    You can use jwt-cpp as a header-only library by downloading the include/ directory.

    Requirements:

    1. Ensure the jwt-cpp/ subdirectory is visible during compilation.
    2. You must correctly link to OpenSSL or an alternative cryptography library.
    3. If you wish to use your own JSON traits implementation, you must define the following macros:
      • JWT_DISABLE_BASE64
      • JWT_DISABLE_PICOJSON

    Refer to traits.md for details on providing custom JSON traits.

  8. Select a cryptography library via CMake

    master

    When configuring the project with CMake, you can choose which underlying SSL/TLS library to use for cryptographic operations. By default, the project uses OpenSSL.

    You can explicitly select one of the following libraries by setting the JWT_SSL_LIBRARY CMake variable:

    • OpenSSL (Default)
    • LibreSSL
    • wolfSSL

    Important Note on Linking: Since jwt-cpp relies on the OpenSSL API, both LibreSSL and wolfSSL require their respective compatibility layers. Ensure that your application only includes one SSL library during compilation to avoid missing symbol errors during the linking stage.

    cmake . -DJWT_SSL_LIBRARY:STRING=wolfSSL
  9. Install jwt-cpp using a package manager

    master

    It is strongly recommended to use a package manager to handle the dependencies for cryptography and JSON libraries. You can find jwt-cpp recipes for the following package managers:

  10. Integrate jwt-cpp using CMake find_package

    master

    The recommended way to use jwt-cpp in a CMake project is via find_package.

    Prerequisites:

    • Ensure OpenSSL is installed on your environment.

    Installation Steps:

    1. Configure and build the library:
    cmake .
    cmake --build .
    cmake --install .
    1. In your own project's CMakeLists.txt, use find_package and link against the jwt-cpp::jwt-cpp target:
    find_package(jwt-cpp CONFIG REQUIRED)
    
    target_link_libraries(my_app PRIVATE jwt-cpp::jwt-cpp)
  11. Requirements for running Traits examples

    master

    The examples located in the example/traits/ directory require an upstream CMake installation to function.

    Note the following specific dependency requirements for header discovery:

    • Boost.JSON: Headers must be located using a custom CMake configuration.
    • PicoJSON: Headers must be located using a custom CMake configuration.
  12. Select a pre-built JSON library trait

    master

    For convenience, jwt-cpp provides built-in trait implementations for several popular JSON libraries. To use one, include its specific header and pass it as a template argument to the jwt namespace functions.

    Supported libraries include:

    • picojson (Note: picojson is used by default for specialized jwt::claim helpers. Define JWT_DISABLE_PICOJSON to remove this dependency.)
    • nlohmann-json
    • jsoncons
    • boost-json
    • jsoncpp
    • glaze
    • reflectcpp

    Example using nlohmann-json:

    #include "jwt-cpp/traits/nlohmann-json/traits.h"
    
    int main() {
        using traits = jwt::traits::nlohmann_json;
        // Use 'traits' in jwt::create<traits>(), jwt::decode<traits>(), etc.
    }
    #include "jwt-cpp/traits/nlohmann-json/traits.h"
    
    int main() {
        using traits = jwt::traits::nlohmann_json;
    
        const auto time = jwt::date::clock::now();
        const auto token = jwt::create<traits>()
                               .set_type("JWT")
                               .set_issuer("auth.mydomain.io")
                               .set_audience("mydomain.io")
                               .set_issued_at(time)
                               .set_not_before(time)
                               .set_expires_at(time + std::chrono::minutes{2} + std::chrono::seconds{15})
                               .sign(jwt::algorithm::none{});
        const auto decoded = jwt::decode<traits>(token);
    
        jwt::verify<traits>()
            .allow_algorithm(jwt::algorithm::none{})
            .with_issuer("auth.mydomain.io")
            .with_audience("mydomain.io")
            .verify(decoded);
    }