Skip to content

feat(jwtinfo): add flags to refresh and write to file JWT tokens#31

Merged
xenOs76 merged 2 commits into
mainfrom
feat/jwtinfo_refresh_token
May 2, 2026
Merged

feat(jwtinfo): add flags to refresh and write to file JWT tokens#31
xenOs76 merged 2 commits into
mainfrom
feat/jwtinfo_refresh_token

Conversation

@xenOs76
Copy link
Copy Markdown
Owner

@xenOs76 xenOs76 commented May 2, 2026

Summary by CodeRabbit

  • New Features

    • Automatic token refresh capability—tokens stay fresh in background until expiration
    • Save tokens to file with optional background refresh functionality
    • Enhanced token lifecycle management with configurable thresholds
  • Documentation

    • Updated usage examples demonstrating token refresh workflows and file persistence features

@xenOs76 xenOs76 self-assigned this May 2, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

Warning

Rate limit exceeded

@xenOs76 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 38 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 48bb01ef-ca4c-42b4-a4cb-a089393a128e

📥 Commits

Reviewing files that changed from the base of the PR and between 1f4681d and 9a25ae0.

📒 Files selected for processing (4)
  • README.md
  • internal/cmd/jwtinfo.go
  • internal/jwtinfo/jwtinfo.go
  • internal/jwtinfo/jwtinfo_refresh_test.go
📝 Walkthrough

Walkthrough

This PR adds JWT token refresh and renew capabilities to the jwtinfo command. Function signatures in the jwtinfo package change from value returns to pointer returns. New methods enable token expiration extraction, automatic refresh scheduling, and file persistence. CLI integration adds --refresh, --renew-threshold, and --token-output-file flags with signal-based graceful shutdown. Comprehensive tests and README documentation follow.

Changes

JWT Token Refresh Feature

Layer / File(s) Summary
API Signature Updates
internal/jwtinfo/jwtinfo.go
RequestToken, ReadTokenFromFile return *JwtTokenData pointers instead of values; PrintTokenInfo accepts pointer parameter. Error paths return nil instead of zero-value structs.
Token Lifecycle Methods
internal/jwtinfo/jwtinfo.go
New methods GetExpiration() and GetIssuedAt() extract exp/iat claims; Refresh() re-requests tokens using optional refresh tokens; RefreshLoop() continuously refreshes until context cancellation. Helper calculateWaitDuration() computes renewal timing.
Token Persistence
internal/jwtinfo/jwtinfo.go
New WriteTokenToFile() method writes refreshed tokens to file or prints info to stdout based on configuration.
Refresh Token Decoding
internal/jwtinfo/jwtinfo.go
DecodeBase64() now conditionally decodes refresh tokens as JWT only when they contain exactly 3 segments (2 dots); non-JWT refresh tokens are treated as opaque.
CLI Integration
internal/cmd/jwtinfo.go
New flags --refresh, --token-output-file, --renew-threshold added. Token variable becomes pointer type. When refresh is enabled, command validates --request-url, installs signal handlers for graceful shutdown, and invokes RefreshLoop() with threshold and output parameters.
Documentation & Tests
README.md, internal/jwtinfo/jwtinfo_refresh_test.go, internal/jwtinfo/jwtinfo_test.go
README expanded with new flags and usage examples. Comprehensive test suite added covering expiration/issued-at claim extraction, refresh loop behavior with mocked HTTP client, file persistence, error handling, and retry scenarios. Existing tests updated for pointer-based signatures.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI (jwtinfo)
    participant TokData as JwtTokenData
    participant Client as HTTP Client
    participant File as File System
    participant OS as OS Signals

    CLI->>TokData: RequestToken() → *JwtTokenData
    TokData->>Client: POST /token (initial request)
    Client-->>TokData: access_token, refresh_token
    TokData->>File: WriteTokenToFile() [if --token-output-file]
    File-->>TokData: ✓ persisted

    alt --refresh enabled
        CLI->>OS: signal.Notify (SIGINT/SIGTERM)
        CLI->>TokData: RefreshLoop(ctx, ...)
        
        loop Until context cancelled
            TokData->>TokData: calculateWaitDuration(renewThreshold)
            TokData->>TokData: time.After(duration)
            TokData->>TokData: Refresh()
            TokData->>Client: POST /token (with refresh_token)
            Client-->>TokData: new access_token
            TokData->>File: WriteTokenToFile()
            File-->>TokData: ✓ refreshed
        end
        
        OS-->>CLI: signal received
        CLI->>TokData: ctx.Cancel()
        TokData-->>CLI: RefreshLoop() returns
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #24: Introduces ReadTokenFromFile() and initial token-file CLI wiring—the main PR updates this function's signature and extends token-file handling with refresh/renew capabilities.
  • PR #28: Updates RequestToken() to accept AllReader interface—the main PR further modifies this signature to return pointers and adds extensive refresh-related callers.
  • PR #27: Modifies RequestToken and PrintTokenInfo signatures and JWT parsing behavior—directly aligned with the main PR's API signature changes and extended token handling.

Poem

🐰 Tokens now refresh with grace and care,
Through signals caught from thin air,
A rabbit bounds from file to net,
Renewing JWTs ere they are set—
No expiration shall us scare! 🌙✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main changes: adding flags for refreshing JWT tokens and writing them to files, which are the primary features introduced across the modified files.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/jwtinfo_refresh_token

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 19 minutes and 38 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@xenOs76 xenOs76 changed the title feat(jwtinfo): add options to write the JWT token to a file and refre… feat(jwtinfo): add flags to refresh and write to file JWT tokens May 2, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/jwtinfo/jwtinfo.go (1)

419-427: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't require iat/exp on refresh tokens.

DecodeBase64 now accepts JWT-shaped refresh tokens, but PrintTokenInfo still unconditionally extracts time claims for every decoded token. Many providers issue refresh tokens without iat/exp, so this can make jwtinfo fail after an otherwise successful decode. Skip the time table when those claims are absent, or limit it to the access token.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/jwtinfo/jwtinfo.go` around lines 419 - 427, PrintTokenInfo currently
always calls unmarshalTokenTimeClaims and returns an error when iat/exp are
missing; change it to first check token.claims for "iat" or "exp" and only call
unmarshalTokenTimeClaims and render the cTable when at least one of those keys
exists (or, if you prefer, only for access tokens). In practice: inspect
token.claims (the map passed to unmarshalTokenTimeClaims) for "iat"/"exp" before
calling unmarshalTokenTimeClaims, and if neither key is present simply skip
creating/printing the time table instead of returning an error; keep using
token, tokenTimeClaims, unmarshalTokenTimeClaims and cTable names so the change
is localized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/cmd/jwtinfo.go`:
- Around line 174-187: The refresh loop currently re-creates refreshClient and
refreshValuesMap and calls jwtinfo.ReadRequestValuesFile and
jwtinfo.ParseRequestJSONValues with ignored errors, which can drop parameters;
instead hoist the existing client and requestValuesMap (the variables originally
created and validated earlier) into a scope visible to the refresh loop and
reuse them there, removing the redundant refreshClient/refreshValuesMap
re-parsing; if you must re-read, propagate and handle errors from
jwtinfo.ReadRequestValuesFile and jwtinfo.ParseRequestJSONValues rather than
assigning to “_”, and ensure the refresh code uses the validated client variable
(client) and requestValuesMap rather than refreshClient/refreshValuesMap.

In `@internal/jwtinfo/jwtinfo.go`:
- Around line 613-647: In calculateWaitDuration (on JwtTokenData) validate
renewThreshold is within 0..100 before any time math: if renewThreshold is < 0
or > 100 return a descriptive error (e.g. "renewThreshold must be between 0 and
100") so invalid values cannot schedule refreshes after expiry or force
immediate tight retries; add this check at the top of the function (before
GetExpiration/GetIssuedAt and before any lifetime/wakeTime calculation).
- Around line 653-659: The current write using os.WriteFile(outFileName,
[]byte(jtd.AccessTokenRaw), 0o600) can leave the target file empty/partial for
readers; instead, write jtd.AccessTokenRaw atomically by creating a temp file in
the same directory (e.g., via os.CreateTemp(dir, "token-*")), write the bytes,
fsync if possible, close it, then os.Rename(tempPath, outFileName) and set
permissions 0600; on any error remove the temp file and report the failure to
outWriter similarly, and keep the existing timestamped success message when
rename succeeds.

In `@README.md`:
- Around line 237-246: The README examples for the jwtinfo command incorrectly
say refresh runs “in the background”; update the wording for the https-wrench
jwtinfo examples and the second occurrence (lines 267-277) to state that
--refresh runs as a foreground loop that blocks the command and keeps the token
refreshed until interrupted (or similar phrasing like “keep it refreshed until
interrupted”), and ensure the flags section (--refresh, --renew-threshold)
reflects this foreground/blocking behavior rather than implying background
operation.

---

Outside diff comments:
In `@internal/jwtinfo/jwtinfo.go`:
- Around line 419-427: PrintTokenInfo currently always calls
unmarshalTokenTimeClaims and returns an error when iat/exp are missing; change
it to first check token.claims for "iat" or "exp" and only call
unmarshalTokenTimeClaims and render the cTable when at least one of those keys
exists (or, if you prefer, only for access tokens). In practice: inspect
token.claims (the map passed to unmarshalTokenTimeClaims) for "iat"/"exp" before
calling unmarshalTokenTimeClaims, and if neither key is present simply skip
creating/printing the time table instead of returning an error; keep using
token, tokenTimeClaims, unmarshalTokenTimeClaims and cTable names so the change
is localized.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6b988d94-338e-44e2-890f-4b285649abad

📥 Commits

Reviewing files that changed from the base of the PR and between 9501d95 and 1f4681d.

📒 Files selected for processing (5)
  • README.md
  • internal/cmd/jwtinfo.go
  • internal/jwtinfo/jwtinfo.go
  • internal/jwtinfo/jwtinfo_refresh_test.go
  • internal/jwtinfo/jwtinfo_test.go

Comment thread internal/cmd/jwtinfo.go Outdated
Comment thread internal/jwtinfo/jwtinfo.go
Comment thread internal/jwtinfo/jwtinfo.go Outdated
Comment thread README.md
@xenOs76
Copy link
Copy Markdown
Owner Author

xenOs76 commented May 2, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@xenOs76 xenOs76 merged commit b8d8f90 into main May 2, 2026
4 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant