fix(oauth): add RefreshTokenHttpError and guard refreshAuthTokens in MaxKeyChainLength recovery#26258
Conversation
…MaxKeyChainLength recovery Companion to MetaMask/core#7989. - Add `RefreshTokenHttpError` class to `AuthTokenHandler` that carries the HTTP `statusCode`, enabling callers to distinguish permanent (401) from transient failures. The core controller duck-types this error shape to map 401 responses to `InvalidRefreshToken` instead of the generic `FailedToRefreshJWTTokens`. - Wrap `SeedlessOnboardingController.refreshAuthTokens()` in a try/catch in the `MaxKeyChainLengthExceeded` recovery path. A stale or revoked refresh token should not abort rehydration — the error is logged and execution continues to `rehydrateSeedPhrase`.
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
| super(message); | ||
| this.name = 'RefreshTokenHttpError'; | ||
| } | ||
| } |
There was a problem hiding this comment.
Missing Object.setPrototypeOf in custom Error subclass
Low Severity
RefreshTokenHttpError extends Error but omits the Object.setPrototypeOf(this, RefreshTokenHttpError.prototype) call that the project's own AuthenticationError class uses (with an explicit link to the TypeScript breaking-changes wiki). Without it, instanceof RefreshTokenHttpError checks can silently return false in transpiled environments, defeating the purpose of this typed error class. The whole point of introducing RefreshTokenHttpError is to let callers distinguish it from plain Error.
Co-authored-by: Cursor <cursoragent@cursor.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
All alerts resolved. Learn more about Socket for GitHub. This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored. Ignoring alerts on:
|
|
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsE2E Test Selection: Performance Test Selection: |
https://github.com/SocketSecurity ignore npm/@metamask/seedless-onboarding-controller@8.1.0 @metamask/seedless-onboarding-controller is used for social login onboarding and requires network access for interacting with Web3Auth servers and Toprf Operations. |
|
@SocketSecurity ignore npm/@metamask/seedless-onboarding-controller@8.1.0
|





Explanation
Companion to MetaMask/core#7989.
1.
RefreshTokenHttpErrorinAuthTokenHandlerThe core
SeedlessOnboardingControllernow distinguishes permanent token failures (401) from transient ones to apply the right recovery strategy. It does this by checking whether the error thrown byrefreshJWTTokenis aRefreshTokenHttpErrorwithstatusCode === 401.Previously
AuthTokenHandlerthrew a plainError('Failed to refresh JWT token')for all non-2xx responses, making this distinction impossible. This PR adds aRefreshTokenHttpErrorclass that carries the HTTPstatusCode, giving the controller the information it needs2. try/catch around
refreshAuthTokensin theMaxKeyChainLengthExceededrecovery pathrefreshAuthTokensis called fire-and-forget in theMaxKeyChainLengthExceededrecovery path beforerehydrateSeedPhrase. If the refresh token is already stale or revoked (which is precisely the scenario that triggers this path), the call would throw and abort rehydration entirely — leaving the user stuck.Wrapping in try/catch logs the error and lets rehydration proceed regardless.
3. encryptorAdapter for SeedlessOnboardingController
KeyringController has a generic EncryptionResult type that accepts our mobile Encryptor's cipher property. However, SeedlessOnboardingController uses a fixed VaultEncryptor type (from ExportableKeyEncryptor) that strictly requires data instead of cipher.
Changelog
CHANGELOG entry: null
References
SeedlessOnboardingControllerChecklist
Note
Medium Risk
Touches OAuth token refresh and seedless recovery flows; incorrect error typing/handling could change recovery behavior for revoked or transient refresh-token failures.
Overview
Improves seedless OAuth token-refresh error handling so callers can distinguish auth-server HTTP failures by status code.
AuthTokenHandler.refreshJWTTokennow throwsRefreshTokenHttpError(includesstatusCode) on non-2xx responses, and theMaxKeyChainLengthExceededrecovery path inAuthentication.syncPasswordAndUnlockWalletwrapsSeedlessOnboardingController.refreshAuthTokens()in atry/catchto log and continue withrehydrateSeedPhraseinstead of aborting recovery.Written by Cursor Bugbot for commit 413b327. This will update automatically on new commits. Configure here.