diff --git a/jwt/api.py b/jwt/api.py
index 5f2ce6f..201bffd 100644
--- a/jwt/api.py
+++ b/jwt/api.py
@@ -181,16 +181,32 @@ class PyJWT(object):
         except KeyError:
             raise InvalidAlgorithmError('Algorithm not supported')
 
+        if 'iat' in payload:
+            try:
+                int(payload['iat'])
+            except ValueError:
+                raise DecodeError('Issued At claim (iat) must be an integer.')
+
         if 'nbf' in payload and verify_expiration:
+            try:
+                nbf = int(payload['nbf'])
+            except ValueError:
+                raise DecodeError('Not Before claim (nbf) must be an integer.')
+
             utc_timestamp = timegm(datetime.utcnow().utctimetuple())
 
-            if payload['nbf'] > (utc_timestamp + leeway):
+            if nbf > (utc_timestamp + leeway):
                 raise ExpiredSignatureError('Signature not yet valid')
 
         if 'exp' in payload and verify_expiration:
+            try:
+                exp = int(payload['exp'])
+            except ValueError:
+                raise DecodeError('Expiration Time claim (exp) must be an integer.')
+
             utc_timestamp = timegm(datetime.utcnow().utctimetuple())
 
-            if payload['exp'] < (utc_timestamp - leeway):
+            if exp < (utc_timestamp - leeway):
                 raise ExpiredSignatureError('Signature has expired')
 
         if 'aud' in payload:

non-numeric expiration claim does not raise an error
I would expect a non-numeric expiration claim to raise an error but it does not. To reproduce, here's a JWT with ``{exp: '<not a number>'}``':

````
>>> import jwt
>>> import calendar, time
>>> iat = calendar.timegm(time.gmtime())
>>> token = jwt.encode({'aud': 'some-aud', 'iss': 'some-iss', 'typ': 'some-typ', 'iat': iat, 'exp': '<not a number>', 'request': {}}, 'secret')
>>> jwt.decode(token, 'secret', verify=True, audience='some-aud')
{u'aud': u'some-aud', u'iss': u'some-iss', u'request': {}, u'exp': u'<not a number>', u'iat': 1427495823, u'typ': u'some-typ'}
````

If a signature checking was somehow bypassed, an expiration like this could maybe allow for replay attacks.
diff --git a/tests/test_api.py b/tests/test_api.py
index 3b79490..371390d 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -195,6 +195,33 @@ class TestAPI(unittest.TestCase):
         exception = context.exception
         self.assertEquals(str(exception), 'Algorithm not supported')
 
+    def test_decode_raises_exception_if_exp_is_not_int(self):
+        # >>> jwt.encode({'exp': 'not-an-int'}, 'secret')
+        example_jwt = ('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.'
+                       'eyJleHAiOiJub3QtYW4taW50In0.'
+                       'P65iYgoHtBqB07PMtBSuKNUEIPPPfmjfJG217cEE66s')
+
+        with self.assertRaisesRegexp(DecodeError, 'exp'):
+            self.jwt.decode(example_jwt, 'secret')
+
+    def test_decode_raises_exception_if_iat_is_not_int(self):
+        # >>> jwt.encode({'iat': 'not-an-int'}, 'secret')
+        example_jwt = ('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.'
+                       'eyJpYXQiOiJub3QtYW4taW50In0.'
+                       'H1GmcQgSySa5LOKYbzGm--b1OmRbHFkyk8pq811FzZM')
+
+        with self.assertRaisesRegexp(DecodeError, 'iat'):
+            self.jwt.decode(example_jwt, 'secret')
+
+    def test_decode_raises_exception_if_nbf_is_not_int(self):
+        # >>> jwt.encode({'nbf': 'not-an-int'}, 'secret')
+        example_jwt = ('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.'
+                       'eyJuYmYiOiJub3QtYW4taW50In0.'
+                       'c25hldC8G2ZamC8uKpax9sYMTgdZo3cxrmzFHaAAluw')
+
+        with self.assertRaisesRegexp(DecodeError, 'nbf'):
+            self.jwt.decode(example_jwt, 'secret')
+
     def test_encode_datetime(self):
         secret = 'secret'
         current_datetime = datetime.utcnow()

pip install -e .
parse_log_pytest
pytest
cryptography pytest
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
cffi==1.17.1
cryptography==44.0.2
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
packaging @ file:///croot/packaging_1734472117206/work
pluggy @ file:///croot/pluggy_1733169602837/work
pycparser==2.22
-e git+https://github.com/jpadilla/pyjwt.git@8f28b4a6124830fcea400668840e645bb91e38a2#egg=PyJWT
pytest @ file:///croot/pytest_1738938843180/work
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work

name: pyjwt
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - cffi==1.17.1
      - cryptography==44.0.2
      - pycparser==2.22
prefix: /opt/conda/envs/pyjwt

tests/test_api.py::TestAPI::test_decode_raises_exception_if_exp_is_not_int tests/test_api.py::TestAPI::test_decode_raises_exception_if_iat_is_not_int tests/test_api.py::TestAPI::test_decode_raises_exception_if_nbf_is_not_int
tests/test_api.py::TestAPI::test_decodes_valid_es384_jwt tests/test_api.py::TestAPI::test_decodes_valid_rs384_jwt tests/test_api.py::TestAPI::test_encode_decode_with_ecdsa_sha256 tests/test_api.py::TestAPI::test_encode_decode_with_ecdsa_sha384 tests/test_api.py::TestAPI::test_encode_decode_with_ecdsa_sha512 tests/test_api.py::TestAPI::test_encode_decode_with_rsa_sha256 tests/test_api.py::TestAPI::test_encode_decode_with_rsa_sha384 tests/test_api.py::TestAPI::test_encode_decode_with_rsa_sha512
tests/test_api.py::TestAPI::test_algorithms_parameter_removes_alg_from_algorithms_list tests/test_api.py::TestAPI::test_allow_skip_verification tests/test_api.py::TestAPI::test_bad_secret tests/test_api.py::TestAPI::test_bytes_secret tests/test_api.py::TestAPI::test_check_audience tests/test_api.py::TestAPI::test_check_audience_in_array tests/test_api.py::TestAPI::test_check_issuer tests/test_api.py::TestAPI::test_custom_headers tests/test_api.py::TestAPI::test_custom_json_encoder tests/test_api.py::TestAPI::test_decode_algorithm_param_should_be_case_sensitive tests/test_api.py::TestAPI::test_decode_fails_when_alg_is_not_on_method_algorithms_param tests/test_api.py::TestAPI::test_decode_invalid_crypto_padding tests/test_api.py::TestAPI::test_decode_invalid_header_padding tests/test_api.py::TestAPI::test_decode_invalid_header_string tests/test_api.py::TestAPI::test_decode_invalid_payload_padding tests/test_api.py::TestAPI::test_decode_invalid_payload_string tests/test_api.py::TestAPI::test_decode_missing_segments_throws_exception tests/test_api.py::TestAPI::test_decode_skip_expiration_verification tests/test_api.py::TestAPI::test_decode_skip_notbefore_verification tests/test_api.py::TestAPI::test_decode_unicode_value tests/test_api.py::TestAPI::test_decode_with_expiration tests/test_api.py::TestAPI::test_decode_with_expiration_with_leeway tests/test_api.py::TestAPI::test_decode_with_invalid_aud_list_member_throws_exception tests/test_api.py::TestAPI::test_decode_with_invalid_audience_param_throws_exception tests/test_api.py::TestAPI::test_decode_with_non_mapping_header_throws_exception tests/test_api.py::TestAPI::test_decode_with_non_mapping_payload_throws_exception tests/test_api.py::TestAPI::test_decode_with_nonlist_aud_claim_throws_exception tests/test_api.py::TestAPI::test_decode_with_notbefore tests/test_api.py::TestAPI::test_decode_with_notbefore_with_leeway tests/test_api.py::TestAPI::test_decode_works_with_unicode_token tests/test_api.py::TestAPI::test_decodes_valid_jwt tests/test_api.py::TestAPI::test_ecdsa_related_algorithms tests/test_api.py::TestAPI::test_encode_algorithm_param_should_be_case_sensitive tests/test_api.py::TestAPI::test_encode_bad_type tests/test_api.py::TestAPI::test_encode_datetime tests/test_api.py::TestAPI::test_encode_decode tests/test_api.py::TestAPI::test_encode_decode_with_algo_none tests/test_api.py::TestAPI::test_invalid_crypto_alg tests/test_api.py::TestAPI::test_load_no_verification tests/test_api.py::TestAPI::test_load_verify_valid_jwt tests/test_api.py::TestAPI::test_no_secret tests/test_api.py::TestAPI::test_nonascii_secret tests/test_api.py::TestAPI::test_raise_exception_invalid_audience tests/test_api.py::TestAPI::test_raise_exception_invalid_audience_in_array tests/test_api.py::TestAPI::test_raise_exception_invalid_issuer tests/test_api.py::TestAPI::test_raise_exception_token_without_audience tests/test_api.py::TestAPI::test_raise_exception_token_without_issuer tests/test_api.py::TestAPI::test_register_algorithm_does_not_allow_duplicate_registration tests/test_api.py::TestAPI::test_register_algorithm_rejects_non_algorithm_obj tests/test_api.py::TestAPI::test_rsa_related_algorithms tests/test_api.py::TestAPI::test_unicode_secret tests/test_api.py::TestAPI::test_unregister_algorithm_removes_algorithm tests/test_api.py::TestAPI::test_unregister_algorithm_throws_error_if_not_registered tests/test_api.py::TestAPI::test_verify_signature_no_secret
jwt/api.py
jwt/api.py