downgradeFromDPoP
Downgrades the userAccount's existing DPoP-bound refresh token to a Bearer (non-DPoP) one, in place — same consumer key, redirect URI, and scopes the account already uses. This is a same-config convenience over migrateRefreshToken with useDPoP = false: no re-consent is expected because nothing about the connected app / External Client App configuration changes.
This works regardless of the global SalesforceSDKManager.useDPoP flag: that flag only sets the default DPoP posture for brand-new logins, while this call is an explicit action on an already-authenticated session — an app can leave the global flag on and still roll one user back to Bearer. The connected app / External Client App must accept Bearer tokens for the downgrade to succeed; a DPoP-enforcing app will reject the resulting session.
On success, the pre-downgrade DPoP key pair and DPoP nonce-cache entries (keyed by the account's pre-migration UserAccount.credentialsIdentifier, since migration mints a new one) are deleted — mirroring the teardown SalesforceSDKManager performs on logout. On failure or cancellation, that state is left untouched so the original DPoP-bound session keeps working.
Callers wanting to migrate to a different consumer key, redirect URI, or scopes (or to explicitly upgrade a Bearer session to DPoP) should call migrateRefreshToken directly with their own OAuthConfig and useDPoP value, or see upgradeToDPoP.
Note: onFailure (and onSuccess) may be invoked off the main thread — the synchronous null-check failure below runs on the caller's thread, but the OAuth-config resolution and migration below it run on Default. Callers that touch UI from these callbacks must marshal to the main thread themselves.
No-op: if userAccount is already Bearer (non-DPoP), there's nothing to downgrade — onSuccess is invoked synchronously with the unchanged account, no migration is attempted, and no DPoP state cleanup runs (there's none to clean up).