Skip to content

Commit

Permalink
Add set_expires_in and set_issued_now methods (#322)
Browse files Browse the repository at this point in the history
* Add set_expires_in and set_issued_now methods

* Add a Clock type parameter for builder

* set_expires_in method sets exp from the current moment

* Update default traits with the new builder interface

* Add VerifyTokenExpirationInValid for all traits

* Use the new methods in examples

* Add create method to specify the clock type

* Use JWT_CLAIM_EXPLICIT for explicit constructors

* Fix builder factory method in mustache file

* fixup whitespace

* default template was missing a few args

* fix whitespace

* linter

---------

Co-authored-by: Chris Mc <[email protected]>
  • Loading branch information
bugdea1er and prince-chrismc authored Dec 30, 2023
1 parent 953aab6 commit a1ac7a0
Show file tree
Hide file tree
Showing 17 changed files with 143 additions and 28 deletions.
6 changes: 3 additions & 3 deletions docs/faqs.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ Here is a simple example of creating a token that will expire in one hour:

```cpp
auto token = jwt::create()
.set_issued_at(std::chrono::system_clock::now())
.set_expires_at(std::chrono::system_clock::now() + std::chrono::seconds{3600})
.sign(jwt::algorithm::hs256{"secret"});
.set_issued_now()
.set_expires_in(std::chrono::seconds{3600})
.sign(jwt::algorithm::hs256{"secret"});
```
### Can you add claims to a signed token?
Expand Down
4 changes: 2 additions & 2 deletions docs/signing.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Then everything else is the same, just pass in your implementation such as:
```cpp
auto token = jwt::create()
.set_id("custom-algo-example")
.set_issued_at(std::chrono::system_clock::now())
.set_expires_at(std::chrono::system_clock::now() + std::chrono::seconds{36000})
.set_issued_now()
.set_expires_in(std::chrono::seconds{36000})
.set_payload_claim("sample", jwt::claim(std::string{"test"}))
.sign(your_algorithm{/* what ever you want */});
```
4 changes: 2 additions & 2 deletions example/es256k.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ K9EDZi0mZ7VUeeNKq476CU5X940yusahgneePQrDMF2nWFEtBCOiXQ==
.set_issuer("auth0")
.set_type("JWT")
.set_id("es256k-create-example")
.set_issued_at(std::chrono::system_clock::now())
.set_expires_at(std::chrono::system_clock::now() + std::chrono::seconds{36000})
.set_issued_now()
.set_expires_in(std::chrono::seconds{36000})
.set_payload_claim("sample", jwt::claim(std::string{"test"}))
.sign(jwt::algorithm::es256k(es256k_pub_key, es256k_priv_key, "", ""));

Expand Down
4 changes: 2 additions & 2 deletions example/partial-claim-verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ rK0/Ikt5ybqUzKCMJZg2VKGTxg==
.set_issuer("auth0")
.set_type("JWT")
.set_id("rsa-create-example")
.set_issued_at(std::chrono::system_clock::now())
.set_expires_at(std::chrono::system_clock::now() + std::chrono::seconds{36000})
.set_issued_now()
.set_expires_in(std::chrono::seconds{36000})
.set_payload_claim("resource-access", role_claim)
.sign(jwt::algorithm::rs256("", rsa_priv_key, "", ""));

Expand Down
4 changes: 2 additions & 2 deletions example/rsa-create.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ rK0/Ikt5ybqUzKCMJZg2VKGTxg==
.set_issuer("auth0")
.set_type("JWT")
.set_id("rsa-create-example")
.set_issued_at(std::chrono::system_clock::now())
.set_expires_at(std::chrono::system_clock::now() + std::chrono::seconds{36000})
.set_issued_now()
.set_expires_in(std::chrono::seconds{36000})
.set_payload_claim("sample", jwt::claim(std::string{"test"}))
.sign(jwt::algorithm::rs256("", rsa_priv_key, "", ""));

Expand Down
39 changes: 35 additions & 4 deletions include/jwt-cpp/jwt.h
Original file line number Diff line number Diff line change
Expand Up @@ -2819,13 +2819,20 @@ namespace jwt {
* Builder class to build and sign a new token
* Use jwt::create() to get an instance of this class.
*/
template<typename json_traits>
template<typename Clock, typename json_traits>
class builder {
typename json_traits::object_type header_claims;
typename json_traits::object_type payload_claims;

/// Instance of clock type
Clock clock;

public:
builder() = default;
/**
* Constructor for building a new builder instance
* \param c Clock instance
*/
JWT_CLAIM_EXPLICIT builder(Clock c) : clock(c) {}
/**
* Set a header claim.
* \param id Name of the claim
Expand Down Expand Up @@ -2940,6 +2947,15 @@ namespace jwt {
* \return *this to allow for method chaining
*/
builder& set_expires_at(const date& d) { return set_payload_claim("exp", basic_claim<json_traits>(d)); }
/**
* Set expires at claim to @p d from the current moment
* \param d token expiration timeout
* \return *this to allow for method chaining
*/
template<class Rep>
builder& set_expires_in(const std::chrono::duration<Rep>& d) {
return set_payload_claim("exp", basic_claim<json_traits>(clock.now() + d));
}
/**
* Set not before claim
* \param d First valid time
Expand All @@ -2952,6 +2968,11 @@ namespace jwt {
* \return *this to allow for method chaining
*/
builder& set_issued_at(const date& d) { return set_payload_claim("iat", basic_claim<json_traits>(d)); }
/**
* Set issued at claim to the current moment
* \return *this to allow for method chaining
*/
builder& set_issued_now() { return set_issued_at(clock.now()); }
/**
* Set id claim
* \param str ID to set
Expand Down Expand Up @@ -3766,6 +3787,16 @@ namespace jwt {
return verifier<Clock, json_traits>(c);
}

/**
* Create a builder using the given clock
* \param c Clock instance to use
* \return builder instance
*/
template<typename Clock, typename json_traits>
builder<Clock, json_traits> create(Clock c) {
return builder<Clock, json_traits>(c);
}

/**
* Default clock class using std::chrono::system_clock as a backend.
*/
Expand All @@ -3787,8 +3818,8 @@ namespace jwt {
* Return a builder instance to create a new token
*/
template<typename json_traits>
builder<json_traits> create() {
return builder<json_traits>();
builder<default_clock, json_traits> create(default_clock c = {}) {
return builder<default_clock, json_traits>(c);
}

/**
Expand Down
7 changes: 5 additions & 2 deletions include/jwt-cpp/traits/boost-json/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ namespace jwt {
}

/**
* Return a builder instance to create a new token
* Create a builder using the default clock
* \return builder instance to create a new token
*/
inline builder<traits::boost_json> create() { return builder<traits::boost_json>(); }
inline builder<default_clock, traits::boost_json> create() {
return builder<default_clock, traits::boost_json>(default_clock{});
}

#ifndef JWT_DISABLE_BASE64
/**
Expand Down
7 changes: 5 additions & 2 deletions include/jwt-cpp/traits/danielaparker-jsoncons/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ namespace jwt {
}

/**
* Return a builder instance to create a new token
* Create a builder using the default clock
* \return builder instance to create a new token
*/
inline builder<traits::danielaparker_jsoncons> create() { return builder<traits::danielaparker_jsoncons>(); }
inline builder<default_clock, traits::danielaparker_jsoncons> create() {
return builder<default_clock, traits::danielaparker_jsoncons>(default_clock{});
}

#ifndef JWT_DISABLE_BASE64
/**
Expand Down
7 changes: 5 additions & 2 deletions include/jwt-cpp/traits/defaults.h.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ namespace jwt {
}

/**
* Return a builder instance to create a new token
* Create a builder using the default clock
* \return builder instance to create a new token
*/
inline builder<traits::{{traits_name}}> create() { return builder<traits::{{traits_name}}>(); }
inline builder<default_clock, traits::{{traits_name}}> create() {
return builder<default_clock, traits::{{traits_name}}>(default_clock{});
}

#ifndef JWT_DISABLE_BASE64
/**
Expand Down
7 changes: 5 additions & 2 deletions include/jwt-cpp/traits/kazuho-picojson/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ namespace jwt {
}

/**
* Return a builder instance to create a new token
* Create a builder using the default clock
* \return builder instance to create a new token
*/
inline builder<traits::kazuho_picojson> create() { return builder<traits::kazuho_picojson>(); }
inline builder<default_clock, traits::kazuho_picojson> create() {
return builder<default_clock, traits::kazuho_picojson>(default_clock{});
}

#ifndef JWT_DISABLE_BASE64
/**
Expand Down
7 changes: 5 additions & 2 deletions include/jwt-cpp/traits/nlohmann-json/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ namespace jwt {
}

/**
* Return a builder instance to create a new token
* Create a builder using the default clock
* \return builder instance to create a new token
*/
inline builder<traits::nlohmann_json> create() { return builder<traits::nlohmann_json>(); }
inline builder<default_clock, traits::nlohmann_json> create() {
return builder<default_clock, traits::nlohmann_json>(default_clock{});
}

#ifndef JWT_DISABLE_BASE64
/**
Expand Down
7 changes: 4 additions & 3 deletions include/jwt-cpp/traits/open-source-parsers-jsoncpp/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ namespace jwt {
}

/**
* Return a builder instance to create a new token
* Create a builder using the default clock
* \return builder instance to create a new token
*/
inline builder<traits::open_source_parsers_jsoncpp> create() {
return builder<traits::open_source_parsers_jsoncpp>();
inline builder<default_clock, traits::open_source_parsers_jsoncpp> create() {
return builder<default_clock, traits::open_source_parsers_jsoncpp>(default_clock{});
}

#ifndef JWT_DISABLE_BASE64
Expand Down
13 changes: 13 additions & 0 deletions tests/traits/BoostJsonTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,19 @@ TEST(BoostJsonTest, VerifyTokenExpirationValid) {
verify.verify(decoded_token);
}

TEST(BoostJsonTest, VerifyTokenExpirationInValid) {
const auto token = jwt::create<jwt::traits::boost_json>()
.set_issuer("auth0")
.set_issued_now()
.set_expires_in(std::chrono::seconds{3600})
.sign(jwt::algorithm::hs256{"secret"});

const auto decoded_token = jwt::decode<jwt::traits::boost_json>(token);
const auto verify =
jwt::verify<jwt::traits::boost_json>().allow_algorithm(jwt::algorithm::hs256{"secret"}).with_issuer("auth0");
verify.verify(decoded_token);
}

TEST(BoostJsonTest, VerifyTokenExpired) {
const auto token = jwt::create<jwt::traits::boost_json>()
.set_issuer("auth0")
Expand Down
14 changes: 14 additions & 0 deletions tests/traits/JsonconsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ TEST(JsonconsTest, VerifyTokenExpirationValid) {
verify.verify(decoded_token);
}

TEST(JsonconsTest, VerifyTokenExpirationInValid) {
const auto token = jwt::create<jwt::traits::danielaparker_jsoncons>()
.set_issuer("auth0")
.set_issued_now()
.set_expires_in(std::chrono::seconds{3600})
.sign(jwt::algorithm::hs256{"secret"});

const auto decoded_token = jwt::decode<jwt::traits::danielaparker_jsoncons>(token);
const auto verify = jwt::verify<jwt::traits::danielaparker_jsoncons>()
.allow_algorithm(jwt::algorithm::hs256{"secret"})
.with_issuer("auth0");
verify.verify(decoded_token);
}

TEST(JsonconsTest, VerifyTokenExpired) {
const auto token = jwt::create<jwt::traits::danielaparker_jsoncons>()
.set_issuer("auth0")
Expand Down
13 changes: 13 additions & 0 deletions tests/traits/NlohmannTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,19 @@ TEST(NlohmannTest, VerifyTokenExpirationValid) {
verify.verify(decoded_token);
}

TEST(NlohmannTest, VerifyTokenExpirationInValid) {
const auto token = jwt::create<jwt::traits::nlohmann_json>()
.set_issuer("auth0")
.set_issued_now()
.set_expires_in(std::chrono::seconds{3600})
.sign(jwt::algorithm::hs256{"secret"});

const auto decoded_token = jwt::decode<jwt::traits::nlohmann_json>(token);
const auto verify =
jwt::verify<jwt::traits::nlohmann_json>().allow_algorithm(jwt::algorithm::hs256{"secret"}).with_issuer("auth0");
verify.verify(decoded_token);
}

TEST(NlohmannTest, VerifyTokenExpired) {
const auto token = jwt::create<jwt::traits::nlohmann_json>()
.set_issuer("auth0")
Expand Down
14 changes: 14 additions & 0 deletions tests/traits/OspJsoncppTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ TEST(OspJsoncppTest, VerifyTokenExpirationValid) {
verify.verify(decoded_token);
}

TEST(OspJsoncppTest, VerifyTokenExpirationInValid) {
const auto token = jwt::create<jwt::traits::open_source_parsers_jsoncpp>()
.set_issuer("auth0")
.set_issued_now()
.set_expires_in(std::chrono::seconds{3600})
.sign(jwt::algorithm::hs256{"secret"});

const auto decoded_token = jwt::decode<jwt::traits::open_source_parsers_jsoncpp>(token);
const auto verify = jwt::verify<jwt::traits::open_source_parsers_jsoncpp>()
.allow_algorithm(jwt::algorithm::hs256{"secret"})
.with_issuer("auth0");
verify.verify(decoded_token);
}

TEST(OspJsoncppTest, VerifyTokenExpired) {
const auto token = jwt::create<jwt::traits::open_source_parsers_jsoncpp>()
.set_issuer("auth0")
Expand Down
14 changes: 14 additions & 0 deletions tests/traits/TraitsTest.cpp.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ TEST({{test_suite_name}}, VerifyTokenExpirationValid) {
verify.verify(decoded_token);
}

TEST({{test_suite_name}}, VerifyTokenExpirationInValid) {
const auto token = jwt::create<jwt::traits::{{traits_name}}>()
.set_issuer("auth0")
.set_issued_now()
.set_expires_in(std::chrono::seconds{3600})
.sign(jwt::algorithm::hs256{"secret"});

const auto decoded_token = jwt::decode<jwt::traits::{{traits_name}}>(token);
const auto verify = jwt::verify<jwt::traits::{{traits_name}}>()
.allow_algorithm(jwt::algorithm::hs256{"secret"})
.with_issuer("auth0");
verify.verify(decoded_token);
}

TEST({{test_suite_name}}, VerifyTokenExpired) {
const auto token = jwt::create<jwt::traits::{{traits_name}}>()
.set_issuer("auth0")
Expand Down

0 comments on commit a1ac7a0

Please sign in to comment.