Skip to content

Fix token refresh not triggering on 403 responses#74

Merged
kilbot merged 2 commits intomainfrom
fix/token-refresh-handle-403
Feb 6, 2026
Merged

Fix token refresh not triggering on 403 responses#74
kilbot merged 2 commits intomainfrom
fix/token-refresh-handle-403

Conversation

@kilbot
Copy link
Copy Markdown
Contributor

@kilbot kilbot commented Feb 6, 2026

Summary

  • Token refresh handler only intercepted 401 responses
  • An expired JWT can cause the PHP backend to return 403 (expired token resets user to 0, capability check fails)
  • Now intercepts both 401 and 403 to trigger token refresh

Context

Companion fix on the PHP side: wcpos/woocommerce-pos#472

Test plan

  • Let a JWT token expire while using the POS
  • Verify the app automatically refreshes the token and retries instead of showing a 403 error

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved token refresh handling to properly manage 403 Forbidden errors in addition to 401 Unauthorized errors, ensuring proper authentication recovery when capability-related permission issues occur.

The token refresh handler only intercepted 401 responses, but an
expired JWT can cause the PHP backend to return 403 when the invalid
token resets the authenticated user to 0 and the capability check
fails. Now intercepts both 401 and 403 to trigger token refresh.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

The token refresh handler now treats HTTP 403 Forbidden errors the same as 401 Unauthorized errors, enabling token refresh attempts when expired JWTs affect capability checks. The canHandle method is extended to check for either status code.

Changes

Cohort / File(s) Summary
Error Status Code Handling
packages/hooks/src/use-http-client/create-token-refresh-handler.ts
Extended error handling to treat 403 Forbidden responses identically to 401 Unauthorized by updating the canHandle condition to check for error.response?.status === 401 || 403.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰✨ A hop and a skip, a status code flip,
403 joins 401's trip,
Tokens refresh with JWT care,
Capabilities flow—oh so fair!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes the main change: extending token refresh handling to trigger on 403 responses in addition to 401 responses, which is the primary modification shown in the code change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/token-refresh-handle-403

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 6, 2026

📊 Test Coverage Report

Package Statements Branches Functions Lines
@wcpos/core 🔴 37.1% 🔴 43.8% 🔴 42.8% 🔴 35.9%
@wcpos/components 🔴 44.9% 🟡 60.9% 🔴 24.2% 🔴 47.3%
@wcpos/database 🔴 33.2% 🔴 35.9% 🔴 40.3% 🔴 32.9%
@wcpos/hooks 🔴 45.5% 🔴 46.8% 🔴 44.8% 🔴 45.7%
@wcpos/utils 🔴 35.0% 🔴 0.0% 🔴 50.0% 🔴 33.3%
@wcpos/query 🟡 68.0% 🔴 52.6% 🟡 66.1% 🟡 68.0%
Average 🔴 44.0% 🔴 40.0% 🔴 44.7% 🔴 43.8%
Coverage Legend
  • 🟢 Good (≥80%)
  • 🟡 Moderate (60-79%)
  • 🔴 Needs improvement (<60%)
  • ⚪ No coverage data
--- 🤖 Updated by GitHub Actions • [View full report](https://github.com/wcpos/monorepo/actions/runs/21753882135)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 6, 2026

🚀 Deployment Summary

Item Status
Preview URL https://wcpos--g6gzs015yf.expo.app
E2E Tests ❌ Failed
Commit 19cd1dc

🔗 Quick Links

❌ Failed Tests (4 total)

settings.spec.ts

  • [free-authenticated] should change language to French and load translations from CDN

    Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

  • [free-authenticated] should persist language after closing and reopening settings

    Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

  • [pro-authenticated] should change language to French and load translations from CDN

    Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed
    ...and 1 more in this file

📋 Full error details (first 5)

settings.spec.ts - should change language to French and load translations from CDN

Project: free-authenticated

Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator: getByText('Produit')
Expected: visible
Timeout: 15000ms
Error: element(s) not found

Call log:
�[2m  - Expect "toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByText('Produit')�[22m

settings.spec.ts - should persist language after closing and reopening settings

Project: free-authenticated

Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator: getByText('Produit')
Expected: visible
Timeout: 15000ms
Error: element(s) not found

Call log:
�[2m  - Expect "toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByText('Produit')�[22m

settings.spec.ts - should change language to French and load translations from CDN

Project: pro-authenticated

Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator: getByText('Produit')
Expected: visible
Timeout: 15000ms
Error: element(s) not found

Call log:
�[2m  - Expect "toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByText('Produit')�[22m

settings.spec.ts - should persist language after closing and reopening settings

Project: pro-authenticated

Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator: getByText('Produit')
Expected: visible
Timeout: 15000ms
Error: element(s) not found

Call log:
�[2m  - Expect "toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByText('Produit')�[22m

📸 Failure Screenshots

📷 settings Language Settings 2a494 sing and reopening settings free authenticated

settings Language Settings 2a494 sing and reopening settings free authenticated

📷 settings Language Settings 2a494 sing and reopening settings free authenticated

settings Language Settings 2a494 sing and reopening settings free authenticated

📷 settings Language Settings 53f0f load translations from CDN free authenticated

settings Language Settings 53f0f  load translations from CDN free authenticated

📷 settings Language Settings 53f0f load translations from CDN free authenticated

settings Language Settings 53f0f  load translations from CDN free authenticated

📷 settings Language Settings 53f0f load translations from CDN pro authenticated

settings Language Settings 53f0f  load translations from CDN pro authenticated

📷 settings Language Settings 53f0f load translations from CDN pro authenticated

settings Language Settings 53f0f  load translations from CDN pro authenticated

🔗 Debug Links


🤖 Updated by GitHub Actions

@kilbot kilbot merged commit 33fbbeb into main Feb 6, 2026
1 of 3 checks passed
@kilbot kilbot deleted the fix/token-refresh-handle-403 branch February 6, 2026 15:09
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