28 Unix tools. One binary. Zero dependencies.·the missing coreutils for the agent era·try vrk in your browser at vrk.sh/play·curl vrk.sh/install.sh | sh - ready in 5 seconds·

vrk jwt

Try it in your browser

vrk, compiled to WebAssembly

# Reads one claim from the token payload. It does not check the signature.

Enter runs, Shift+Enter adds a line
    output
    Press RUN. Nothing leaves your browser.

    files you can cat:

    Edit the command and press RUN. Open the full playground for more recipes, or install vrk to run it on your own files.

    vrk jwt decodes JWT tokens locally without sending them anywhere, and checks expiry and claims.

    The problem

    A CI pipeline gets a 401. The token looks valid. You paste it into jwt.io to inspect it, which sends a production token to a third-party server. Or you base64-decode it manually and fight padding errors for twenty minutes. The answer was that the token expired two hours ago.

    The solution

    vrk jwt decodes JWT tokens locally, without sending them anywhere. It prints the payload as JSON, extracts individual claims with --claim, and checks expiry with --expired. It does not verify signatures. Use it to inspect a token, not to authenticate one.

    Before and after

    Before

    echo "$TOKEN" | base64 -d 2>/dev/null | jq .
    # base64 padding errors, no expiry check
    # or worse: paste into jwt.io
    

    After

    echo $TOKEN | vrk jwt --expired
    

    Example

    echo $TOKEN | vrk jwt --claim sub
    

    Exit codes

    CodeMeaning
    0Success or token is valid
    1Token expired/invalid or runtime error
    2Usage error - bad format, too many args

    Flags

    FlagShortTypeDescription
    --json-jboolEmit decoded token as JSON
    --claim-cstringPrint value of a single claim
    --expired-eboolExit 1 if the token is expired
    --validboolExit 1 if expired, not-yet-valid, or issued in the future
    --quiet-qboolSuppress stderr output

    How it works

    vrk jwt decodes a JWT (JSON Web Token) and prints its payload, one claim, or an expiry check. It never verifies the signature.

    Decode a token

    $ echo 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjoxNjAwMDAwMDAwLCJpYXQiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' | vrk jwt
    {"exp":1600000000,"iat":1516239022,"name":"John Doe","sub":"1234567890"}
    

    jwt prints the full payload as JSON, sorted alphabetically. It does not verify the signature, so use it for inspection only.

    Extract a single claim

    $ TOKEN='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjoxNjAwMDAwMDAwLCJpYXQiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
    $ echo "$TOKEN" | vrk jwt --claim name
    John Doe
    
    $ echo "$TOKEN" | vrk jwt --claim sub
    1234567890
    

    jwt prints the raw value with no JSON wrapping. Use it to get a user ID or email in a script.

    Check if a token is expired

    $ TOKEN='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjoxNjAwMDAwMDAwLCJpYXQiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
    $ echo "$TOKEN" | vrk jwt --expired
    error: jwt: token expired ... ago (exp: 2020-09-13T12:26:40Z)
    $ echo $?
    1
    

    Exits 0 if the token is still valid. Exits 1 if expired. The error message shows when it expired and how long ago.

    Full time validity check

    echo "$TOKEN" | vrk jwt --valid
    

    --valid checks three things: not expired (exp), not before the valid time (nbf), and not issued in the future (iat). If any check fails, it exits 1. If a time claim is present but is not a number (a string, null), that also fails, so a malformed token cannot pass. Fractional dates like 1700000000.5 are compared as real dates.

    --valid and the valid field in --json cover the time claims only. The signature is never checked, and --json says so with "signature_verified":false.

    JSON output

    echo "$TOKEN" | vrk jwt --json
    

    Wraps the decoded payload in a JSON envelope with header information.

    Pipeline integration

    Check token before API call

    # Only call the API if the token is still valid
    echo "$TOKEN" | vrk jwt --expired --quiet && \
      curl -H "Authorization: Bearer $TOKEN" https://api.example.com/data
    

    Extract user info from a token and store it

    USER_ID=$(echo "$TOKEN" | vrk jwt --claim sub)
    USER_EMAIL=$(echo "$TOKEN" | vrk jwt --claim email)
    vrk kv set --ns auth "user:$USER_ID" "$USER_EMAIL" --ttl 1h
    

    Decode and convert timestamps

    # Get the expiry time as a human-readable date
    EXP=$(echo "$TOKEN" | vrk jwt --claim exp)
    vrk epoch "$EXP" --iso
    

    When it fails

    Expired token:

    $ TOKEN='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjoxNjAwMDAwMDAwLCJpYXQiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
    $ echo "$TOKEN" | vrk jwt --expired
    error: jwt: token expired ... ago (exp: 2020-09-13T12:26:40Z)
    $ echo $?
    1
    

    Invalid token format:

    $ echo "not.a.jwt" | vrk jwt
    error: jwt: invalid token: header is not valid JSON
    $ echo $?
    1
    

    No input:

    $ vrk jwt
    usage error: jwt: no input: provide as argument or via stdin
    $ echo $?
    2