Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decode JWT Token (Boost) #248

Closed
hanusek opened this issue Sep 23, 2022 · 7 comments · Fixed by #251
Closed

Decode JWT Token (Boost) #248

hanusek opened this issue Sep 23, 2022 · 7 comments · Fixed by #251
Assignees
Labels

Comments

@hanusek
Copy link

hanusek commented Sep 23, 2022

What's your question?

How to decode JWT token (HS256) with Boost traits?

Additional Context

Hello.
I have a token generated by https://jwt.io but I have a problem - Exception: Invalid input: not within alphabet.
How to fix it?
Encoded:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Header:

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

VERIFY SIGNATURE:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload), 
your-256-bit-secret
)

Code:

#include <boost/json/src.hpp>
#include <jwt-cpp/traits/boost-json/traits.h>

using traits = jwt::traits::boost_json;
using claim = jwt::basic_claim<traits>;

void jwt_token(const std::string& token)
{
    const auto decoded = jwt::decode<traits>(token);
    std::cout << "decoded token: " << decoded.get_algorithm() << std::endl;
}

Error log:

token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Exception: Invalid input: not within alphabet
@prince-chrismc
Copy link
Collaborator

Hmm I am not able to repoduce 🤔

https://github.com/prince-chrismc/jwt-cpp/actions/runs/3116500580/jobs/5054387893#step:11:1536

Want to try my code?

@hanusek
Copy link
Author

hanusek commented Sep 26, 2022

I solved it. The problem existed because my string (text) have white characters.

void jwt_token(const std::string& text)
{
    std::cout << "text:\t\t'" << text <<"'" << std::endl;

    auto clean_text = text;

    clean_text.erase(std::remove_if(clean_text.begin(), clean_text.end(), [](unsigned char c){return !std::isgraph(c);}), clean_text.end());

    const auto decoded = jwt::decode<traits>(clean_text);
    std::cout << "buggy alg: " << decoded.get_algorithm() << std::endl;

    const auto name = decoded.get_payload_claim("name");
    std::cout << "name: " << name << std::endl;

    const auto iat = decoded.get_payload_claim("iat");
    std::cout << "iat: " << name << std::endl;

    const auto sub = decoded.get_payload_claim("sub");
    std::cout << "sub: " << sub << std::endl;

    jwt::verify<traits>().allow_algorithm(jwt::algorithm::hs256{"your-256-bit-secret"}).verify(decoded);
  }

@Thalhammer
Copy link
Owner

Glad to hear you solved your issue. jwt-cpp expects a clean token as a parameter, not sure if we should check for preceding/trailing whitespace and remove it. What do you think @prince-chrismc ?

@hanusek
Copy link
Author

hanusek commented Sep 26, 2022

@Thalhammer @prince-chrismc This problem was very difficult to detect. Because prints were the same. But strings weren't been the same. My string has a lot of white characters inside (Not only on end and begin).

I have a new problem with get_header_claims() and get_payload_claims().

I would like print all claims.

    const auto decoded = jwt::decode<traits>(clean_text);

    for (auto& e : decoded.get_header_claims()) {
        std::cout << e.first << " = " << e.second<< std::endl;
    }

I can't find test/example for this
https://github.com/Thalhammer/jwt-cpp/blob/5c9787ebcadd122ae5c41248a0ac416f85eb846d/tests/traits/BoostJsonTest.cpp

Error:

