A C++14 library for JSON Web Tokens(JWT)

Overview

CPP-JWT

A C++14 library for JSON Web Tokens(JWT)


A little library built with lots of ❤︎ for working with JWT easier. By Arun Muralidharan.

Table of Contents

What is it ?

For the uninitiated, JSON Web Token(JWT) is a JSON based standard (RFC-7519) for creating assertions or access tokens that consists of some claims (encoded within the assertion). This assertion can be used in some kind of bearer authentication mechanism that the server will provide to clients, and the clients can make use of the provided assertion for accessing resources.

Few good resources on this material which I found useful are: Anatomy of JWT Learn JWT RFC 7519

Example

Lets dive into see a simple example of encoding and decoding in Python. Taking the example of pyjwt module from its docs.

>>import jwt
>>key = 'secret'
>>
>>encoded = jwt.encode({'some': 'payload'}, key, algorithm='HS256')
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg'
>>
>>decoded = jwt.decode(encoded, key, algorithms='HS256')
{'some': 'payload'}

Now, lets look at our C++ code doing the same thing.

#include <iostream>
#include "jwt/jwt.hpp"

int main() {
  using namespace jwt::params;

  auto key = "secret"; //Secret to use for the algorithm
  //Create JWT object
  jwt::jwt_object obj{algorithm("HS256"), payload({{"some", "payload"}}), secret(key)};

  //Get the encoded string/assertion
  auto enc_str = obj.signature();
  std::cout << enc_str << std::endl;

  //Decode
  auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), secret(key));
  std::cout << dec_obj.header() << std::endl;
  std::cout << dec_obj.payload() << std::endl;

  return 0;
}

It outputs:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg
{"alg":"HS256","typ":"JWT"}
{"some":"payload"}

Almost the same API, except for some ugliness here and there. But close enough!

Lets take another example in which we will see to add payload claim having type other than string. The payload function used in the above example to create jwt_object object can only take strings. For anything else, it will throw a compilation error.

For adding claims having values other than string, jwt_object class provides add_claim API. We will also see few other APIs in the next example. Make sure to read the comments :).

  #include <chrono>
  #include <cassert>
  #include <iostream>
  #include "jwt/jwt.hpp"

  int main() {
    using namespace jwt::params;

    jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"user", "admin"}})};

    //Use add_claim API to add claim values which are
    // _not_ strings.
    // For eg: `iat` and `exp` claims below.
    // Other claims could have been added in the payload
    // function above as they are just stringy things.
    obj.add_claim("iss", "arun.muralidharan")
       .add_claim("sub", "test")
       .add_claim("id", "a-b-c-d-e-f-1-2-3")
       .add_claim("iat", 1513862371)
       .add_claim("exp", std::chrono::system_clock::now() + std::chrono::seconds{10})
       ;

    //Use `has_claim` to check if the claim exists or not
    assert (obj.has_claim("iss"));
    assert (obj.has_claim("exp"));

    //Use `has_claim_with_value` to check if the claim exists
    //with a specific value or not.
    assert (obj.payload().has_claim_with_value("id", "a-b-c-d-e-f-1-2-3"));
    assert (obj.payload().has_claim_with_value("iat", 1513862371));

    //Remove a claim using `remove_claim` API.
    //Most APIs have an overload which takes enum class type as well
    //It can be used interchangeably with strings.
    obj.remove_claim(jwt::registered_claims::expiration);
    assert (!obj.has_claim("exp"));

    //Using `add_claim` with extra features.
    //Check return status and overwrite
    bool ret = obj.payload().add_claim("sub", "new test", false/*overwrite*/);
    assert (!ret);

    // Overwrite an existing claim
    ret = obj.payload().add_claim("sub", "new test", true/*overwrite*/);
    assert (ret);

    assert (obj.payload().has_claim_with_value("sub", "new test"));

    return 0;
  }

The jwt_object class is basically a composition of the JWT component classes, which are jwt_header & jwt_payload. For convenience jwt_object exposes only few important APIs to the user, the remaining APIs under jwt_header and jwt_payload can be accessed by calling jwt_object::header() and jwt_object::payload() APIs.

API Philosophy

I wanted to make the code easy to read and at the same time make most of the standard library and the modern features. It also uses some metaprogramming tricks to enforce type checks and give better error messages.

The design of parameters alleviates the pain of remembering positional arguments. Also makes the APIs more extensible for future enhancements.

The library has 2 sets of APIs for encoding and decoding:

  • API which takes an instance of std::error_code These APIs will report the errors by setting the error_code. This does not mean that these API would not throw. Memory allocation errors would still be thrown instead of setting the error_code.
  • API which throws exceptions All the errors would be thrown as exception.

Support

Algorithms and features supported

  • HS256
  • HS384
  • HS512
  • RS256
  • RS384
  • RS512
  • ES256
  • ES384
  • ES512
  • Sign
  • Verify
  • iss (issuer) check
  • sub (subject) check
  • aud (audience) check
  • exp (expiration time) check
  • nbf (not before time) check
  • iat (issued at) check
  • jti (JWT id) check
  • JWS header addition support. For eg "kid" support.

External Dependencies

  • OpenSSL (Version >= 1.0.2j) Might work with older version as well, but I did not check that.
  • Google Test Framework For running the tests
  • nlohmann JSON library The awesome JSON library :)

Thanks to...

ben-collins JWT library - Howard Hinnant for the stack allocator - libstd++ code (I took the hashing code for string_view) ">
- ben-collins JWT library
- Howard Hinnant for the stack allocator
- libstd++ code (I took the hashing code for string_view)

Compiler Support

Tested with clang-5.0 and g++-6.4. With issue#12, VS2017 is also supported.

Building the library

using conan

mkdir build
cd build
conan install .. --build missing
cmake ..
cmake --build . -j

using debian

sudo apt install nlohmann-json3-dev 
sudo apt install libgtest-dev
sudo apt install libssl-dev
mkdir build
cd build
cmake ..
cmake --build . -j

Consuming the library

This library is uses cmake as a build system.

# you can use cmake's `find_package` after installation or `add_subdirectory` when vendoring this repository

find_package(cpp-jwt REQUIRED)
# or
add_subdirectory(third_party/cpp-jwt)

add_executable(main main.cpp)
target_link_libraries(main cpp-jwt::cpp-jwt)

You can also use this library as a conan package, its available in the conan center: just add cpp-jwt[>=1.2] to your conanfile.txt.

It can also be installed using vcpkg by adding "cpp-jwt" to the dependencies in your vcpkg.json file.

Parameters

There are two sets of parameters which can be used for creating jwt_object and for decoding. All the parameters are basically a function which returns an instance of a type which are modelled after ParameterConcept (see jwt::detail::meta::is_parameter_concept).

  • jwt_object creation parameters

    • payload

      Used to populate the claims while creating the jwt_object instance.

      There are two overloads of this function:

      • Takes Initializer list of pair

        Easy to pass claims with string values which are all known at the time of object creation. Can be used like:

        jwt_object obj {
          payload({
              {"iss", "some-guy"},
              {"sub", "something"},
              {"X-pld", "data1"}
            }),
            ... // Add other parameters
        };

        Claim values which are not strings/string_views cannot be used.

      • Takes any type which models MappingConcept (see detail::meta::is_mapping_concept)

        This overload can accept std::map or std::unordered_map like containers. Can be used like:

        map
                  m;
        m[
                 "iss"] = 
                 "some-guy";
        m[
                 "sub"] = 
                 "something";
        m[
                 "X-pld"] = 
                 "data1";
        
        jwt_object obj{
          
                 payload(
                 std::move(m)),
          ... 
                 // Add other parameters
        };
        
                 //OR
        jwt_object obj{
          
                 payload(m),
          ... 
                 // Add other parameters
        };
                
    • secret

      Used to pass the key which could be some random string or the bytes of the PEM encoded public key file in PEM format (wrapped in -----BEGIN PUBLIC KEY----- block) as string. The passed string type must be convertible to jwt::string_view

    • algorithm

      Used to pass the type of algorithm to use for encoding. There are two overloads of this function:

      • Takes jwt::string_view

        Can pass the algorithm value in any case. It is case agnostic.

      • Takes value of type enum class jwt::algorithm

    • headers

      Used to populate fields in JWT header. It is very similar to payload function parameter. There are two overloads for this function which are similar to how payload function is. This parameter can be used to add headers other that alg and typ.

      Same as the case with payload, only string values can be used with this. For adding values of other data types, use add_header API of jwt_header class.

      For example adding kid header with other additional data fields.

      jwt_object obj{
        algorithm("HS256"),
        headers({
          {"kid", "12-34-56"},
          {"xtra", "header"}
        })
        ... // Add other parameters
      };
  • Decoding parameters

    • algorithms

      This is a mandatory parameter which takes a sequence of algorithms (as string) which the user would like to permit when validating the JWT. The value in the header for "alg" would be matched against the provided sequence of values. If nothing matches InvalidAlgorithmError exception or InvalidAlgorithm error would be set based upon the API being used.

      There are two overloads for this function:

      • Takes initializer-list of string values
      • Takes in any type which satifies the SequenceConcept (see idetail::meta::is_sequence_concept)
    algs{"none", "HS256", "RS256"}; jwt::decode(algorithms(algs), ...); ">
    jwt::decode(algorithms({"none", "HS256", "RS256"}), ...);
    
    OR
    
    std::vector
          algs{
         "none", 
         "HS256", 
         "RS256"};
    
         jwt::decode(algorithms(algs), ...);
        
    • secret

      Optional parameter. To be supplied only when the algorithm used is not "none". Else would throw/set KeyNotPresentError / KeyNotPresent exception/error.

    • leeway

      Optional parameter. Used with validation of "Expiration" and "Not Before" claims. The value passed should be seconds to account for clock skew. Default value is 0 seconds.

    • verify

      Optional parameter. Suggests if verification of claims should be done or not. Takes a boolean value. By default verification is turned on.

    • issuer

      Optional parameter. Takes a string value. Validates the passed issuer value against the one present in the decoded JWT object. If the values do not match InvalidIssuerError or InvalidIssuer exception or error_code is thrown/set.

    • aud

      Optional parameter. Takes a string value. Validates the passed audience value against the one present in the decoded JWT object. If the values do not match InvalidAudienceError or InvalidAudience exception or error_code is thrown/set.

    • sub

      Optional parameter. Takes a string value. Validates the passed subject value against the one present in the decoded JWT object. If the values do not match InvalidSubjectError or InvalidSubject exception or error_code is thrown/set.

    • validate_iat

      Optional parameter. Takes a boolean value. Validates the IAT claim. Only checks whether the field is present and is of correct type. If not throws/sets InvalidIATError or InvalidIAT.

      Default value is false.

    • validate_jti

      Optional parameter. Takes a boolean value. Validates the JTI claim. Only checks for the presence of the claim. If not throws or sets InvalidJTIError or InvalidJTI.

      Default is false.

