DeepSeek Harness plugin

dsh-tool-jwt

DSH JWT tool: HS256 decode (header/payload/expiry status), sign, and verify — zero runtime dependencies, RFC 7515-verified

Jump to install

Source facts

Repository
chenxuhl/dsh-tool-jwt
Latest update
Aug 19, 2026
Category
Tools & Capabilities
GitHub stars
0
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/chenxuhl/dsh-tool-jwt
Plugin: dsh-tool-jwt
Author: chenxuhl

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer4 files
README.en.mdSource · read only
README language

dsh-tool-jwt

中文

DSH JWT tool plugin — HS256 JWT decode (without verification), sign, and full verification. Pure functions, zero runtime dependencies (only Node.js built-in crypto).

![License](LICENSE)

Motivation

Backend developers deal with JWTs daily: you want to peek inside a token to see what's in it and whether it's expired, but manually base64url-decoding + JSON-parsing + timestamp arithmetic is too slow; during integration testing you need to craft test tokens (for gateways/downstream auth), and hand-assembling header/payload/signature is error-prone; when verifying a token's signature and expiry, mental HMAC is unreliable.

This plugin provides deterministic JWT tools, of which decode is the differentiating capability: it does not verify the signature, only does structural parsing + expiry status computation (against the current clock), for quick token inspection. verify runs the full validation chain: algorithm check (alg=HS256), constant-time signature comparison (crypto.timingSafeEqual, resistant to timing attacks), and expiry judgment (optional leewaySeconds clock-skew tolerance).

Security Model

JWT signature forgery and algorithm confusion are real threats. Defenses:

1. Algorithm enforcement: verify only accepts alg=HS256; alg=none or any non-HS256 algorithm is rejected outright, preventing algorithm downgrade attacks 2. Constant-time signature comparison: crypto.timingSafeEqual, byte-by-byte comparison that leaks no timing information 3. Input length caps: token ≤ 16KB, secret ≤ 4KB, serialized payload ≤ 8KB — over-limit inputs are rejected at the entry point and never enter processing 4. decode does not verify: only structural parsing + expiry status computation, explicitly informing the caller that "decode does not verify the signature"

> ⚠️ This tool is intended for development/integration-testing scenarios (inspecting tokens, crafting test tokens, verifying signatures). Never paste production secrets into untrusted sessions.

Other boundaries: invalid base64url strings are caught and reported (with input truncation); non-JSON header/payload is reported (with location); non-object JSON is reported; non-numeric exp is reported; mutually-exclusive secret detection (secret and secretBase64url given together is rejected).

Tool Declaration

Registers the jwt tool (dsh-tool-jwt, row id tool-jwt), uniformly outputting a text report.

ParameterTypeRequiredDescription
actionstringdecode / sign / verify
tokenstringJWT compact serialization (header.payload.signature). Required for decode/verify
payloadobjectClaim object (required for sign), e.g. {"sub":"u1","role":"admin"}. exp/iat are managed by expiresInSeconds
secretstringHMAC secret (UTF-8 bytes). Required for sign/verify. Mutually exclusive with secretBase64url
secretBase64urlstringHMAC secret (base64url-encoded raw bytes, for binary keys such as RFC 7515 vectors and JWK k values). Mutually exclusive with secret
expiresInSecondsintegersign only: validity duration in seconds; sets exp = now + N (skipped when payload.exp is given)
leewaySecondsintegerverify only: allowed clock skew in seconds when judging exp (default 0)

Actions

actionFunctionOutput example
decodeParse header/payload as JSON, compute expiry status against the current clock (valid / expired / no-exp-claim, with ISO timestamps and remaining/elapsed seconds). Does not verify the signatureheader: {"alg":"HS256","typ":"JWT"}<br>payload: {"sub":"u1","exp":1767231600}<br>expiry.status: valid<br>expiry.expiresInSeconds: 3600
signIssue an HS256 token. Optional expiresInSeconds auto-sets exp, iat is auto-added; an explicit payload.exp takes precedencetoken: eyJ...<br>claims: {"sub":"u1","iat":1767225600,"exp":1767231600}
verifyFull validation: alg=HS256, constant-time signature comparison, expiry judgment (optional leewaySeconds)valid: true<br>payload: {"sub":"u1","exp":1767231600}<br>expiry.expiresAt: 2026-01-01T01:00:00.000Z

Examples

jwt { action: "decode", token: "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1MSJ9.sig" }
  → header: {"alg":"HS256","typ":"JWT"}
    payload: {"sub":"u1"}
    expiry.status: no-exp-claim
    note: decode does not verify the signature

jwt { action: "sign", payload: {"sub":"u1","role":"admin"}, secret: "topsecret", expiresInSeconds: 3600 }
  → token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1MSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTc2NzIyNTYwMCwiZXhwIjoxNzY3MjI5MjAwfQ.<sig>
    claims: {"sub":"u1","role":"admin","iat":1767225600,"exp":1767229200}

jwt { action: "verify", token: "eyJ...", secret: "topsecret", leewaySeconds: 30 }
  → valid: true
    payload: {"sub":"u1","role":"admin","iat":1767225600,"exp":1767229200}
    expiry.expiresAt: 2026-01-01T01:00:00.000Z

Edge Cases

CaseHandling
Token without three segmentsjwt: token must have exactly three segments
Non-JSON header/payloadjwt: header/payload is not valid JSON
Non-object header/payloadjwt: header/payload JSON must be an object
Invalid base64urljwt: invalid base64url input: "..."
exp not a numberjwt: exp claim must be a number
exp exactly equal to current timeexpired (RFC 7519: exp must be strictly greater than the current time)
No exp claimno-exp-claim
Token over 16KB / secret over 4KB / payload over 8KBRejected at the entry point (not truncated)
Both secret and secretBase64url givenRejected at the entry point
Signature mismatchvalid: false + reason: bad-signature
alg not HS256valid: false + reason: wrong-alg
Expired tokenvalid: false + reason: expired (tolerated within leewaySeconds)
Empty secretjwt: secret must be a non-empty string
RFC 7515 binary keysPassed via secretBase64url as raw bytes (Buffer.from(key, 'base64url'))

Correctness

The signature logic is verified against the RFC 7515 Appendix A.1 official HS256 test vector — the verifyJwt: RFC vector test group in tests/jwt-sign.spec.ts confirms byte-for-byte agreement with the RFC standard output.

Installation

Profile Bundle (Recommended)

Install this plugin into a profile as a standalone bundle:

# Interactive (web) profile —— install from the GitHub repository
dsh plugin --profile web add github:chenxuhl/dsh-tool-jwt
# One-off task (headless) profile —— dsh run uses headless by default
dsh plugin --profile headless add github:chenxuhl/dsh-tool-jwt

Or install from the tarball produced by npm pack:

npm pack     # produces dsh-tool-jwt-<version>.tgz
# Interactive (web) profile
dsh plugin --profile web add ./dsh-tool-jwt-<version>.tgz
# One-off task (headless) profile
dsh plugin --profile headless add ./dsh-tool-jwt-<version>.tgz

The bundled dsh.bundle.patch automatically adds the plugin to the profile's layer stack after installation (row id: tool-jwt). The plugin's missing peer dependencies (@deepseek-ai/cordis, @deepseek-ai/dsh-tools) are provided by the profile's healed profiles/node_modules fallback installation.

> ⚠️ web and headless are different profiles: installing into web does not automatically cover headless; dsh run uses the headless profile by default. Use forward slashes for Windows paths (C:/...).

Local Development (link installation)

git clone https://github.com/chenxuhl/dsh-tool-jwt.git
cd dsh-tool-jwt && npm install && npm run build
dsh plugin --profile web add link:<repo-path>

> Windows + pnpm link: protocol note: some pnpm versions incorrectly concatenate link:D:\... backslash paths. Use forward slashes link:D:/...; if the junction still points to the wrong path, manually New-Item -ItemType Junction to fix the link inside node_modules.

Verify Installation

dsh --profile web --dump-config | grep tool-jwt

Runtime Verification

dsh run "use the jwt tool to decode eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1MSJ9.sig"

Tests

npm test
  • base64url.spec.ts: encode/decode all branches + invalid characters + non-string input + case/padding variants
  • jwt-decode.spec.ts: three-segment splitting + JSON parsing + expiry status (valid/expired/no-exp-claim/boundary) + size guards
  • jwt-sign.spec.ts: RFC 7515 A.1 official HS256 vector + self-sign round-trip + wrong key + expiry + leeway tolerance + tampering detection + non-HS256 algorithm rejection
  • register.spec.ts: registration contract (AUDIT-CROSS-02 style)

License

MIT