Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
885b558
Implement Native Auth V2 sign-in: password first factor and email OTP…
djanardhan98 Aug 31, 2026
a057db6
Report an unsupported V2 MFA channel as not implemented
djanardhan98 Aug 31, 2026
125e815
Point the common submodule at the merged Native Auth V2 sign-in branc…
djanardhan98 Aug 31, 2026
ba279a4
Add gated E2E coverage for Native Auth V2 sign-in
djanardhan98 Aug 31, 2026
9ce02b7
Record the SpotBugs fix in the common submodule
djanardhan98 Aug 31, 2026
fc0c805
Bump Common for Native Auth V2 compatibility fix
djanardhan98 Sep 1, 2026
866f14a
initial commit
spetrescu84 Sep 1, 2026
92b969e
common
spetrescu84 Sep 1, 2026
fb741d0
Address Native Auth V2 sign-in review findings
djanardhan98 Sep 1, 2026
9a5c176
feat: add native auth v2 mfa resend support
djanardhan98 Sep 1, 2026
718f8f5
fix: address native auth v2 sign-in review
djanardhan98 Sep 1, 2026
e164fa5
fix: preserve claims across native auth resend
djanardhan98 Sep 1, 2026
e0a37c0
Merge branch 'djanardhan/native-auth-v2-signin' into spetrescu/native…
spetrescu84 Sep 2, 2026
e04e8fe
correct common
spetrescu84 Sep 2, 2026
509ef59
align with sign in on requiredAttributes
spetrescu84 Sep 2, 2026
f2769ae
tests for password wipe
spetrescu84 Sep 2, 2026
b8b14fe
tests for command parameters for sign up
spetrescu84 Sep 2, 2026
76f20bd
Update Common for Native Auth V2 sign-in
djanardhan98 Sep 3, 2026
be59fb1
Update msal/src/main/java/com/microsoft/identity/nativeauth/statemach…
djanardhan98 Sep 3, 2026
88034f6
Restore V2 MFA invalid challenge naming
djanardhan98 Sep 3, 2026
e29643d
Align V2 MFA handling with latest Common
djanardhan98 Sep 3, 2026
bc14471
Merge branch 'dev' into djanardhan/native-auth-v2-signin
djanardhan98 Sep 3, 2026
4efdf86
Rename Native Auth V2 sign-in parameter adapter
djanardhan98 Sep 3, 2026
2dd1af1
Delegate MFA methods to the next state
djanardhan98 Sep 3, 2026
06345f0
Bump common submodule to e5fd150e
djanardhan98 Sep 4, 2026
b4fe6fb
Stop pinning the NativeAuthV2ContinuationState constructor arity in t…
djanardhan98 Sep 4, 2026
8ab480a
Remove invalid-credentials helper from V2 password errors
djanardhan98 Sep 8, 2026
3fd6c65
Drop unnecessary reflection test for unshipped V2 API
djanardhan98 Sep 8, 2026
de25b94
Merge remote-tracking branch 'origin/dev' into djanardhan/native-auth…
Copilot Sep 8, 2026
7ac288b
Align continuation-state helper with dev
Copilot Sep 8, 2026
19e20ba
Merge branch 'djanardhan/native-auth-v2-signin' into spetrescu/native…
spetrescu84 Sep 8, 2026
eb3e5d9
Merge remote-tracking branch 'origin/djanardhan/native-auth-v2-signin…
spetrescu84 Sep 8, 2026
9ab26eb
Merge branch 'dev' into djanardhan/native-auth-v2-signin
djanardhan98 Sep 8, 2026
3db5ca5
Point common submodule to latest dev
djanardhan98 Sep 8, 2026
5a45ab4
Use shared continuation-state test helper
djanardhan98 Sep 9, 2026
16a6eed
PR comments
spetrescu84 Sep 9, 2026
9fc9b46
PR comments
spetrescu84 Sep 9, 2026
ac5bca4
Merge branch 'djanardhan/native-auth-v2-signin' into spetrescu/native…
spetrescu84 Sep 9, 2026
db1348c
PR comments
spetrescu84 Sep 9, 2026
efcca2f
Route Native Auth V2 sign-up code submissions separately
djanardhan98 Sep 9, 2026
27cd885
Update Common for submit-code compatibility
djanardhan98 Sep 9, 2026
89df771
Use explicit reset-password submit-code names
djanardhan98 Sep 9, 2026
d0d8812
test fixes
spetrescu84 Sep 10, 2026
99dad53
last common
spetrescu84 Sep 10, 2026
3d500aa
last common
spetrescu84 Sep 10, 2026
51cf698
PR Comments
spetrescu84 Sep 10, 2026
deef0cd
Add email OTP first-factor sign-in support
spetrescu84 Sep 10, 2026
0eb026d
Align sign-in code flow with signup architecture
spetrescu84 Sep 10, 2026
ace4fd7
Update Common sign-in email OTP dependency
spetrescu84 Sep 10, 2026
7ec5acd
Merge dev into spetrescu/native-auth-v2-signup
spetrescu84 Sep 10, 2026
9324376
update for single calsite
spetrescu84 Sep 10, 2026
092552f
Add Native Auth V2 SMS MFA support
spetrescu84 Sep 10, 2026
99867cd
Merge remote-tracking branch 'origin/dev' into spetrescu/native-auth-…
Copilot Sep 11, 2026
1c72f77
Change return value for invalid continuation state
spetrescu84 Sep 11, 2026
b87977f
Revise CoroutineExtensions documentation
spetrescu84 Sep 11, 2026
71f73ed
Pr comments
spetrescu84 Sep 11, 2026
141e4b0
PR comments
spetrescu84 Sep 11, 2026
e65ae93
Merge branch 'spetrescu/native-auth-v2-signup' into spetrescu/native-…
spetrescu84 Sep 14, 2026
c2a257d
Merge branch 'spetrescu/native-auth-v2-signin-email-otp' into spetres…
spetrescu84 Sep 14, 2026
1395484
validate scenario before parameter creation
spetrescu84 Sep 14, 2026
fe41f0e
Merge branch 'dev' into spetrescu/native-auth-v2-signin-email-otp
spetrescu84 Sep 15, 2026
16e9709
Add sub error
spetrescu84 Sep 16, 2026
cc54dfa
latest common
spetrescu84 Sep 16, 2026
46c1e59
Merge branch 'spetrescu/native-auth-v2-signin-email-otp' into spetres…
spetrescu84 Sep 16, 2026
15751e7
Merge branch 'dev' into spetrescu/native-auth-v2-mfa-sms
spetrescu84 Sep 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common
Submodule common updated 22 files
+3 −0 changelog.txt
+31 −0 common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/PasskeyWebListener.kt
+13 −2 common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/WebViewAuthorizationFragment.java
+14 −9 ...rc/main/java/com/microsoft/identity/common/nativeauth/internal/controllers/v2/NativeAuthV2FlowController.kt
+42 −1 common/src/test/java/com/microsoft/identity/common/internal/providers/oauth2/PasskeyWebListenerTest.kt
+72 −0 ...t/java/com/microsoft/identity/common/internal/providers/oauth2/WebViewAuthorizationFragmentPasskeyTest.java
+31 −0 ...va/com/microsoft/identity/common/nativeauth/internal/controllers/v2/NativeAuthV2SignInFlowControllerTest.kt
+9 −0 common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthV2OAuth2Strategy.kt
+31 −0 ...on4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/interactors/NativeAuthV2Interactor.kt
+1 −0 .../main/com/microsoft/identity/common/java/nativeauth/providers/responses/v2/NativeAuthV2ContinuationState.kt
+1 −0 ...on4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/responses/v2/NativeAuthV2HalAction.kt
+14 −0 ...in/com/microsoft/identity/common/java/nativeauth/providers/responses/v2/NativeAuthV2InteractionApiResult.kt
+1 −0 ...j/src/main/com/microsoft/identity/common/java/nativeauth/providers/responses/v2/NativeAuthV2LinkRelation.kt
+28 −8 ...src/main/com/microsoft/identity/common/java/nativeauth/providers/responses/v2/NativeAuthV2ResponseParser.kt
+18 −1 common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/v2/NativeAuthV2RequestProvider.kt
+3 −0 common4j/src/test/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthOAuth2StrategyV2Test.kt
+32 −0 ...est/com/microsoft/identity/common/java/nativeauth/providers/interactors/NativeAuthV2SignInInteractorTest.kt
+8 −8 ...test/com/microsoft/identity/common/java/nativeauth/providers/responses/v2/NativeAuthV2ResponseParserTest.kt
+76 −0 ...om/microsoft/identity/common/java/nativeauth/providers/responses/v2/NativeAuthV2SignInResponseParserTest.kt
+18 −3 ...on4j/src/test/com/microsoft/identity/common/java/nativeauth/providers/v2/NativeAuthV2RequestProviderTest.kt
+1 −1 common4j/versioning/version.properties
+1 −1 versioning/version.properties
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ import java.util.Collections
*
* No challenge is sent until the app selects a method explicitly. [authMethods] is exactly the set
* the server offered for this step; selecting anything else fails without issuing a request. This
* increment supports email one-time codes only, so any other channel returns a not-implemented
* error ([com.microsoft.identity.nativeauth.statemachine.errors.NativeAuthErrorV2.isNotImplemented])
* rather than following the wrong link.
* state supports email and SMS one-time codes; any other channel returns a not-implemented error
* ([com.microsoft.identity.nativeauth.statemachine.errors.NativeAuthErrorV2.isNotImplemented])
* rather than following an unsupported method.
*/
class MFARequiredStateV2 internal constructor(
continuationToken: String?,
Expand Down Expand Up @@ -162,13 +162,18 @@ class MFARequiredStateV2 internal constructor(
scenario = scenario
)

if (!offeredMethod.challengeChannel.equals(NativeAuthConstants.ChallengeChannel.EMAIL, ignoreCase = true)) {
// Reported as not-implemented rather than a bare error so the app can tell "this SDK
// increment only supports email one-time codes" apart from an unspecified server error,
// which is what an untyped error would be indistinguishable from.
if (!offeredMethod.challengeChannel.equals(
NativeAuthConstants.ChallengeChannel.EMAIL,
ignoreCase = true
) &&
!offeredMethod.challengeChannel.equals(
NativeAuthConstants.ChallengeChannel.SMS,
ignoreCase = true
)
) {
return MFARequestChallengeErrorV2(
errorType = ErrorTypes.NOT_IMPLEMENTED,
errorMessage = "Only email authentication methods are supported for multi-factor authentication.",
errorMessage = "Only email and SMS authentication methods are supported for multi-factor authentication.",
correlationId = correlationId,
scenario = scenario
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,25 @@ class NativeAuthV2SignInTest : PublicClientApplicationAbstractTest() {
assertEquals("email", result.authMethods.single().challengeChannel)
}

@Test
fun submitFirstFactorEmailCodeCanTransitionToSmsMFA() = runTest {
val state = codeRequiredState()
enqueueResult(
NativeAuthV2CommandResult.MFARequired(
correlationId,
createContinuationState(),
listOf(NativeAuthV2AuthMethod("sms-1", "sms", "+X XXX XXX 34"))
),
NativeAuthV2SignInSubmitCodeCommand::class
)

val result = state.submitCode("12345678") as NativeAuthResultV2.MFARequired

assertEquals(NativeAuthFlowScenarioV2.SIGN_IN, result.scenario)
assertEquals("sms-1", result.authMethods.single().id)
assertEquals("sms", result.authMethods.single().challengeChannel)
}

@Test
fun submitFirstFactorEmailCodeCanCompleteSignIn() = runTest {
val state = codeRequiredState()
Expand Down Expand Up @@ -692,7 +711,7 @@ class NativeAuthV2SignInTest : PublicClientApplicationAbstractTest() {
}

// -----------------------------------------------------------------------------------------
// Email OTP MFA
// Email and SMS OTP MFA
// -----------------------------------------------------------------------------------------

@Test
Expand All @@ -717,6 +736,26 @@ class NativeAuthV2SignInTest : PublicClientApplicationAbstractTest() {
assertEquals(NativeAuthFlowScenarioV2.SIGN_IN, result.scenario)
}

@Test
fun signInV2WithPasswordCanTransitionToSmsMFA() = runTest {
enqueueResult(
NativeAuthV2CommandResult.MFARequired(
correlationId,
createContinuationState(),
listOf(NativeAuthV2AuthMethod("sms-1", "sms", "+X XXX XXX 34"))
),
NativeAuthV2SignInStartCommand::class
)

val result = application.signInV2(signInParameters()) as NativeAuthResultV2.MFARequired
val method = result.authMethods.single()

assertEquals("sms-1", method.id)
assertEquals("sms", method.challengeChannel)
assertEquals("sms", method.challengeType)
assertEquals("+X XXX XXX 34", method.loginHint)
}

@Test
fun selectAuthMethodTransitionsToMFAVerificationRequired() = runTest {
val state = mfaRequiredState()
Expand All @@ -740,6 +779,31 @@ class NativeAuthV2SignInTest : PublicClientApplicationAbstractTest() {
assertEquals(NativeAuthFlowScenarioV2.SIGN_IN, result.scenario)
}

@Test
fun selectSmsAuthMethodTransitionsToMFAVerificationRequired() = runTest {
val state = mfaRequiredState(
methods = listOf(NativeAuthV2AuthMethod("sms-1", "sms", "+X XXX XXX 34"))
)
enqueueResult(
NativeAuthV2CommandResult.MFAVerificationRequired(
correlationId,
createContinuationState(),
7,
"+X XXX XXX 34",
"sms"
),
NativeAuthV2SelectMFAMethodCommand::class
)

val result = state.selectAuthMethod(state.authMethods.single()) as
NativeAuthResultV2.MFAVerificationRequired

assertEquals(7, result.codeLength)
assertEquals("+X XXX XXX 34", result.sentTo)
assertEquals("sms", result.channel)
assertEquals(NativeAuthFlowScenarioV2.SIGN_IN, result.scenario)
}

@Test
fun selectAuthMethodRejectsAMethodTheServerDidNotOffer() = runTest {
val state = mfaRequiredState()
Expand All @@ -753,16 +817,15 @@ class NativeAuthV2SignInTest : PublicClientApplicationAbstractTest() {
}

@Test
fun selectAuthMethodRejectsAnUnsupportedChannelWithoutIssuingACommand() = runTest {
fun selectAuthMethodRejectsAnUnknownChannelWithoutIssuingACommand() = runTest {
val state = mfaRequiredState(
methods = listOf(NativeAuthV2AuthMethod("sms-1", "sms", "+1***4567"))
methods = listOf(NativeAuthV2AuthMethod("voice-1", "voice", "+1***4567"))
)

val result = state.selectAuthMethod(state.authMethods.single())

assertTrue(result is MFARequestChallengeErrorV2)
val error = result as MFARequestChallengeErrorV2
// Distinguishable from an unspecified server error: this increment supports email only.
assertTrue(error.isNotImplemented())
assertFalse(error.isAuthMethodBlocked())
assertFalse(error.isBrowserRequired())
Expand Down
Loading