Claim Data Types

For the registered claim types the library assumes specific data types for the claim values. Using anything else is not supported and would result in runtime JSON parse error.

Claim                 |  Data Type
-----------------------------------
Expiration(exp)       |  uint64_t (Epoch time in seconds)
-----------------------------------
Not Before(nbf)       |  uint64_t (Epoch time in seconds)
-----------------------------------
Issuer(iss)           |  string
-----------------------------------
Audience(aud)         |  string
-----------------------------------
Issued At(iat)        |  uint64_t (Epoch time in seconds)
-----------------------------------
Subject(sub)          |  string
-----------------------------------
JTI(jti)              | 
   
    
-----------------------------------

   

Advanced Examples

We will see few complete examples which makes use of error code checks and exception handling. The examples are taken from the "tests" section. Users are requested to checkout the tests to find out more ways to use this library.

Expiration verification example (uses error_code):

(jwt::VerificationErrc::TokenExpired)); return 0; } ">
#include <cassert>
#include <iostream>
#include "jwt/jwt.hpp"

int main() {
  using namespace jwt::params;

  jwt::jwt_object obj{algorithm("HS256"), secret("secret")};
  obj.add_claim("iss", "arun.muralidharan")
     .add_claim("exp", std::chrono::system_clock::now() - std::chrono::seconds{1})
     ;

  std::error_code ec;
  auto enc_str = obj.signature(ec);
  assert (!ec);

  auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret"), verify(true));
  assert (ec);
  assert (ec.value() == static_cast<int>(jwt::VerificationErrc::TokenExpired));

  return 0;
}

Expiration verification example (uses exception):

#include <cassert>
#include <iostream>
#include "jwt/jwt.hpp"

int main() {
  using namespace jwt::params;

  jwt::jwt_object obj{algorithm("HS256"), secret("secret")};

  obj.add_claim("iss", "arun.muralidharan")
     .add_claim("exp", std::chrono::system_clock::now() - std::chrono::seconds{1})
     ;

  auto enc_str = obj.signature();

  try {
    auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), secret("secret"), verify(true));
  } catch (const jwt::TokenExpiredError& e) {
    //Handle Token expired exception here
    //...
  } catch (const jwt::SignatureFormatError& e) {
    //Handle invalid signature format error
    //...
  } catch (const jwt::DecodeError& e) {
    //Handle all kinds of other decode errors
    //...
  } catch (const jwt::VerificationError& e) {
    // Handle the base verification error.
    //NOTE: There are other derived types of verification errors
    // which will be discussed in next topic.
  } catch (...) {
    std::cerr << "Caught unknown exception\n";
  }

  return 0;
}

Invalid issuer test(uses error_code):

(jwt::VerificationErrc::InvalidIssuer)); return 0; } ">
#include <cassert>
#include <iostream>
#include "jwt/jwt.hpp"

int main() {
  using namespace jwt::params;

  jwt::jwt_object obj{algorithm("HS256"), secret("secret"), payload({{"sub", "test"}})};

  std::error_code ec;
  auto enc_str = obj.signature(ec);
  assert (!ec);

  auto dec_obj = jwt::decode(enc_str, algorithms({"HS256"}), ec, secret("secret"), issuer("arun.muralidharan"));
  assert (ec);

  assert (ec.value() == static_cast<int>(jwt::VerificationErrc::InvalidIssuer));

  return 0;
}

Error Codes & Exceptions

The library as we saw earlier supports error reporting via both exceptions and error_code.

Error codes:

The error codes are divided into different categories:

  • Algorithm Errors

    Used for reporting errors at the time of encoding / signature creation.

    enum class AlgorithmErrc
    {
      SigningErr = 1,
      VerificationErr,
      KeyNotFoundErr,
      NoneAlgorithmUsed, // Not an actual error!
    };

    NOTE: NoneAlgorithmUsed will be set in the error_code, but it usually should not be treated as a hard error when NONE algorithm is used intentionally.

  • Decode Errors

    Used for reporting errors at the time of decoding. Different categories of decode errors are:

    enum class DecodeErrc
    {
      // No algorithms provided in decode API
      EmptyAlgoList = 1,
      // The JWT signature has incorrect format
      SignatureFormatError,
      // The JSON library failed to parse
      JsonParseError,
      // Algorithm field in header is missing
      AlgHeaderMiss,
      // Type field in header is missing
      TypHeaderMiss,
      // Unexpected type field value
      TypMismatch,
      // Found duplicate claims
      DuplClaims,
      // Key/Secret not passed as decode argument
      KeyNotPresent,
      // Key/secret passed as argument for NONE algorithm.
      // Not a hard error.
      KeyNotRequiredForNoneAlg,
    };
  • Verification errors

    Used for reporting verification errors when the verification falg is set to true in decode API. Different categories of decode errors are:

    enum class VerificationErrc
    {
      //Algorithms provided does not match with header
      InvalidAlgorithm = 1,
      //Token is expired at the time of decoding
      TokenExpired,
      //The issuer specified does not match with payload
      InvalidIssuer,
      //The subject specified does not match with payload
      InvalidSubject,
      //The field IAT is not present or is of invalid type
      InvalidIAT,
      //Checks for the existence of JTI
      //if validate_jti is passed in decode
      InvalidJTI,
      //The audience specified dowes not match with payload
      InvalidAudience,
      //Decoded before nbf time
      ImmatureSignature,
      //Signature match error
      InvalidSignature,
      // Invalid value type used for known claims
      TypeConversionError,
    };

