Add downgradeFromDPoP for in-place DPoP→Bearer migration - #4142
Merged
Conversation
sfdctaka
marked this pull request as ready for review
August 24, 2026 21:50
Clang Static Analysis Issues
Generated by 🚫 Danger |
Add SFUserAccountManager.downgradeFromDPoP(_:success:failure:), the inverse of upgradeToDPoP: it rolls a DPoP-bound session back to Bearer in place using the same connected app, redirect URI, and scopes, independent of the global useDPoP flag. It is a no-op (success callback, unchanged account) when the session is already Bearer. On success it deletes the obsolete DPoP key pair and nonce-cache entry keyed to the pre-migration credentials, and unregisters the DP user-agent feature marker for the now-Bearer completion. Make the downgrade durable across an interactive re-auth: SFOAuthCoordinator now decides whether to append dpop_jkt to /authorize by precedence — an explicit per-call override first, then the per-user credential token type, and only then the global useDPoP flag. Previously an interactive re-login of a downgraded account fell through to the global flag (default on in 14.0) and silently re-bound the session to DPoP. AuthFlowTester: add a "Downgrade from DPoP" action (enabled only for a DPoP-bound session) and a downgrade UI test. Add unit tests for the coordinator precedence and for downgrade delegation and the no-op guard.
sfdctaka
force-pushed
the
feature/dpop-downgrade-api
branch
from
August 24, 2026 21:53
fa40832 to
4ada124
Compare
|
||||||||||||||||
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev #4142 +/- ##
==========================================
+ Coverage 71.77% 71.80% +0.03%
==========================================
Files 254 254
Lines 22804 22837 +33
==========================================
+ Hits 16367 16398 +31
- Misses 6437 6439 +2
🚀 New features to boost your workflow:
|
wmathurin
reviewed
Aug 24, 2026
…truth Address review: the token-type comparisons were inconsistent — the /authorize binding gate in SFOAuthCoordinator compared case-insensitively against SFSDKDPoPRequestDecorator.dpopTokenType, while the migration guards in SFUserAccountManager inlined a case-sensitive isEqualToString:@"DPoP". On a server casing variant the two paths could disagree on whether a session is DPoP-bound. Add SFSDKDPoPRequestDecorator.isDPoPTokenType: — one case-insensitive predicate (RFC 6749 §5.1 / RFC 9449 §6.1) keyed off the single dpopTokenType constant, nil/empty-safe — and route every DPoP-vs-Bearer decision through it: the coordinator gate, the decorator's own proof-attach gate, the upgrade/downgrade no-op guards, the migration success-callback cleanup, the DP feature-marker register/unregister, and the photo-request nonce-harvest guard. Predicate is public (not internal) so it stays visible to the Objective-C callers across framework, SPM, and CocoaPods builds. Adds a unit test covering casing variants and the nil/empty/Bearer cases.
wmathurin
approved these changes
Aug 24, 2026
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
SFUserAccountManager.downgradeFromDPoP(_:success:failure:), the inverse of the existingupgradeToDPoP. It rolls a DPoP-bound session back to unbound Bearer in place — same connected app, redirect URI, and scopes — independent of the globalusesDPoPflag. It is a no-op (success callback, unchanged account) when the session is already Bearer.Why
Completes the in-place DPoP migration pair so apps can move a user off DPoP without a full logout/login, mirroring
upgradeToDPoP.Changes
SFUserAccountManager— newdowngradeFromDPoP:wrapper delegating tomigrateRefreshTokenwithuseDPoP:@NO; no-op guard when already Bearer. On success it deletes the obsolete DPoP key pair + nonce-cache entry keyed to the pre-migration credentials, and unregisters theDPuser-agent feature marker for the now-Bearer completion.SFOAuthCoordinator(/authorizebinding) — decides whether to appenddpop_jktby precedence: explicit per-call override → per-usercredentials.tokenType→ global flag. Previously an interactive re-login of a downgraded account fell through to the global flag (default on in 14.0) and silently re-bound the session to DPoP. This is an OAuth2/authorizebehavior change and needs maintainer review.Review notes
/authorizebinding decision — requesting maintainer (Wolf) review before merge; kept as draft.