Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ cc_test(
)

cc_test(
name = "verify_time_test",
name = "jwt_time_test",
timeout = "short",
srcs = [
"src/test_common.h",
"src/verify_time_test.cc",
"src/jwt_time_test.cc",
],
linkopts = [
"-lm",
Expand Down
16 changes: 16 additions & 0 deletions jwt_verify_lib/jwt.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
namespace google {
namespace jwt_verify {

// Clock skew defaults to one minute.
constexpr uint64_t kClockSkewInSecond = 60;

/**
* struct to hold a JWT data.
*/
Expand Down Expand Up @@ -89,6 +92,19 @@ struct Jwt {
* @return the status.
*/
Status parseFromString(const std::string& jwt);

/*
* Verify Jwt time constraint if specified
* esp: expiration time, nbf: not before time.
* `now`: is a pass in parameter.
* @return the status.
*/
Status verifyTimeConstraint(uint64_t now) const;

/*
* Same as above, but `now` is calculated by calling absl::Now.
*/
Status verifyTimeConstraint() const;
};

} // namespace jwt_verify
Expand Down
4 changes: 1 addition & 3 deletions jwt_verify_lib/status.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,7 @@ class WithStatus {
}
}

void resetStatus(Status status) {
status_ = status;
}
void resetStatus(Status status) { status_ = status; }

private:
// The internal status.
Expand Down
17 changes: 17 additions & 0 deletions src/jwt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "absl/container/flat_hash_set.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_split.h"
#include "absl/time/clock.h"
#include "google/protobuf/util/json_util.h"
#include "jwt_verify_lib/struct_utils.h"

Expand Down Expand Up @@ -136,5 +137,21 @@ Status Jwt::parseFromString(const std::string& jwt) {
return Status::Ok;
}

Status Jwt::verifyTimeConstraint(uint64_t now) const {
// Check Jwt is active (nbf).
if (now + kClockSkewInSecond < nbf_) {
return Status::JwtNotYetValid;
}
// Check JWT has not expired (exp).
if (exp_ && now > exp_ + kClockSkewInSecond) {
return Status::JwtExpired;
}
return Status::Ok;
}

Status Jwt::verifyTimeConstraint() const {
return verifyTimeConstraint(absl::ToUnixSeconds(absl::Now()));
}

} // namespace jwt_verify
} // namespace google
111 changes: 111 additions & 0 deletions src/jwt_time_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "gtest/gtest.h"
#include "jwt_verify_lib/jwt.h"
#include "src/test_common.h"

namespace google {
namespace jwt_verify {
namespace {

// Header: {"alg":"RS256","typ":"JWT"}
// Payload: {
// "iss":"https://example.com",
// "sub":"test@example.com",
// "exp": 1605052800,
// "nbf": 1605050800
// }
const std::string JwtText =
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9."
"ewogICJpc3MiOiAiaHR0cHM6Ly9leGFtcGxlLmNvbSIsCiAgInN1YiI6ICJ0ZXN0QGV4YW1wbG"
"UuY29tIiwKICAiZXhwIjogMTYwNTA1MjgwMCwKICAibmJmIjogMTYwNTA1MDgwMAp9."
"digk0Fr_IdcWgJNVyeVDw2dC1cQG6LsHwg5pIN93L4";

// The exp time for above Jwt
constexpr uint64_t ExpTime = 1605052800U;

// The nbf time for above Jwt.
constexpr uint64_t NbfTime = 1605050800U;

TEST(VerifyExpTest, BothNbfExp) {
Jwt jwt;
EXPECT_EQ(jwt.parseFromString(JwtText), Status::Ok);

// 10s before exp
EXPECT_EQ(jwt.verifyTimeConstraint(ExpTime + kClockSkewInSecond - 10),
Status::Ok);
// 10s after exp
EXPECT_EQ(jwt.verifyTimeConstraint(ExpTime + kClockSkewInSecond + 10),
Status::JwtExpired);

// 10s after nbf
EXPECT_EQ(jwt.verifyTimeConstraint(NbfTime - kClockSkewInSecond + 10),
Status::Ok);
// 10s befoe nbf
EXPECT_EQ(jwt.verifyTimeConstraint(NbfTime - kClockSkewInSecond - 10),
Status::JwtNotYetValid);
}

TEST(VerifyExpTest, OnlyExp) {
Jwt jwt;
EXPECT_EQ(jwt.parseFromString(JwtText), Status::Ok);
// Reset nbf
jwt.nbf_ = 0;

// 10s before exp
EXPECT_EQ(jwt.verifyTimeConstraint(ExpTime + kClockSkewInSecond - 10),
Status::Ok);
// 10s after exp
EXPECT_EQ(jwt.verifyTimeConstraint(ExpTime + kClockSkewInSecond + 10),
Status::JwtExpired);

// `Now` can be 0,
EXPECT_EQ(jwt.verifyTimeConstraint(0), Status::Ok);
}

TEST(VerifyExpTest, OnlyNbf) {
Jwt jwt;
EXPECT_EQ(jwt.parseFromString(JwtText), Status::Ok);
// Reset exp
jwt.exp_ = 0;

// `Now` can be very large
EXPECT_EQ(jwt.verifyTimeConstraint(9223372036854775810U), Status::Ok);

// 10s after nbf
EXPECT_EQ(jwt.verifyTimeConstraint(NbfTime - kClockSkewInSecond + 10),
Status::Ok);
// 10s befoe nbf
EXPECT_EQ(jwt.verifyTimeConstraint(NbfTime - kClockSkewInSecond - 10),
Status::JwtNotYetValid);
}

TEST(VerifyExpTest, NotTimeConstraint) {
Jwt jwt;
EXPECT_EQ(jwt.parseFromString(JwtText), Status::Ok);
// Reset both exp and nbf
jwt.exp_ = 0;
jwt.nbf_ = 0;

// `Now` can be very large
EXPECT_EQ(jwt.verifyTimeConstraint(9223372036854775810U), Status::Ok);

// `Now` can be 0,
EXPECT_EQ(jwt.verifyTimeConstraint(0), Status::Ok);
}

} // namespace
} // namespace jwt_verify
} // namespace google
9 changes: 3 additions & 6 deletions src/verify.cc
Original file line number Diff line number Diff line change
Expand Up @@ -304,12 +304,9 @@ Status verifyJwt(const Jwt& jwt, const Jwks& jwks) {
}

Status verifyJwt(const Jwt& jwt, const Jwks& jwks, uint64_t now) {
// First check that the JWT has not expired (exp) and is active (nbf).
if (now < jwt.nbf_) {
return Status::JwtNotYetValid;
}
if (jwt.exp_ && now > jwt.exp_) {
return Status::JwtExpired;
Status time_status = jwt.verifyTimeConstraint(now);
if (time_status != Status::Ok) {
return time_status;
}

return verifyJwtWithoutTimeChecking(jwt, jwks);
Expand Down
60 changes: 0 additions & 60 deletions src/verify_time_test.cc

This file was deleted.