Exceptions: There are exception types created for almost all the error codes above.

  • MemoryAllocationException

    Derived from std::bad_alloc. Thrown for memory allocation errors in OpenSSL C API.

  • SigningError

    Derived from std::runtime_error. Thrown for failures in OpenSSL APIs while signing.

  • DecodeError

    Derived from std::runtime_error. Base class for all decoding related exceptions.

    • SignatureFormatError

      Thrown if the format of the signature is not as expected.

    • KeyNotPresentError

      Thrown if key/secret is not passed in with the decode API if the algorithm used is something other than "none".

  • VerificationError

    Derived from std::runtime_error. Base class exception for all kinds of verification errors. Verification errors are thrown only when the verify decode parameter is set to true.

    • InvalidAlgorithmError
    • TokenExpiredError
    • InvalidIssuerError
    • InvalidAudienceError
    • InvalidSubjectError
    • InvalidIATError
    • InvalidJTIError
    • ImmatureSignatureError
    • InvalidSignatureError
    • TypeConversionError

    NOTE: See the error code section for explanation on above verification errors or checkout exceptions.hpp header for more details.

Additional Header Data

Generally the header consists only of type and algorithm fields. But there could be a need to add additional header fields. For example, to provide some kind of hint about what algorithm was used to sign the JWT. Checkout JOSE header section in RFC-7515.

The library provides APIs to do that as well.

{"exp"}); assert (ret); std::error_code ec; auto enc_str = obj.signature(); auto dec_obj = jwt::decode(enc_str, algorithms({"none"}), ec, verify(false)); // Should not be a hard error in general assert (ec.value() == static_cast (jwt::AlgorithmErrc::NoneAlgorithmUsed)); } ">
#include <cassert>
#include <iostream>
#include "jwt/jwt.hpp"

int main() {
  using namespace jwt::params;

  jwt::jwt_object obj{
      headers({
        {"alg", "none"},
        {"typ", "jwt"},
        }),
      payload({
        {"iss", "arun.muralidharan"},
        {"sub", "nsfw"},
        {"x-pld", "not my ex"}
      })
  };

  bool ret = obj.header().add_header("kid", 1234567);
  assert (ret);

  ret = obj.header().add_header("crit", std::array
    1>{
    "exp"});
  
    assert (ret);

  std::error_code ec;
  
    auto enc_str = obj.
    signature();

  
    auto dec_obj = 
    jwt::decode(enc_str, 
    algorithms({
    "none"}), ec, 
    verify(
    false));

  
    // Should not be a hard error in general
  
    assert (ec.
    value() == 
    static_cast<
    int>(jwt::AlgorithmErrc::NoneAlgorithmUsed));
}
   

Things for improvement

Many things! Encoding and decoding JWT is fairly a simple task and could be done in a single source file. I have tried my best to get the APIs and design correct in how much ever time I could give for this project. Still, there are quite a few places (or all the places :( ? ) where things are not correct or may not be the best approach.

With C++, it is pretty easy to go overboard and create something very difficult or something very straightforward (not worth to be a library). My intention was to make a sane library easier for end users to use while also making the life of someone reading the source have fairly good time debugging some issue.

Things one may have questions about

  • There is a string_view implementation. Why not use boost::string_ref ?

    Sorry, I love boost! But, do not want it to be part of dependency. If you use C++17 or greater std::string_view gets used instead and jwt::string_view implementation does not get included.

  • You are not using the stack allocator or the shart string anywhere. Why to include it then ?

    I will be using it in few places where I am sure I need not use std::string especially in the signing code.

  • Why the complete nlohmann JSON is part of your library ?

    Honestly did not know any better way. I know there are ways to use third party github repositories, but I do not know how to do that. Once I figure that out, I may move it out.

  • Am I bound to use nlohmann JSON ? Can I use some other JSON library ?

    As of now, ys. You cannot use any other JSON library unless you change the code. I would have liked to provide some adaptors for JSON interface. Perhaps in future, if required.

  • Error codes and exceptions....heh?

    Yeah, I often wonder if that was the right approach. I could have just stuck with error codes and be happy. But that was a good learning time for me.

  • Where to find more about the usage ?

    Checkout the tests. It has examples for all the algorithms which are supported.

  • Support for C++11 seems trivial based on the changes required. Why not support C+11 then ?

    Its 2018 now! If I ever start getting requests to have support for C++11, then I will surely consider it.

  • The Metaprogramming concept checks for Sequence and Mapping looks sad.

    Yeah I know. Just hacked something very basic.

License

MIT License

Copyright (c) 2017 Arun Muralidharan

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Comments
  • ES256/384 signature verification fails

    ES256/384 signature verification fails

    Starting from this test, I'm trying to get my stuff working. However, I failed at verifying the signature from the tests as a starting example. Something is wrong. I need ECC because it's more efficient than RSA. In this test that I got from the code:

    TEST (ESAlgo, ES384EncodingDecodingTest)
    {
      using namespace jwt::params;
    
      std::string key = read_from_file(EC384_PRIV_KEY);
      ASSERT_TRUE (key.length());
    
      jwt::jwt_object obj{algorithm("ES384"), secret(key)};
    
      obj.add_claim("iss", "arun.muralidharan")
         .add_claim("aud", "all")
         .add_claim("exp", 1513862371)
         ;
    
      auto enc_str = obj.signature();
    
      key = read_from_file(EC384_PUB_KEY);
      ASSERT_TRUE (key.length());
    
      auto dec_obj = jwt::decode(enc_str, algorithms({"es384"}), verify(false), secret(key));
    
      EXPECT_EQ (dec_obj.header().algo(), jwt::algorithm::ES384);
    
      std::cout << enc_str << std::endl;
    
    }
    

    I added that cout statement, then went to jwt.io, and it fails at verifying the signature. Something is wrong there.

    I also tried using my own key that I generated in OpenSSL using:

    CURVE=secp384r1
    openssl ecparam -name ${CURVE} -out curve.pem
    openssl ecparam -name ${CURVE} -genkey -noout -out privkey.pem
    openssl ec -in privkey.pem -pubout -out pubkey.pem
    

    But my key fails too. Also 256 bit fail the same.

    Unfortunately the library is not usable in this state. Can you please take a look and see why this is happening?

    opened by TheQuantumPhysicist 19
  • Why does the existence of a signature algorithm entail a required verification?

    Why does the existence of a signature algorithm entail a required verification?

    In my code, I have parts where I need to extract the data from a token without verifying it (and without the key being available). Basically because the verification was done before and the token was authorized.

    Now check out this part of the code:

    https://github.com/arun11299/cpp-jwt/blob/077e6f3f07ec113d2ae24384d1b10870c059d04d/include/jwt/impl/jwt.ipp#L698

    In line 698, the code gets the message from the user that a verification is not necessary, so that block is skipped. But then in line 709, this block completely ignores whether the user wants to verify, and simply checks the header and whether there's an algorithm associated with the header. This basically means that it's impossible to extract information from a token without a key. For me, I'm getting an error code DecodeErrc::KeyNotPresent, because there's no key associated with the object, although I'm not willing to verify.

    The fix I suggest is to put this block inside the other block in line 698. Only if the user is willing to verify, then the algorithm should be checked.

    The reason I haven't created a pull-request for this is that I'm not sure why this was done this way, and there's the possibility that there's something I'm misunderstanding here. So kindly explain whether my reasoning is correct.

    Best.

    opened by TheQuantumPhysicist 9
  • Visual Studio will not find

    Visual Studio will not find "jwt/jwt.hpp"

    I'm using VisualStudio 2019 Communitiy edition and I am trying to use cpp-jwt.

    I've tried building using the Visual studio cmake handling. Building returns no errors, but when trying to create my own application (console app) with a cpp file with:

    #include #include "jwt/jwt.hpp"

    int main() { return 0; }

    returns an error that jwt/jwt.hpp can not be found. Adding include libraries does not solve the problem.

    What can be the cause?

    I've also tried building it using (from a command prompt): cd cpp-jwt mkdir build cd build cmake .. This needed admin rights to install everything in: C:/Program Files(x86)/cpp-jwt/lib/cmake/cpp-jwt

    with identical results.

    opened by Ruuddenbekker 8
  • VS2015 compile fail

    VS2015 compile fail

    d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\string_view.hpp(352): warning C4003: not enough actual parameters for macro 'max' 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\string_view.hpp(353): warning C4003: not enough actual parameters for macro 'max' 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\string_view.hpp(354): warning C4003: not enough actual parameters for macro 'min' 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\string_view.hpp(355): warning C4003: not enough actual parameters for macro 'min' 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\base64.hpp(64): error C3249: illegal statement or sub-expression for 'constexpr' function 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\base64.hpp(158): error C3249: illegal statement or sub-expression for 'constexpr' function 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(223): error C3431: 'algorithm': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(248): error C3431: 'algorithm': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(252): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(253): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(254): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(255): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(256): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(257): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(258): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(259): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(260): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\algorithm.hpp(261): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(62): error C3431: 'type': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(66): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(67): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(69): warning C4297: 'jwt::str_to_type': function assumed not to throw an exception but does 1> d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(69): note: __declspec(nothrow), throw(), noexcept(true), or noexcept was specified on the function 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(79): error C3431: 'type': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(116): error C3431: 'registered_claims': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(300): error C3431: 'algorithm': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(300): error C3431: 'type': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(330): error C3431: 'algorithm': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(348): error C3431: 'algorithm': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(360): error C3431: 'type': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(378): error C3431: 'type': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(493): error C3431: 'algorithm': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(496): error C3431: 'type': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(422): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(444): error C3861: 'strcasecmp': identifier not found 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(606): error C3431: 'registered_claims': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(620): error C3431: 'registered_claims': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(635): error C3431: 'registered_claims': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(668): error C3431: 'registered_claims': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(692): error C3431: 'registered_claims': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(716): error C3431: 'registered_claims': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(741): error C3431: 'registered_claims': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(1018): error C3431: 'registered_claims': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(1035): error C3431: 'registered_claims': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\jwt.hpp(1057): error C3431: 'registered_claims': a scoped enumeration cannot be redeclared as an unscoped enumeration 1>d:\workspace\trd\curl-7.61.0\projects\windows\vc14\curl_test\jwt\impl\jwt.ipp(91): error C3861: 'strcasecmp': identifier not found

    opened by Clinkz24 8
  • Verify JWT token with Certificate

    Verify JWT token with Certificate

    Hello,

    is it possible to verify the JWT token with a certificate? I tried it with following code line:

    auto dec_obj = jwt::decode(token, jwt::params::algorithms({"rs256"}), jwt::params::aud(audience), jwt::params::secret(key), jwt::params::verify(true));

    but i get the following exception: verification failed

    What is wrong? How can i verify the signature with using a certificate

    opened by XM37 5
  • Unable to sign ES256 JWT

    Unable to sign ES256 JWT

    I've been attempting to use this library in one of our projects for the past day but I am unable to sign the JWT with the ES256 algorithm. We are using Openssl 1.0.2 and it is correctly linked into our project.

    We've followed your examples and test code:

    // kid and iss are strings defined by the 3rd party API
    jwt::jwt_object obj{
      algorithm("ES256"),
      headers({
        {"kid", kid},
      }),
      payload({
        {"iss", iss}
      }),
        secret(privateKey)
    };
    // iat and exp are calculated elsewhere, in milliseconds
    obj.add_claim("iat", iat)
      .add_claim("exp", exp);
    const string sig = obj.signature();
    

    I've managed to trace the issue to line 207 in algorithm.ipp:

      EVP_PKEY* pkey = PEM_read_bio_PrivateKey(
          bio_ptr.get(), nullptr, nullptr, nullptr);
    

    pkey is getting set to NULL, which eventually causes an error to be thrown.

    Our secret/private key is in the PEM format. From various sources online, I tried to add new lines to our PEM string, to simulate being read from a file, but that did not help.

    Any help you can provide would be very appreciated. Thanks!

    opened by jstarschuyler 5
  • Openssl make does not work

    Openssl make does not work

    This seems to be a big problem with a lot of other projects so I'm surprised it hasn't been reported here yet.

    I'm getting make errors like so...

    
    /usr/include/openssl/ec.h:1039:16: note: forward declaration of 'ECDSA_SIG {aka struct ECDSA_SIG_st}'
     typedef struct ECDSA_SIG_st ECDSA_SIG;
    

    Is there a fix for this?

    opened by tkaplan 5
  • Deprecated BIO_f_base64 from boringssl

    Deprecated BIO_f_base64 from boringssl

    opened by gramic 4
  • rs256 secret destructs after call

    rs256 secret destructs after call

    auto dec_obj = jwt::decode(enc_str, algorithms({ "rs256" }), secret(key));

    where key is: auto key = R"(-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoRRQG+ib30x09eWtDpL0 wWahA+hgjc0lWoQU4lwBFjXV2PfPImiAvwxOxNG34Mgnw3K9huBYLsrvOQAbMdBm E8lwz8DFKMWqHqoH3xSqDGhIYFobQDiVRkkecpberH5hqJauSD7PiwDBSQ/RCDIj b0SOmSTpZR97Ws4k1z9158VRf4BUbGjzVt4tUAz/y2cI5JsXQfcgAPB3voP8eunx GwZ/iM8evw3hUOw7+nuiPyts7HSkvV6GMwrXfOymY/w07mYxw/2LnKInfsWBtcRI DG+Nrsj237LgtBhK7TkzuVrguq//+bkDwwF3qTRXGAX9KrwY4huRxDRslMIg30Hq gwIDAQAB -----END PUBLIC KEY----- )";

    After, I call dec_obj.signature() or retrieve the secret and the object itself has the secret as set to empty.

    opened by armaansood 4
  • compile error with master

    compile error with master

    Hi ... trying to build lastest version of master, but getting compile error below. I am trying to build the first example found on the main page.

    However, I don't get this error with release v1.1.0

    /home/build/opt/gcc-8.2.0/bin/g++ -MMD -MP -Wall -O0 -g3 -ggdb  -std=c++17 -I/home/build/opt/cpp-jwt/cpp-jwt/include   -c example.cc
    example.cc: In function ‘int main()’:
    example.cc:9:86: error: no matching function for call to ‘jwt::jwt_object::jwt_object(<brace-enclosed initializer list>)’
       jwt::jwt_object obj{algorithm("HS256"), payload({{"some", "payload"}}), secret(key)};
                                                                                          ^
    In file included from example.cc:2:
    /home/build/opt/cpp-jwt/cpp-jwt/include/jwt/jwt.hpp:892:3: note: candidate: ‘template<class First, class ... Rest> jwt::jwt_object::jwt_object(std::enable_if_t<jwt::detail::meta::is_parameter_concept<First>::value, First>&&, Rest&& ...)’
       jwt_object(std::enable_if_t<detail::meta::is_parameter_concept<First>::value, First>&& first, Rest&&... rest);
       ^~~~~~~~~~
    /home/build/opt/cpp-jwt/cpp-jwt/include/jwt/jwt.hpp:892:3: note:   template argument deduction/substitution failed:
    example.cc:9:86: note:   couldn't deduce template parameter ‘First’
       jwt::jwt_object obj{algorithm("HS256"), payload({{"some", "payload"}}), secret(key)};
                                                                                          ^
    In file included from example.cc:2:
    /home/build/opt/cpp-jwt/cpp-jwt/include/jwt/jwt.hpp:870:3: note: candidate: ‘jwt::jwt_object::jwt_object()’
       jwt_object() = default;
       ^~~~~~~~~~
    /home/build/opt/cpp-jwt/cpp-jwt/include/jwt/jwt.hpp:870:3: note:   candidate expects 0 arguments, 3 provided
    /home/build/opt/cpp-jwt/cpp-jwt/include/jwt/jwt.hpp:864:7: note: candidate: ‘jwt::jwt_object::jwt_object(const jwt::jwt_object&)’
     class jwt_object
           ^~~~~~~~~~
    /home/build/opt/cpp-jwt/cpp-jwt/include/jwt/jwt.hpp:864:7: note:   candidate expects 1 argument, 3 provided
    /home/build/opt/cpp-jwt/cpp-jwt/include/jwt/jwt.hpp:864:7: note: candidate: ‘jwt::jwt_object::jwt_object(jwt::jwt_object&&)’
    /home/build/opt/cpp-jwt/cpp-jwt/include/jwt/jwt.hpp:864:7: note:   candidate expects 1 argument, 3 provided
    makefile:23: recipe for target 'example.o' failed
    
    opened by darrenjs 4
  • Move semantics

    Move semantics

    It would be nice if jwt_object supported move semantics:

    jwt_object(jwt_object&&);
    jwt_object& operator=(jwt_object&&);
    

    If this is acceptable, I can provide a PR.

    opened by mhfrantz 4
  • Not able to call `payload()` with a string

    Not able to call `payload()` with a string

    I'm currently trying to use jwt::params::payload() in making a jwt_object, but my "payload" is a string (json string). I'm not sure how to get it into payload().

    opened by TennisBowling 0
  • Allow jwt::params::algorithms with enum values

    Allow jwt::params::algorithms with enum values

    Currently needed:

    const auto obj = jwt::decode(enc_str, jwt::params::algorithms({jwt::alg_to_str(jwt::algorithm::HS256), jwt::alg_to_str(jwt::algorithm::HS512)}), jwt::params::secret(key));
    

    Expected:

    const auto obj = jwt::decode(enc_str, jwt::params::algorithms({jwt::algorithm::HS256, jwt::algorithm::HS512}), jwt::params::secret(key));
    
    opened by GeneratedNickname 0
  • Empty signature part triggers assert

    Empty signature part triggers assert

    jwt_object::three_parts tries to read part three with negative length. Expected: Some kind of invalid_format error.

    Reproduction:

    jwt::decode("eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJtdl9jbGFpbSI6WyJmaXJzdCIsInNlY29uZCJdfQ.", jwt::params::algorithms({alg_to_str(jwt::algorithm::NONE)}), jwt::params::verify(false));
    
    opened by GeneratedNickname 0
  • How do I include your library?

    How do I include your library?

    Hello, I built the code:

    cd cpp-jwt
    mkdir build
    cd build
    cmake ..
    

    and then opened cpp-jwt.sln and built ALL_BUILD project in vs studio project. But I did not get any library files as an output. What did I do wrong?

    How to include your project into my project?

    opened by yateam 1
Releases(v1.4)
  • v1.4(Mar 2, 2021)

  • v1.3(Jun 13, 2020)

    There has been few issues reported for the use of BIO_f_base64 which has been deprecated by boringssl. Removed that dependency with the JWT base64 implementation.

    Source code(tar.gz)
    Source code(zip)
  • v1.2(Feb 24, 2020)

    Thanks to @gocarlos effort, we have now (Copied shamelessly from the PR request):

    installation of header files make tests and examples optional clean up compiler flags -> make it possible compile on mscv make vendored json version optional -> important for software clearing in some corporations added conan support and build instructions

    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Nov 21, 2018)

    1b105f47727099bb577857b436460ea877c745c6 introduced compilation regression with C++14/17 flags. Fixed it.

    See https://github.com/arun11299/cpp-jwt/issues/37

    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(May 31, 2018)

    Fixed compiler warnings with pedantic mode enabled. Thanks to Samer Afach. Added ES256/384 verification test. Fix a major error in error_code category checking implementations. Thanks to Samer Afach. Setting verify to false in decode will not do signature verification, This could be a breaking change.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.2(May 2, 2018)

    • Thanks to issues raised by @sarbjit (Issue #11, #12, #13), VS2017 is also supported now.
    • Fixed compilation of internal tests (Issue #9 ).
    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Apr 7, 2018)

    See https://github.com/arun11299/cpp-jwt/issues/5 for more details. Some structures were made private and some APIs were deprecated with OpenSSL 1.1.x version

    Source code(tar.gz)
    Source code(zip)
  • v1.0(Mar 31, 2018)

Owner
Arun Muralidharan
Arun Muralidharan
https://github.com/json-c/json-c is the official code repository for json-c. See the wiki for release tarballs for download. API docs at http://json-c.github.io/json-c/

\mainpage json-c Overview and Build Status Building on Unix Prerequisites Build commands CMake options Testing Building with vcpkg Linking to libjson-

json-c 2.6k Dec 31, 2022
json-cpp is a C++11 JSON serialization library.

JSON parser and generator for C++ Version 0.1 alpha json-cpp is a C++11 JSON serialization library. Example #include <json-cpp.hpp> struct Foo {

Anatoly Scheglov 7 Oct 30, 2022
This is a JSON C++ library. It can write and read JSON files with ease and speed.

Json Box JSON (JavaScript Object Notation) is a lightweight data-interchange format. Json Box is a C++ library used to read and write JSON with ease a

Anhero inc. 110 Dec 4, 2022
A convenience C++ wrapper library for JSON-Glib providing friendly syntactic sugar for parsing JSON

This library is a wrapper for the json-glib library that aims to provide the user with a trivial alternative API to the API provided by the base json-

Rob J Meijer 17 Oct 19, 2022
json-build is a zero-allocation JSON serializer compatible with C89

json-build is a zero-allocation JSON serializer compatible with C89. It is inspired by jsmn, a minimalistic JSON tokenizer.

Lucas Müller 31 Nov 16, 2022
An easy-to-use and competitively fast JSON parsing library for C++17, forked from Bitcoin Cash Node's own UniValue library.

UniValue JSON Library for C++17 (and above) An easy-to-use and competitively fast JSON parsing library for C++17, forked from Bitcoin Cash Node's own

Calin Culianu 24 Sep 21, 2022
A Haskell library for fast decoding of JSON documents using the simdjson C++ library

hermes A Haskell interface over the simdjson C++ library for decoding JSON documents. Hermes, messenger of the gods, was the maternal great-grandfathe

Josh Miller 36 Dec 5, 2022
C library for encoding, decoding and manipulating JSON data

Jansson README Jansson is a C library for encoding, decoding and manipulating JSON data. Its main features and design principles are: Simple and intui

Petri Lehtinen 2.7k Dec 31, 2022
A very sane (header only) C++14 JSON library

JeayeSON - a very sane C++14 JSON library JeayeSON was designed out of frustration that there aren't many template-based approaches to handling JSON i

Jeaye Wilkerson 128 Nov 28, 2022
A C++ library for interacting with JSON.

JsonCpp JSON is a lightweight data-interchange format. It can represent numbers, strings, ordered sequences of values, and collections of name/value p

null 6.9k Dec 31, 2022
A tiny JSON library for C++11.

json11 json11 is a tiny JSON library for C++11, providing JSON parsing and serialization. The core object provided by the library is json11::Json. A J

Dropbox 2.4k Dec 31, 2022
A killer modern C++ library for interacting with JSON.

JSON Voorhees Yet another JSON library for C++. This one touts new C++11 features for developer-friendliness, an extremely slow-speed parser and no de

Travis Gockel 124 Oct 26, 2022
a JSON parser and printer library in C. easy to integrate with any model.

libjson - simple and efficient json parser and printer in C Introduction libjson is a simple library without any dependancies to parse and pretty prin

Vincent Hanquez 260 Nov 21, 2022
Lightweight JSON library written in C.

About Parson is a lightweight json library written in C. Features Full JSON support Lightweight (only 2 files) Simple API Addressing json values with

Krzysztof Gabis 1.2k Dec 31, 2022
QJson is a qt-based library that maps JSON data to QVariant objects.

QJson JSON (JavaScript Object Notation) is a lightweight data-interchange format. It can represents integer, real number, string, an ordered sequence

Flavio Castelli 273 Dec 2, 2022
C++ header-only JSON library

Welcome to taoJSON taoJSON is a C++ header-only JSON library that provides a generic Value Class, uses Type Traits to interoperate with C++ types, use

The Art of C++ 499 Dec 27, 2022
A fast streaming JSON parsing library in C.

********************************************************************** This is YAJL 2. For the legacy version of YAJL see https

Lloyd Hilaiel 2.1k Jan 1, 2023
Very fast Python JSON parsing library

cysimdjson Fast JSON parsing library for Python, 7-12 times faster than standard Python JSON parser. It is Python bindings for the simdjson using Cyth

TeskaLabs 234 Jan 8, 2023
Immediate Mode JSON Serialization Library in C

JIM Immediate Mode JSON Serialization Library in C. Similar to imgui but for generating JSON. Example example.c: #include <stdio.h> #define JIM_IMPLE

Tsoding 33 Dec 13, 2022