/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h: In instantiation of ‘std::unordered_map<typename json_traits::string_type, jwt::basic_claim<json_traits> > jwt::details::map_of_claims<json_traits>::get_claims() const [with json_traits = jwt::traits::boost_json; typename json_traits::string_type = std::__cxx11::basic_string<char>]’:
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2640:41:   required from ‘std::unordered_map<typename json_traits::string_type, jwt::basic_claim<json_traits> > jwt::decoded_jwt<json_traits>::get_header_claims() const [with json_traits = jwt::traits::boost_json; typename json_traits::string_type = std::__cxx11::basic_string<char>]’
/home/mhanusek/work/VersionControl/Cybersec/temp/auth/client/src/Client.cpp:38:45:   required from here
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2318:135: error: static assertion failed: currently there is a limitation on the internal implemantation of the `object_type` to have an `std::pair` like `value_type`
 2318 |                                                                                                   typename json_traits::object_type>::supports_claims_transform,
      |                                                                                                                                       ^~~~~~~~~~~~~~~~~~~~~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2318:135: note: ‘jwt::details::is_valid_json_object<boost::json::standalone::value, std::__cxx11::basic_string<char>, boost::json::standalone::object>::supports_claims_transform’ evaluates to false
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2325:94: error: ‘const value_type’ {aka ‘const class boost::json::standalone::key_value_pair’} has no member named ‘first’
 2325 |                                                                    return std::make_pair(val.first, basic_claim_t{val.second});
      |                                                                                          ~~~~^~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2325:119: error: ‘const value_type’ {aka ‘const class boost::json::standalone::key_value_pair’} has no member named ‘second’
 2325 |                                                                    return std::make_pair(val.first, basic_claim_t{val.second});
      |                                                                                                                   ~~~~^~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2325:89: error: no matching function for call to ‘jwt::basic_claim<jwt::traits::boost_json>::basic_claim(<brace-enclosed initializer list>)’
 2325 |                                                                    return std::make_pair(val.first, basic_claim_t{val.second});
      |                                                                           ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2157:17: note: candidate: ‘template<class Iterator> jwt::basic_claim<json_traits>::basic_claim(Iterator, Iterator) [with Iterator = Iterator; json_traits = jwt::traits::boost_json]’
 2157 |                 basic_claim(Iterator begin, Iterator end) : val(typename json_traits::array_type(begin, end)) {}
      |                 ^~~~~~~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2157:17: note:   template argument deduction/substitution failed:
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2155:36: note: candidate: ‘jwt::basic_claim<json_traits>::basic_claim(const set_t&) [with json_traits = jwt::traits::boost_json; jwt::basic_claim<json_traits>::set_t = std::set<std::__cxx11::basic_string<char> >]’
 2155 |                 JWT_CLAIM_EXPLICIT basic_claim(const set_t& s) : val(typename json_traits::array_type(s.begin(), s.end())) {}
      |                                    ^~~~~~~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2155:36: note:   conversion of argument 1 would be ill-formed:
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2154:36: note: candidate: ‘jwt::basic_claim<json_traits>::basic_claim(typename json_traits::value_type) [with json_traits = jwt::traits::boost_json; typename json_traits::value_type = boost::json::standalone::value]’
 2154 |                 JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::value_type v) : val(std::move(v)) {}
      |                                    ^~~~~~~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2154:36: note:   conversion of argument 1 would be ill-formed:
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2153:36: note: candidate: ‘jwt::basic_claim<json_traits>::basic_claim(typename json_traits::array_type) [with json_traits = jwt::traits::boost_json; typename json_traits::array_type = boost::json::standalone::array]’
 2153 |                 JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::array_type a) : val(std::move(a)) {}
      |                                    ^~~~~~~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2153:36: note:   conversion of argument 1 would be ill-formed:
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2151:36: note: candidate: ‘jwt::basic_claim<json_traits>::basic_claim(const date&) [with json_traits = jwt::traits::boost_json; jwt::date = std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long int, std::ratio<1, 1000000000> > >]’
 2151 |                 JWT_CLAIM_EXPLICIT basic_claim(const date& d)
      |                                    ^~~~~~~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2151:36: note:   conversion of argument 1 would be ill-formed:
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2150:36: note: candidate: ‘jwt::basic_claim<json_traits>::basic_claim(typename json_traits::string_type) [with json_traits = jwt::traits::boost_json; typename json_traits::string_type = std::__cxx11::basic_string<char>]’
 2150 |                 JWT_CLAIM_EXPLICIT basic_claim(typename json_traits::string_type s) : val(std::move(s)) {}
      |                                    ^~~~~~~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2150:36: note:   conversion of argument 1 would be ill-formed:
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2145:17: note: candidate: ‘jwt::basic_claim<json_traits>::basic_claim(jwt::basic_claim<json_traits>&&) [with json_traits = jwt::traits::boost_json]’
 2145 |                 basic_claim(basic_claim&&) = default;
      |                 ^~~~~~~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2145:17: note:   conversion of argument 1 would be ill-formed:
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2144:17: note: candidate: ‘jwt::basic_claim<json_traits>::basic_claim(const jwt::basic_claim<json_traits>&) [with json_traits = jwt::traits::boost_json]’
 2144 |                 basic_claim(const basic_claim&) = default;
      |                 ^~~~~~~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2144:17: note:   conversion of argument 1 would be ill-formed:
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2143:17: note: candidate: ‘jwt::basic_claim<json_traits>::basic_claim() [with json_traits = jwt::traits::boost_json]’
 2143 |                 basic_claim() = default;
      |                 ^~~~~~~~~~~
/home/mhanusek/.conan/data/jwt-cpp/0.6.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/jwt-cpp/jwt.h:2143:17: note:   candidate expects 0 arguments, 1 provided

Can you help me?

@hanusek hanusek changed the title Decode JWT Token Decode JWT Token (Boost) Sep 26, 2022
@prince-chrismc
Copy link
Collaborator

The boost library has a funky implementation which the library does not support for the "key value pairs"...

You should be able to covert the object maps to JSON as a workaround.

typename json_traits::object_type claims;

Sadly I am traveling so I can not write any code to show that

@prince-chrismc
Copy link
Collaborator

What do you think @prince-chrismc ?

I think the head of the problem is the error message. When it said it should say "the character at Index 14 ' ' is not apart of the alphabet" usually you need to stop through the code which is less fun

@prince-chrismc
Copy link
Collaborator

I opened a PR to that it will be easier to print the claims for Boost. #251

I would also like to break a separate issue for having more feedback in the errors of base64 decoding, is that good for everyone?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants