Skip to content

Refresh expired CLI session instead of dropping to none auth#184

Merged
hackerwins merged 1 commit into
mainfrom
fix/cli-refresh-expired-session
May 5, 2026
Merged

Refresh expired CLI session instead of dropping to none auth#184
hackerwins merged 1 commit into
mainfrom
fix/cli-refresh-expired-session

Conversation

@hackerwins

@hackerwins hackerwins commented May 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Fixes wafflebase docs list (and other CLI subcommands) returning HTTP 404 once the session's access token expires, even when a valid refresh token is sitting in ~/.wafflebase/session.json.
  • Root cause: resolveConfig in packages/cli/src/config/config.ts only adopted the saved session when !isSessionExpired(session). With an expired access token it fell through to authMode: 'none' and dropped session.activeWorkspace, so the HTTP client built GET /api/v1/workspaces//documents (empty segment) and the backend rejected it with a 404. The HttpClient's existing 401 → refresh → retry path requires authMode === 'jwt', so it was effectively dead code in exactly the scenario it was designed for.
  • Fix: adopt the session whenever both accessToken and refreshToken are present. The HttpClient now actually gets to refresh the access token on 401; if the refresh token is also dead, the existing SESSION_EXPIRED path still surfaces a clear "run wafflebase login" message.
  • wafflebase status keeps using isSessionExpired for its "valid" / "expired" UX hint — only config resolution is changed.

Test plan

  • pnpm --filter @wafflebase/cli test — new regression case in packages/cli/test/config.test.ts fails before the fix, passes after.
  • Manual repro: forced ~/.wafflebase/session.json expiresAt into the past, ran the installed CLI → HTTP 404. Then ran the patched CLI from source (pnpm --filter @wafflebase/cli dev docs list) → auto-refresh fired, document list returned, expiresAt rotated forward.
  • pnpm -w run verify:fast — exit 0.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Resolved CLI HTTP 404 errors that occurred when session access tokens expired despite having a valid refresh token. The CLI now properly handles automatic token refresh before retrying requests.
  • Tests

    • Added test coverage for session authentication scenarios with expired and valid access tokens.

When a session's access token expired, resolveConfig fell through to
authMode: 'none' and silently dropped session.activeWorkspace. The HTTP
client then built `/api/v1/workspaces//documents` (empty segment) and
the backend returned 404, making expired sessions surface as missing
routes — even though the refresh token was still valid and the existing
401 -> refresh -> retry path in HttpClient was waiting to handle exactly
this case.

Adopt the saved session whenever both tokens are present and let the
HTTP client decide if the access token still works. If the refresh
token is also dead, the existing SESSION_EXPIRED error path surfaces a
clear "run `wafflebase login`" message.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@coderabbitai

coderabbitai Bot commented May 5, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR fixes a CLI issue where an expired access token would cause a 404 error even with a valid refresh token. The resolveConfig function now permits sessions with both tokens present, deferring expiration checks to the HTTP client's refresh logic, and adds regression tests to verify the fix.

Changes

Session Token Handling in Config Resolution

Layer / File(s) Summary
Problem Documentation
docs/tasks/archive/2026/05/20260505-cli-expired-session-404-todo.md
New task document outlines the prior behavior (session gated by isSessionExpired), root cause (auth mode set to 'none' dropping workspace), and the fix strategy (allow both tokens through, let HTTP refresh handle expiration).
Core Implementation
packages/cli/src/config/config.ts
Removed isSessionExpired import and gate from resolveConfig session step; now returns authMode: 'jwt' whenever both accessToken and refreshToken are present, allowing downstream HTTP client to retry with refresh.
Test Coverage
packages/cli/test/config.test.ts
Added session-backed JWT auth test suite with temp file provisioning to verify resolveConfig returns authMode: 'jwt' and session.activeWorkspace in both unexpired and expired access token scenarios.
Archive & Index Updates
docs/tasks/README.md, docs/tasks/archive/README.md
Updated task count from 155 to 156 archived tasks and added new 2026/05 task entry linking to the session 404 fix documentation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit hopped through session gates,
Found tokens stuck in expired states—
Now both shall pass, the refresh flow thrives,
HTTP retries save the lives! 🚀
Test cases check each path with care. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main change: removing the expired session gate to enable auto-refresh via HttpClient instead of falling back to 'none' auth.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cli-refresh-expired-session

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

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/cli/test/config.test.ts (1)

60-112: ⚡ Quick win

Add one negative session-token edge test to lock guard behavior.

You already cover valid and expired access-token paths. Please also assert that when either token is missing, resolveConfig({}) does not select authMode: 'jwt' (protects the new session.accessToken && session.refreshToken contract at Line 112).

🧪 Suggested test addition
   describe('session-backed JWT auth', () => {
@@
     it('keeps JWT auth and workspace when access token is expired but refresh token exists', () => {
       writeSessionFile({ expiresAt: new Date(Date.now() - 60_000).toISOString() });
       const config = resolveConfig({});
       expect(config.authMode).toBe('jwt');
       expect(config.workspace).toBe('ws-from-session');
       expect(config.accessToken).toBe('access-token');
       expect(config.refreshToken).toBe('refresh-token');
     });
+
+    it('does not use JWT auth when refresh token is missing', () => {
+      writeSessionFile({ refreshToken: '' });
+      const config = resolveConfig({});
+      expect(config.authMode).not.toBe('jwt');
+    });
   });

As per coding guidelines, "**/*.{test,spec}.{js,ts,jsx,tsx}: Write tests for critical business logic and edge cases".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/test/config.test.ts` around lines 60 - 112, Add a negative test
in the 'session-backed JWT auth' describe block that uses writeSessionFile to
create a session missing either accessToken or refreshToken (e.g., omit
accessToken and/or refreshToken in overrides), calls resolveConfig({}), and
asserts that config.authMode is not 'jwt' and that
workspace/accessToken/refreshToken are not taken from the session; this protects
the new session.accessToken && session.refreshToken contract checked in
resolveConfig.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/tasks/archive/2026/05/20260505-cli-expired-session-404-todo.md`:
- Around line 13-15: Add explicit fenced code block languages to the two code
fences: change the block containing { "error": { "code": "ERROR", "message":
"HTTP 404" } } to a ```json fence, and change the block containing the GET
https://api.wafflebase.io/api/v1/workspaces//documents request to a ```http
fence so the JSON and HTTP examples are properly annotated for markdown linting.

---

Nitpick comments:
In `@packages/cli/test/config.test.ts`:
- Around line 60-112: Add a negative test in the 'session-backed JWT auth'
describe block that uses writeSessionFile to create a session missing either
accessToken or refreshToken (e.g., omit accessToken and/or refreshToken in
overrides), calls resolveConfig({}), and asserts that config.authMode is not
'jwt' and that workspace/accessToken/refreshToken are not taken from the
session; this protects the new session.accessToken && session.refreshToken
contract checked in resolveConfig.
🪄 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: 7398a161-86bb-4ecf-9f87-3e9cb2148a54

📥 Commits

Reviewing files that changed from the base of the PR and between 8cd453a and d5a2a9b.

📒 Files selected for processing (5)
  • docs/tasks/README.md
  • docs/tasks/archive/2026/05/20260505-cli-expired-session-404-todo.md
  • docs/tasks/archive/README.md
  • packages/cli/src/config/config.ts
  • packages/cli/test/config.test.ts

Comment on lines +13 to +15
```
{ "error": { "code": "ERROR", "message": "HTTP 404" } }
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Specify fenced code block languages to satisfy markdown lint.

Line 13 and Line 27 should include language identifiers (json, http) to clear MD040 warnings.

📝 Suggested markdown fix
-```
+```json
 { "error": { "code": "ERROR", "message": "HTTP 404" } }

@@
- +http
GET https://api.wafflebase.io/api/v1/workspaces//documents

Also applies to: 27-29

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 13-13: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/tasks/archive/2026/05/20260505-cli-expired-session-404-todo.md` around
lines 13 - 15, Add explicit fenced code block languages to the two code fences:
change the block containing { "error": { "code": "ERROR", "message": "HTTP 404"
} } to a ```json fence, and change the block containing the GET
https://api.wafflebase.io/api/v1/workspaces//documents request to a ```http
fence so the JSON and HTTP examples are properly annotated for markdown linting.

@github-actions

github-actions Bot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Verification: verify:self

Result: ✅ PASS in 138.5s

Lane Status Duration
sheets:build ✅ pass 13.6s
docs:build ✅ pass 12.1s
verify:fast ✅ pass 71.3s
frontend:build ✅ pass 17.4s
verify:frontend:chunks ✅ pass 0.3s
backend:build ✅ pass 4.8s
cli:build ✅ pass 2.1s
verify:entropy ✅ pass 16.8s

Verification: verify:integration

Result: ✅ PASS

@hackerwins
hackerwins merged commit 948c276 into main May 5, 2026
3 checks passed
@hackerwins
hackerwins deleted the fix/cli-refresh-expired-session branch May 5, 2026 08:52
@codecov

codecov Bot commented May 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@hackerwins hackerwins mentioned this pull request May 11, 2026
6 tasks
hackerwins added a commit that referenced this pull request May 11, 2026
Adds @wafflebase/slides as a third surface alongside Sheets and Docs,
plus 53-shape library (Phase 1+2), adjustment handles for 9 pilot
shapes (P3-A.1), live snap guides, align/distribute toolbar, themed
authoring, and layout-change UI. Also ships Sheets cell comments
(Phase B), docs peer-avatar caret jump, yorkie-js-sdk 0.7.8 upgrade,
and CLI/REST API improvements (docs export imageFetcher, expired
session refresh, REST docs split). Minor bump because slides is a
new top-level package.

Highlights: #184 #185 #186 #187 #188 #189 #190 #191 #192 #197 #198
#201 #202 #203 #204 #205 #206 #207 #209 #210
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