Skip to content

[iOS] NativeLoginManager Basic-Auth header uses URL-safe Base64 instead of standard Base64, breaking login for some username/password combinations - #4161

Merged
JohnsonEricAtSalesforce merged 1 commit into
forcedotcom:devfrom
JohnsonEricAtSalesforce:bugfix/ios-nativeloginmanager-basic-auth-header-uses-url-safe-base64-instead-of-standard-base64-breaking-login-for-some-username-password-combinations
Aug 31, 2026
Merged

[iOS] NativeLoginManager Basic-Auth header uses URL-safe Base64 instead of standard Base64, breaking login for some username/password combinations#4161
JohnsonEricAtSalesforce merged 1 commit into
forcedotcom:devfrom
JohnsonEricAtSalesforce:bugfix/ios-nativeloginmanager-basic-auth-header-uses-url-safe-base64-instead-of-standard-base64-breaking-login-for-some-username-password-combinations

Conversation

@JohnsonEricAtSalesforce

Copy link
Copy Markdown
Contributor

Summary

NativeLoginManagerInternal's helper for building the Basic-Auth Authorization header (generateColonConcatenatedBase64String()) encoded the colon-concatenated username and password with the URL-safe Base64 alphabet and no padding (via urlSafeBase64Encode()). HTTP Basic Authentication (RFC 7617) requires the standard Base64 alphabet with padding. For most credential pairs the two alphabets produce identical output, which is why this went unnoticed — they only diverge when the encoded bytes would contain +, /, or need = padding under the standard alphabet. When that happens, login fails with a generic "check your username and password" error even though the credentials are correct (confirmed working via web login for the same user).

The equivalent fix already shipped on Android for the same defect class in its own Basic-Auth encoding helper; the iOS Swift implementation independently had the identical bug and that fix was never ported over.

  • Changed generateColonConcatenatedBase64String() to encode with the standard Base64 alphabet (plain data.base64EncodedString()) instead of urlSafeBase64Encode().
  • This helper is shared by login(), submitAuthorizationRequest() (used by the OTP/registration-completion flows), and submitPasswordlessAuthorizationRequest() (OTP/passwordless login), so all three call sites are fixed by the one change.

Scope note

This does not touch urlSafeBase64Encode()'s other callers in the same file — generateCodeVerifier() and generateChallenge() — which correctly need URL-safe Base64 per RFC 7636 for PKCE codeVerifier/codeChallenge values and are unrelated to this HTTP Basic-Auth header.

Test plan

  • Added a regression test covering login(), using a username/password pair whose combined UTF-8 bytes diverge between the standard and URL-safe alphabets (contains / and requires = padding under the standard alphabet); asserts the Authorization header matches standard Base64 output.
  • Added a regression test covering submitPasswordlessAuthorizationRequest() (a call site sharing the same helper), same divergent credential pair.
  • Ran NativeLoginManagerTests on the iOS simulator — both new tests pass. (Two pre-existing, unrelated failures in this suite — testShouldShowBackButton/testShouldShowBackButtonWithBioAuth — are keychain-entitlement issues in this local sandboxed environment, reproduced identically on unmodified dev.)
  • Found via a real reproduction during release validation: fresh self-registration on iOS 26 (Native Login template) followed by an immediate logout and login attempt with the identical, just-set password failed; the same password worked correctly via Salesforce web login for the same user, isolating the defect to this SDK's Basic-Auth header encoding.

This response was generated by an AI agent on behalf of @JohnsonEricAtSalesforce.

@github-actions

Copy link
Copy Markdown
TestsPassedSkippedFailed ❌️
AuthFlowTester UI Test Results all1 ran1 ❌
TestResult
AuthFlowTester UI Test Results all
AuthFlowTesterUITests.xctest
LegacyLoginTests.testCAOpaque_DefaultScopes_WebServerFlow()❌ failure

@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.57%. Comparing base (1f2b5d8) to head (2551251).
⚠️ Report is 3 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #4161      +/-   ##
==========================================
- Coverage   71.47%   67.57%   -3.91%     
==========================================
  Files         254      254              
  Lines       22868    22901      +33     
==========================================
- Hits        16346    15475     -871     
- Misses       6522     7426     +904     
Components Coverage Δ
Analytics 70.78% <ø> (ø)
Common 70.88% <ø> (-0.47%) ⬇️
Core 61.30% <46.34%> (-5.80%) ⬇️
SmartStore 73.45% <ø> (ø)
MobileSync 88.84% <ø> (-0.12%) ⬇️
Files with missing lines Coverage Δ
...Login/NativeLogin/NativeLoginManagerInternal.swift 35.51% <100.00%> (+7.68%) ⬆️

... and 34 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

Copy link
Copy Markdown
TestsPassed ✅SkippedFailed
SalesforceSDKCore iOS ^18 Test Results1018 ran1018 ✅
TestResult
No test annotations available

… (Replace urlSafeBase64Encode with base64EncodedString in generateColonConcatenatedBase64String; add regression tests for login and submitPasswordlessAuthorizationRequest)
@JohnsonEricAtSalesforce
JohnsonEricAtSalesforce force-pushed the bugfix/ios-nativeloginmanager-basic-auth-header-uses-url-safe-base64-instead-of-standard-base64-breaking-login-for-some-username-password-combinations branch from 4144f6b to 2551251 Compare August 31, 2026 20:08
@JohnsonEricAtSalesforce
JohnsonEricAtSalesforce merged commit ff4e588 into forcedotcom:dev Aug 31, 2026
22 of 24 checks passed
@JohnsonEricAtSalesforce
JohnsonEricAtSalesforce deleted the bugfix/ios-nativeloginmanager-basic-auth-header-uses-url-safe-base64-instead-of-standard-base64-breaking-login-for-some-username-password-combinations branch August 31, 2026 20:31
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.

2 participants