From 1b79b739dcdaee1a83521a602a456a03d8e4be1a Mon Sep 17 00:00:00 2001 From: Luciano Balmaceda Date: Fri, 6 Dec 2019 14:27:07 -0300 Subject: [PATCH 1/3] add passwordless flow using /oauth/token endpoint --- .../AuthenticationAPIClient.java | 92 +++++++++++++------ .../authentication/ParameterBuilder.java | 1 + 2 files changed, 64 insertions(+), 29 deletions(-) diff --git a/auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.java b/auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.java index 07e033db3..1214f44cd 100755 --- a/auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.java +++ b/auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.java @@ -58,6 +58,7 @@ import static com.auth0.android.authentication.ParameterBuilder.GRANT_TYPE_AUTHORIZATION_CODE; import static com.auth0.android.authentication.ParameterBuilder.GRANT_TYPE_MFA_OTP; import static com.auth0.android.authentication.ParameterBuilder.GRANT_TYPE_PASSWORD; +import static com.auth0.android.authentication.ParameterBuilder.GRANT_TYPE_PASSWORDLESS_OTP; import static com.auth0.android.authentication.ParameterBuilder.GRANT_TYPE_PASSWORD_REALM; import static com.auth0.android.authentication.ParameterBuilder.ID_TOKEN_KEY; import static com.auth0.android.authentication.ParameterBuilder.SCOPE_OPENID; @@ -320,7 +321,8 @@ public AuthenticationRequest loginWithOAuthAccessToken(@NonNull String token, @N /** * Log in a user using a phone number and a verification code received via SMS (Part of passwordless login flow) * The default scope used is 'openid'. - * Requires your Application to have the Resource Owner Legacy Grant Type enabled. See Client Grant Types to learn how to enable it. + * How the user is logged in depends on the {@link Auth0#isOIDCConformant()} flag. If this flag is set to true, your Application requires to have the Passwordless OTP Grant Type enabled. + * If this flag is set to false, the Resource Owner Legacy Grant Type must be enabled instead. * Example usage: *
      * {@code
@@ -335,25 +337,38 @@ public AuthenticationRequest loginWithOAuthAccessToken(@NonNull String token, @N
      * }
      * 
* - * @param phoneNumber where the user received the verification code - * @param verificationCode sent by Auth0 via SMS - * @param connection to end the passwordless authentication on + * @param phoneNumber where the user received the verification code + * @param verificationCode sent by Auth0 via SMS + * @param realmOrConnection to end the passwordless authentication on * @return a request to configure and start that will yield {@link Credentials} */ @SuppressWarnings("WeakerAccess") - public AuthenticationRequest loginWithPhoneNumber(@NonNull String phoneNumber, @NonNull String verificationCode, @NonNull String connection) { - Map parameters = ParameterBuilder.newAuthenticationBuilder() - .set(USERNAME_KEY, phoneNumber) - .set(PASSWORD_KEY, verificationCode) - .setGrantType(GRANT_TYPE_PASSWORD) + public AuthenticationRequest loginWithPhoneNumber(@NonNull String phoneNumber, @NonNull String verificationCode, @NonNull String realmOrConnection) { + ParameterBuilder builder = ParameterBuilder.newAuthenticationBuilder() .setClientId(getClientId()) - .setConnection(connection) - .asDictionary(); - return loginWithResourceOwner(parameters); + .set(USERNAME_KEY, phoneNumber); + + if (auth0.isOIDCConformant()) { + Map parameters = builder + .setGrantType(GRANT_TYPE_PASSWORDLESS_OTP) + .set(ONE_TIME_PASSWORD_KEY, verificationCode) + .setRealm(realmOrConnection) + .asDictionary(); + return loginWithToken(parameters); + } else { + Map parameters = builder + .setGrantType(GRANT_TYPE_PASSWORD) + .set(PASSWORD_KEY, verificationCode) + .setConnection(realmOrConnection) + .asDictionary(); + return loginWithResourceOwner(parameters); + } } /** * Log in a user using a phone number and a verification code received via SMS (Part of passwordless login flow). + * How the user is logged in depends on the {@link Auth0#isOIDCConformant()} flag. If this flag is set to true, your Application requires to have the Passwordless OTP Grant Type enabled. + * If this flag is set to false, the Resource Owner Legacy Grant Type must be enabled instead. * By default it will try to authenticate using the "sms" connection. * Example usage: *
@@ -381,7 +396,8 @@ public AuthenticationRequest loginWithPhoneNumber(@NonNull String phoneNumber, @
     /**
      * Log in a user using an email and a verification code received via Email (Part of passwordless login flow).
      * The default scope used is 'openid'.
-     * Requires your Application to have the Resource Owner Legacy Grant Type enabled. See Client Grant Types to learn how to enable it.
+     * How the user is logged in depends on the {@link Auth0#isOIDCConformant()} flag. If this flag is set to true, your Application requires to have the Passwordless OTP Grant Type enabled.
+     * If this flag is set to false, the Resource Owner Legacy Grant Type must be enabled instead.
      * Example usage:
      * 
      * {@code
@@ -396,26 +412,39 @@ public AuthenticationRequest loginWithPhoneNumber(@NonNull String phoneNumber, @
      * }
      * 
* - * @param email where the user received the verification code - * @param verificationCode sent by Auth0 via Email - * @param connection to end the passwordless authentication on + * @param email where the user received the verification code + * @param verificationCode sent by Auth0 via Email + * @param realmOrConnection to end the passwordless authentication on * @return a request to configure and start that will yield {@link Credentials} */ @SuppressWarnings("WeakerAccess") - public AuthenticationRequest loginWithEmail(@NonNull String email, @NonNull String verificationCode, @NonNull String connection) { - Map parameters = ParameterBuilder.newAuthenticationBuilder() - .set(USERNAME_KEY, email) - .set(PASSWORD_KEY, verificationCode) - .setGrantType(GRANT_TYPE_PASSWORD) + public AuthenticationRequest loginWithEmail(@NonNull String email, @NonNull String verificationCode, @NonNull String realmOrConnection) { + ParameterBuilder builder = ParameterBuilder.newAuthenticationBuilder() .setClientId(getClientId()) - .setConnection(connection) - .asDictionary(); - return loginWithResourceOwner(parameters); + .set(USERNAME_KEY, email); + + if (auth0.isOIDCConformant()) { + Map parameters = builder + .setGrantType(GRANT_TYPE_PASSWORDLESS_OTP) + .set(ONE_TIME_PASSWORD_KEY, verificationCode) + .setRealm(realmOrConnection) + .asDictionary(); + return loginWithToken(parameters); + } else { + Map parameters = builder + .setGrantType(GRANT_TYPE_PASSWORD) + .set(PASSWORD_KEY, verificationCode) + .setConnection(realmOrConnection) + .asDictionary(); + return loginWithResourceOwner(parameters); + } } /** * Log in a user using an email and a verification code received via Email (Part of passwordless login flow) * By default it will try to authenticate using the "email" connection. + * How the user is logged in depends on the {@link Auth0#isOIDCConformant()} flag. If this flag is set to true, your Application requires to have the Passwordless OTP Grant Type enabled. + * If this flag is set to false, the Resource Owner Legacy Grant Type must be enabled instead. * Example usage: *
      * {@code
@@ -831,8 +860,9 @@ public DelegationRequest> delegationWithIdToken(@NonNull Str
     }
 
     /**
-     * Start a passwordless flow with an Email
-     * Requires your Application to have the Resource Owner Legacy Grant Type enabled. See Client Grant Types to learn how to enable it.
+     * Start a passwordless flow with an Email.
+     * How the user is logged in depends on the {@link Auth0#isOIDCConformant()} flag. If this flag is set to true, your Application requires to have the Passwordless OTP Grant Type enabled.
+     * If this flag is set to false, the Resource Owner Legacy Grant Type must be enabled instead.
      * Example usage:
      * 
      * {@code
@@ -867,7 +897,8 @@ public ParameterizableRequest passwordlessWithEma
     /**
      * Start a passwordless flow with an Email
      * By default it will try to authenticate using "email" connection.
-     * Requires your Application to have the Resource Owner Legacy Grant Type enabled. See Client Grant Types to learn how to enable it.
+     * How the user is logged in depends on the {@link Auth0#isOIDCConformant()} flag. If this flag is set to true, your Application requires to have the Passwordless OTP Grant Type enabled.
+     * If this flag is set to false, the Resource Owner Legacy Grant Type must be enabled instead.
      * Example usage:
      * 
      * {@code
@@ -893,7 +924,8 @@ public ParameterizableRequest passwordlessWithEma
 
     /**
      * Start a passwordless flow with a SMS
-     * Requires your Application to have the Resource Owner Legacy Grant Type enabled. See Client Grant Types to learn how to enable it.
+     * How the user is logged in depends on the {@link Auth0#isOIDCConformant()} flag. If this flag is set to true, your Application requires to have the Passwordless OTP Grant Type enabled.
+     * If this flag is set to false, the Resource Owner Legacy Grant Type must be enabled instead.
      * Example usage:
      * 
      * {@code
@@ -927,7 +959,9 @@ public ParameterizableRequest passwordlessWithSMS
     /**
      * Start a passwordless flow with a SMS
      * By default it will try to authenticate using the "sms" connection.
-     * Requires your Application to have the Resource Owner Legacy Grant Type enabled. See Client Grant Types to learn how to enable it.
+     * How the user is logged in depends on the {@link Auth0#isOIDCConformant()} flag. If this flag is set to true, your Application requires to have the Passwordless OTP Grant Type enabled.
+     * If this flag is set to false, the Resource Owner Legacy Grant Type must be enabled instead.
+     * See Client Grant Types to learn how to enable it.
      * Example usage:
      * 
      * {@code
diff --git a/auth0/src/main/java/com/auth0/android/authentication/ParameterBuilder.java b/auth0/src/main/java/com/auth0/android/authentication/ParameterBuilder.java
index 26b64ec21..4c3b9ac2d 100755
--- a/auth0/src/main/java/com/auth0/android/authentication/ParameterBuilder.java
+++ b/auth0/src/main/java/com/auth0/android/authentication/ParameterBuilder.java
@@ -54,6 +54,7 @@ public class ParameterBuilder {
     public static final String GRANT_TYPE_JWT = "urn:ietf:params:oauth:grant-type:jwt-bearer";
     public static final String GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code";
     public static final String GRANT_TYPE_MFA_OTP = "http://auth0.com/oauth/grant-type/mfa-otp";
+    public static final String GRANT_TYPE_PASSWORDLESS_OTP = "http://auth0.com/oauth/grant-type/passwordless/otp";
 
     public static final String SCOPE_OPENID = "openid";
     public static final String SCOPE_OFFLINE_ACCESS = "openid offline_access";

From 0307fc47b4777965dc3a9e6319b345117bdf0b4a Mon Sep 17 00:00:00 2001
From: Luciano Balmaceda 
Date: Fri, 6 Dec 2019 14:27:46 -0300
Subject: [PATCH 2/3] Add new tests for the new passwordless endpoint

---
 .../AuthenticationAPIClientTest.java          | 164 ++++++++++++++++++
 1 file changed, 164 insertions(+)

diff --git a/auth0/src/test/java/com/auth0/android/authentication/AuthenticationAPIClientTest.java b/auth0/src/test/java/com/auth0/android/authentication/AuthenticationAPIClientTest.java
index 4eee5c047..e6e150a59 100755
--- a/auth0/src/test/java/com/auth0/android/authentication/AuthenticationAPIClientTest.java
+++ b/auth0/src/test/java/com/auth0/android/authentication/AuthenticationAPIClientTest.java
@@ -421,6 +421,164 @@ public void shouldLoginWithOAuthAccessTokenSync() throws Exception {
         assertThat(credentials, is(notNullValue()));
     }
 
+    @Test
+    public void shouldLoginWithPhoneNumberWithCustomConnectionWithOTPGrantIfOIDCConformant() throws Exception {
+        mockAPI.willReturnSuccessfulLogin();
+
+        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
+        auth0.setOIDCConformant(true);
+        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);
+
+        final MockAuthenticationCallback callback = new MockAuthenticationCallback<>();
+        client.loginWithPhoneNumber("+10101010101", "1234", MY_CONNECTION)
+                .start(callback);
+
+        final RecordedRequest request = mockAPI.takeRequest();
+        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
+        assertThat(request.getPath(), equalTo("/oauth/token"));
+
+        Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORDLESS_OTP));
+        assertThat(body, hasEntry("realm", MY_CONNECTION));
+        assertThat(body, hasEntry("username", "+10101010101"));
+        assertThat(body, hasEntry("otp", "1234"));
+        assertThat(body, hasEntry("scope", OPENID));
+
+        assertThat(callback, hasPayloadOfType(Credentials.class));
+    }
+
+    @Test
+    public void shouldLoginWithPhoneNumberWithOTPGrantIfOIDCConformant() throws Exception {
+        mockAPI.willReturnSuccessfulLogin();
+
+        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
+        auth0.setOIDCConformant(true);
+        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);
+
+        final MockAuthenticationCallback callback = new MockAuthenticationCallback<>();
+        client.loginWithPhoneNumber("+10101010101", "1234")
+                .start(callback);
+
+        final RecordedRequest request = mockAPI.takeRequest();
+        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
+        assertThat(request.getPath(), equalTo("/oauth/token"));
+
+        Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORDLESS_OTP));
+        assertThat(body, hasEntry("realm", "sms"));
+        assertThat(body, hasEntry("username", "+10101010101"));
+        assertThat(body, hasEntry("otp", "1234"));
+        assertThat(body, hasEntry("scope", OPENID));
+
+        assertThat(callback, hasPayloadOfType(Credentials.class));
+    }
+
+    @Test
+    public void shouldLoginWithPhoneNumberSyncWithOTPGrantIfOIDCConformant() throws Exception {
+        mockAPI.willReturnSuccessfulLogin();
+
+        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
+        auth0.setOIDCConformant(true);
+        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);
+
+        final Credentials credentials = client
+                .loginWithPhoneNumber("+10101010101", "1234")
+                .execute();
+
+        final RecordedRequest request = mockAPI.takeRequest();
+        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
+        assertThat(request.getPath(), equalTo("/oauth/token"));
+
+        Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORDLESS_OTP));
+        assertThat(body, hasEntry("realm", "sms"));
+        assertThat(body, hasEntry("username", "+10101010101"));
+        assertThat(body, hasEntry("otp", "1234"));
+        assertThat(body, hasEntry("scope", OPENID));
+
+        assertThat(credentials, is(notNullValue()));
+    }
+
+    @Test
+    public void shouldLoginWithEmailOnlyWithCustomConnectionWithOTPGrantIfOIDCConformant() throws Exception {
+        mockAPI.willReturnSuccessfulLogin();
+
+        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
+        auth0.setOIDCConformant(true);
+        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);
+
+        final MockAuthenticationCallback callback = new MockAuthenticationCallback<>();
+        client.loginWithEmail(SUPPORT_AUTH0_COM, "1234", MY_CONNECTION)
+                .start(callback);
+
+        final RecordedRequest request = mockAPI.takeRequest();
+        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
+        assertThat(request.getPath(), equalTo("/oauth/token"));
+
+        Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORDLESS_OTP));
+        assertThat(body, hasEntry("realm", MY_CONNECTION));
+        assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
+        assertThat(body, hasEntry("otp", "1234"));
+        assertThat(body, hasEntry("scope", OPENID));
+
+        assertThat(callback, hasPayloadOfType(Credentials.class));
+    }
+
+    @Test
+    public void shouldLoginWithEmailOnlyWithOTPGrantIfOIDCConformant() throws Exception {
+        mockAPI.willReturnSuccessfulLogin();
+
+        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
+        auth0.setOIDCConformant(true);
+        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);
+
+        final MockAuthenticationCallback callback = new MockAuthenticationCallback<>();
+        client.loginWithEmail(SUPPORT_AUTH0_COM, "1234")
+                .start(callback);
+
+        final RecordedRequest request = mockAPI.takeRequest();
+        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
+        assertThat(request.getPath(), equalTo("/oauth/token"));
+
+        Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORDLESS_OTP));
+        assertThat(body, hasEntry("realm", "email"));
+        assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
+        assertThat(body, hasEntry("otp", "1234"));
+        assertThat(body, hasEntry("scope", OPENID));
+
+        assertThat(callback, hasPayloadOfType(Credentials.class));
+    }
+
+    @Test
+    public void shouldLoginWithEmailOnlySyncWithOTPGrantIfOIDCConformant() throws Exception {
+        mockAPI
+                .willReturnSuccessfulLogin()
+                .willReturnTokenInfo();
+
+        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
+        auth0.setOIDCConformant(true);
+        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);
+
+        final Credentials credentials = client
+                .loginWithEmail(SUPPORT_AUTH0_COM, "1234")
+                .execute();
+
+        final RecordedRequest request = mockAPI.takeRequest();
+        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
+        assertThat(request.getPath(), equalTo("/oauth/token"));
+
+        Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORDLESS_OTP));
+        assertThat(body, hasEntry("realm", "email"));
+        assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
+        assertThat(body, hasEntry("otp", "1234"));
+        assertThat(body, hasEntry("scope", OPENID));
+
+        assertThat(credentials, is(notNullValue()));
+    }
+
     @Test
     public void shouldLoginWithPhoneNumberWithCustomConnection() throws Exception {
         mockAPI.willReturnSuccessfulLogin();
@@ -434,6 +592,7 @@ public void shouldLoginWithPhoneNumberWithCustomConnection() throws Exception {
         assertThat(request.getPath(), equalTo("/oauth/ro"));
 
         Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORD));
         assertThat(body, hasEntry("connection", MY_CONNECTION));
         assertThat(body, hasEntry("username", "+10101010101"));
         assertThat(body, hasEntry("password", "1234"));
@@ -455,6 +614,7 @@ public void shouldLoginWithPhoneNumber() throws Exception {
         assertThat(request.getPath(), equalTo("/oauth/ro"));
 
         Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORD));
         assertThat(body, hasEntry("connection", "sms"));
         assertThat(body, hasEntry("username", "+10101010101"));
         assertThat(body, hasEntry("password", "1234"));
@@ -476,6 +636,7 @@ public void shouldLoginWithPhoneNumberSync() throws Exception {
         assertThat(request.getPath(), equalTo("/oauth/ro"));
 
         Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORD));
         assertThat(body, hasEntry("connection", "sms"));
         assertThat(body, hasEntry("username", "+10101010101"));
         assertThat(body, hasEntry("password", "1234"));
@@ -497,6 +658,7 @@ public void shouldLoginWithEmailOnlyWithCustomConnection() throws Exception {
         assertThat(request.getPath(), equalTo("/oauth/ro"));
 
         Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORD));
         assertThat(body, hasEntry("connection", MY_CONNECTION));
         assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
         assertThat(body, hasEntry("password", "1234"));
@@ -518,6 +680,7 @@ public void shouldLoginWithEmailOnly() throws Exception {
         assertThat(request.getPath(), equalTo("/oauth/ro"));
 
         Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORD));
         assertThat(body, hasEntry("connection", "email"));
         assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
         assertThat(body, hasEntry("password", "1234"));
@@ -541,6 +704,7 @@ public void shouldLoginWithEmailOnlySync() throws Exception {
         assertThat(request.getPath(), equalTo("/oauth/ro"));
 
         Map body = bodyFromRequest(request);
+        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_PASSWORD));
         assertThat(body, hasEntry("connection", "email"));
         assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
         assertThat(body, hasEntry("password", "1234"));

From f276db5765d7d06a3ecd58f9a693837ab6aa90c7 Mon Sep 17 00:00:00 2001
From: Luciano Balmaceda 
Date: Fri, 6 Dec 2019 14:28:20 -0300
Subject: [PATCH 3/3] clarify that OIDC applications can now use the new
 passwordless endpoint

---
 README.md                                        | 4 ++--
 auth0/src/main/java/com/auth0/android/Auth0.java | 9 +++++++++
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 302e02ebb..435590f5d 100644
--- a/README.md
+++ b/README.md
@@ -88,7 +88,7 @@ account.setOIDCConformant(true);
 //Use the account in the API clients
 ```
 
-Passwordless authentication *cannot be used* with this flag set to `true`. For more information, please see the [OIDC adoption guide](https://auth0.com/docs/api-auth/tutorials/adoption).
+For more information, please see the [OIDC adoption guide](https://auth0.com/docs/api-auth/tutorials/adoption).
 
 
 ### Authentication with Universal Login
@@ -436,7 +436,7 @@ authentication
 
 #### Passwordless Login
 
-This feature requires your Application to have the *Resource Owner* Legacy Grant Type enabled. Check [this article](https://auth0.com/docs/clients/client-grant-types) to learn how to enable it. Note that Passwordless authentication *cannot be used* with the [OIDC Conformant Mode](#oidc-conformant-mode) enabled.
+This feature requires your Application to have a specific Grant Type enabled. If the [OIDC Conformant flag](#OIDC-Conformant-Mode) is enabled, the required Grant Type is *Passwordless OTP*. If instead the flag is disabled, the required Grant Type is *Resource Owner*. Check [this article](https://auth0.com/docs/clients/client-grant-types) to learn how to enable it.
 
 Passwordless it's a 2 steps flow:
 
diff --git a/auth0/src/main/java/com/auth0/android/Auth0.java b/auth0/src/main/java/com/auth0/android/Auth0.java
index 436b2e8dd..76eca2aba 100755
--- a/auth0/src/main/java/com/auth0/android/Auth0.java
+++ b/auth0/src/main/java/com/auth0/android/Auth0.java
@@ -31,6 +31,7 @@
 
 import com.auth0.android.auth0.BuildConfig;
 import com.auth0.android.authentication.AuthenticationAPIClient;
+import com.auth0.android.authentication.PasswordlessType;
 import com.auth0.android.util.Telemetry;
 import com.squareup.okhttp.HttpUrl;
 
@@ -208,6 +209,14 @@ public void doNotSendTelemetry() {
      * 
  • {@link AuthenticationAPIClient#signUp(String, String, String)}
  • *
  • {@link AuthenticationAPIClient#signUp(String, String, String, String)}
  • *
  • {@link AuthenticationAPIClient#renewAuth(String)}
  • + *
  • {@link AuthenticationAPIClient#passwordlessWithSMS(String, PasswordlessType, String)}
  • + *
  • {@link AuthenticationAPIClient#passwordlessWithSMS(String, PasswordlessType)}
  • + *
  • {@link AuthenticationAPIClient#passwordlessWithEmail(String, PasswordlessType)}
  • + *
  • {@link AuthenticationAPIClient#passwordlessWithEmail(String, PasswordlessType, String)}
  • + *
  • {@link AuthenticationAPIClient#loginWithPhoneNumber(String, String)}
  • + *
  • {@link AuthenticationAPIClient#loginWithPhoneNumber(String, String, String)}
  • + *
  • {@link AuthenticationAPIClient#loginWithEmail(String, String)}
  • + *
  • {@link AuthenticationAPIClient#loginWithEmail(String, String, String)}
  • * * * @param enabled if Lock will use the Legacy Authentication API or the new OIDC Conformant Authentication API.