coveralls: 
[![Coverage Status](https://coveralls.io/builds/14045386/badge)](https://coveralls.io/builds/14045386)

Coverage decreased (-0.4%) to 99.552% when pulling **09cbf0634e47ee97b93eefae7ef8fa44d8682bc0 on fix-298** into **e1e4d02c5d9499bcd59403fff2ad73d67cdc8af4 on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14045386/badge)](https://coveralls.io/builds/14045386)

Coverage decreased (-0.4%) to 99.552% when pulling **09cbf0634e47ee97b93eefae7ef8fa44d8682bc0 on fix-298** into **e1e4d02c5d9499bcd59403fff2ad73d67cdc8af4 on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14045590/badge)](https://coveralls.io/builds/14045590)

Coverage decreased (-0.1%) to 99.851% when pulling **99c1ee928af045c9b15fdce9c60cb4fbf6157ed1 on fix-298** into **e1e4d02c5d9499bcd59403fff2ad73d67cdc8af4 on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/14049235/badge)](https://coveralls.io/builds/14049235)

Coverage remained the same at 100.0% when pulling **8d104bc73c8b7ec1de7d724ff0a8c3be83e1893d on fix-298** into **e1e4d02c5d9499bcd59403fff2ad73d67cdc8af4 on master**.

diff --git a/.gitignore b/.gitignore
index 9672a5b..a6f0fb1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ develop-eggs/
 dist/
 downloads/
 eggs/
+.eggs/
 lib/
 lib64/
 parts/
diff --git a/jwt/__main__.py b/jwt/__main__.py
index 52e7abf..396dc0d 100644
--- a/jwt/__main__.py
+++ b/jwt/__main__.py
@@ -54,10 +54,13 @@ def encode_payload(args):
 
 def decode_payload(args):
     try:
-        if sys.stdin.isatty():
-            token = sys.stdin.read()
-        else:
+        if args.token:
             token = args.token
+        else:
+            if sys.stdin.isatty():
+                token = sys.stdin.readline().strip()
+            else:
+                raise IOError('Cannot read from stdin: terminal not a TTY')
 
         token = token.encode('utf-8')
         data = decode(token, key=args.key, verify=args.verify)
@@ -133,7 +136,10 @@ def build_argparser():
 
     # Decode subcommand
     decode_parser = subparsers.add_parser('decode', help='use to decode a supplied JSON web token')
-    decode_parser.add_argument('token', help='JSON web token to decode.')
+    decode_parser.add_argument(
+        'token',
+        help='JSON web token to decode.',
+        nargs='?')
 
     decode_parser.add_argument(
         '-n', '--no-verify',

pyjwt decode --verify CLI hang 
$ pyjwt -v
pyjwt 1.5.3


$ pyjwt decode --no-verify eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg
^CTraceback (most recent call last):
  File "/usr/local/bin/pyjwt", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/jwt/__main__.py", line 157, in main
    output = arguments.func(arguments)
  File "/usr/local/lib/python2.7/dist-packages/jwt/__main__.py", line 58, in decode_payload
    token = sys.stdin.read()

$  pyjwt decode --no-verify eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg
^CTraceback (most recent call last):
  File "/Users/v612996/anaconda/bin/pyjwt", line 11, in <module>
    sys.exit(main())
  File "/Users/v612996/anaconda/lib/python3.6/site-packages/jwt/__main__.py", line 157, in main
    output = arguments.func(arguments)
  File "/Users/v612996/anaconda/lib/python3.6/site-packages/jwt/__main__.py", line 58, in decode_payload
    token = sys.stdin.read()
KeyboardInterrupt
$ python --version
Python 3.6.0 :: Anaconda custom (x86_64)

But the same token decoded perfectly under python 2.6 interpreter: 
>>> jwt.decode(encoded,verify=False)
{u'some': u'payload'}


What is the work around of "pyjwt decode --no-verify" hang in the CLI? 






diff --git a/tests/test_cli.py b/tests/test_cli.py
index f08cf6b..715c2f1 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -57,6 +57,37 @@ class TestCli:
 
         assert 'There was an error decoding the token' in str(excinfo.value)
 
+    def test_decode_payload_terminal_tty(self, monkeypatch):
+        encode_args = [
+            '--key=secret-key',
+            'encode',
+            'name=hello-world',
+        ]
+        parser = build_argparser()
+        parsed_encode_args = parser.parse_args(encode_args)
+        token = encode_payload(parsed_encode_args)
+
+        decode_args = ['--key=secret-key', 'decode']
+        parsed_decode_args = parser.parse_args(decode_args)
+
+        monkeypatch.setattr(sys.stdin, 'isatty', lambda: True)
+        monkeypatch.setattr(sys.stdin, 'readline', lambda:  token)
+
+        actual = json.loads(decode_payload(parsed_decode_args))
+        assert actual['name'] == 'hello-world'
+
+    def test_decode_payload_raises_terminal_not_a_tty(self, monkeypatch):
+        decode_args = ['--key', '1234', 'decode']
+        parser = build_argparser()
+        args = parser.parse_args(decode_args)
+
+        monkeypatch.setattr(sys.stdin, 'isatty', lambda: False)
+
+        with pytest.raises(IOError) as excinfo:
+            decode_payload(args)
+            assert 'Cannot read from stdin: terminal not a TTY' \
+                in str(excinfo.value)
+
     @pytest.mark.parametrize('key,name,job,exp,verify', [
         ('1234', 'Vader', 'Sith', None, None),
         ('4567', 'Anakin', 'Jedi', '+1', None),

pip install -e .[crypto]
parse_log_pytest
pytest
pytest pytest-cov
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
cffi==1.17.1
coverage==7.8.0
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@e1e4d02c5d9499bcd59403fff2ad73d67cdc8af4#egg=PyJWT
pytest @ file:///croot/pytest_1738938843180/work
pytest-cov==6.0.0
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
      - coverage==7.8.0
      - cryptography==44.0.2
      - pycparser==2.22
      - pytest-cov==6.0.0
prefix: /opt/conda/envs/pyjwt

tests/test_cli.py::TestCli::test_decode_payload_terminal_tty tests/test_cli.py::TestCli::test_decode_payload_raises_terminal_not_a_tty
tests/test_cli.py::TestCli::test_build_argparse tests/test_cli.py::TestCli::test_encode_payload_raises_value_error_key_is_required tests/test_cli.py::TestCli::test_decode_payload_raises_decoded_error tests/test_cli.py::TestCli::test_decode_payload_raises_decoded_error_isatty tests/test_cli.py::TestCli::test_encode_decode[1234-Vader-Sith-None-None] tests/test_cli.py::TestCli::test_encode_decode[4567-Anakin-Jedi-+1-None] tests/test_cli.py::TestCli::test_encode_decode[4321-Padme-Queen-4070926800-true] tests/test_cli.py::TestCli::test_main[1234-Vader-Sith-None-None] tests/test_cli.py::TestCli::test_main[4567-Anakin-Jedi-+1-None] tests/test_cli.py::TestCli::test_main[4321-Padme-Queen-4070926800-true] tests/test_cli.py::TestCli::test_main_throw_exception
.gitignore jwt/__main__.py
.gitignore jwt/__main__.py