Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update LockCallback and AuthenticationCallback [SDK-2480] #621

Merged
merged 4 commits into from
May 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- /usr/local/android-sdk-linux/extras
- run:
name: Run checks
command: ./gradlew clean test lint --continue --console=plain --max-workers=4
command: ./gradlew clean test lint --continue --console=plain --max-workers=3
- store_artifacts:
path: lib/build/reports
destination: reports
Expand Down
53 changes: 48 additions & 5 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ android {
}
```

## Changes to the AndroidManifest file
In the previous version you had to declare the Lock activities you planned to use. These activities are now declared internally by the library with intent filters configured using the Manifest Placeholders that you provide for the Domain and Scheme. The Manifest Merger tool will process these and include them as part of your Android application.

If your `AndroidManifest.xml` file includes declarations for `LockActivity`, `PasswordlessLockActivity` or `CountryCodeActivity`, you should remove them to avoid duplicated intent filter declarations.

If you are using a custom style for the theme or need to override the intent-filter declarations in any of these activities, you will have to declare an activity with the same component name and annotate it with `tools:node="replace"`.

Find details about the merging rules that will be used in the [Android Manifest Merger article](https://developer.android.com/studio/build/manifest-merge).

## Changes to the Public API
As part of removing legacy APIs or authentication flows no longer recommended for mobile clients, the following features are no longer available:

Expand All @@ -39,20 +48,54 @@ As part of removing legacy APIs or authentication flows no longer recommended fo

Continue reading for the detail of classes and methods that were impacted.

## Changes to the AndroidManifest file
In the previous version you had to declare the Lock activities you planned to use. These activities are now declared internally by the library with intent filters configured using the Manifest Placeholders that you provide for the Domain and Scheme. The Manifest Merger tool will process these and include them as part of your Android application.
### Updated Callbacks
The widget requires a callback to receive the results in. The interface for this is `LockCallback`, which takes either an event or an error. The `onError` method got updated to receive an `AuthenticationException` instead of `LockException`. This change will help developers extract the *code* and *description* of the error and understand better what went wrong and how to recover from it.

If your `AndroidManifest.xml` file includes declarations for `LockActivity`, `PasswordlessLockActivity` or `CountryCodeActivity`, you should remove them to avoid duplicated intent filter declarations.
The change impacts the abstract subclass `AuthenticationCallback`. Additionally, this class no longer has an `onCanceled` method. If you need to handle this scenario you have two options:
- Implement `LockCallback` and handle the different event types, checking for `LockEvent.CANCELED`.
- Implement `AuthenticationCallback` and check the received exception using the `AuthenticationException#isCanceled()` method.

If you are using a custom style for the theme or need to override the intent-filter declarations in any of these activities, you will have to declare an activity with the same component name and annotate it with `tools:node="replace"`.
```kotlin
// Before
val callback: LockCallback = object : AuthenticationCallback() {
override fun onAuthentication(credentials: Credentials) {
// Authenticated
}

Find details about the merging rules that will be used in the [Android Manifest Merger article](https://developer.android.com/studio/build/manifest-merge).
override fun onCanceled() {
// Canceled
}

override fun onError(error: LockException) {
// Another error. Check code & description.
}
}

// After
val callback: LockCallback = object : AuthenticationCallback() {
override fun onAuthentication(credentials: Credentials) {
// Authenticated
}

override fun onError(error: AuthenticationException) {
if (error.isCanceled) {
// Canceled
} else {
// Another error. Check code & description.
}
}
}
```

### Removed classes
- `VoidCallback` is no longer available. Please, use `Callback<Void, AuthenticationException>` instead.
- `LockException` is no longer available. This impacts the `LockCallback` and `AuthenticationCallback` classes. Please, use `AuthenticationException` instead.

### Removed methods

#### From class `AuthenticationCallback`
- Removed `public void onCanceled()`. Instead, an exception will be raised through the `public void onError(AuthenticationException)` method. Check for this scenario using the `AuthenticationException#isCanceled()` method.

#### From class `Lock.Builder`
- Removed `public Builder useBrowser(boolean)`. The library will always use a third party browser app instead of a Web View to authenticate. No replacement is available.
- Removed `public Builder useImplicitGrant(boolean)`. The library will always use the "Proof Key for Code Exchange" (PKCE) flow. Your application must be configured with the type "Native" and the "OIDC Conformant" switch ON. No replacement is available.
Expand Down
12 changes: 2 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,7 @@ class MyActivity : AppCompatActivity() {
// Authenticated
}

override fun onCanceled() {
// User pressed back and closed Lock
}

override fun onError(error: LockException) {
override fun onError(error: AuthenticationException) {
// An exception occurred
}
}
Expand Down Expand Up @@ -195,11 +191,7 @@ class MyActivity : AppCompatActivity() {
// Authenticated
}

override fun onCanceled() {
// User pressed back and closed Lock
}

override fun onError(error: LockException) {
override fun onError(error: AuthenticationException) {
// An exception occurred
}
}
Expand Down
13 changes: 6 additions & 7 deletions app/src/main/java/com/auth0/android/lock/app/DemoActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import com.auth0.android.Auth0
import com.auth0.android.authentication.AuthenticationException
import com.auth0.android.callback.Callback
import com.auth0.android.lock.*
import com.auth0.android.lock.utils.LockException
import com.auth0.android.provider.WebAuthProvider.login
import com.auth0.android.provider.WebAuthProvider.logout
import com.auth0.android.result.Credentials
Expand Down Expand Up @@ -238,12 +237,12 @@ class DemoActivity : AppCompatActivity() {
showResult("OK > " + credentials.accessToken)
}

override fun onCanceled() {
showResult("User pressed back.")
}

override fun onError(error: LockException) {
showResult(error.message.orEmpty())
override fun onError(error: AuthenticationException) {
if (error.isCanceled) {
showResult("User pressed back.")
} else {
showResult(error.getDescription())
}
}
}
private val loginCallback: Callback<Credentials, AuthenticationException> = object : Callback<Credentials, AuthenticationException> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,10 @@
package com.auth0.android.lock;

import android.content.Intent;
import android.util.Log;

import androidx.annotation.NonNull;

import com.auth0.android.authentication.AuthenticationException;
import com.auth0.android.lock.utils.LockException;
import com.auth0.android.result.Credentials;

import java.util.Date;
Expand All @@ -42,32 +40,24 @@
*/
public abstract class AuthenticationCallback implements LockCallback {

private static final String TAG = AuthenticationCallback.class.getSimpleName();

/**
* Called when the authentication flow finished successfully.
*
* @param credentials with the tokens.
*/
public abstract void onAuthentication(@NonNull Credentials credentials);

/**
* Called when the user goes back and closes the activity, without using an Authentication flow.
*/
public abstract void onCanceled();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AuthenticationCallback is a subclass of LockCallback. The onCanceled is now merged into onError for those developers passing an AuthenticationCallback implementation (what we document and recommend).


@Override
public void onEvent(@LockEvent int event, @NonNull Intent data) {
switch (event) {
case LockEvent.CANCELED:
onCanceled();
break;
case LockEvent.AUTHENTICATION:
parseAuthentication(data);
break;
case LockEvent.RESET_PASSWORD:
case LockEvent.SIGN_UP:
break;
if (data.hasExtra(Constants.EXCEPTION_EXTRA)) {
onError((AuthenticationException) data.getSerializableExtra(Constants.EXCEPTION_EXTRA));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any exception available would be raised through onError immediately

return;
}
if (event == LockEvent.AUTHENTICATION) {
Credentials credentials = extractCredentials(data);
onAuthentication(credentials);
} else if (event == LockEvent.CANCELED) {
onError(new AuthenticationException("a0.authentication_canceled", "The user pressed back"));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the event is "canceled", then raise an exception with the specific code that represents this. This is only for AuthenticationException. LockCallback would still receive this event and is up to the dev to handle (this advanced scenario remains available)

}
}

Expand All @@ -76,21 +66,13 @@ public void onEvent(@LockEvent int event, @NonNull Intent data) {
*
* @param data the intent received at the end of the login process.
*/
private void parseAuthentication(Intent data) {
if (data.hasExtra(Constants.EXCEPTION_EXTRA)) {
AuthenticationException error = (AuthenticationException) data.getSerializableExtra(Constants.EXCEPTION_EXTRA);
onError(new LockException(error));
return;
}
private Credentials extractCredentials(Intent data) {
String idToken = data.getStringExtra(Constants.ID_TOKEN_EXTRA);
String accessToken = data.getStringExtra(Constants.ACCESS_TOKEN_EXTRA);
String tokenType = data.getStringExtra(Constants.TOKEN_TYPE_EXTRA);
String refreshToken = data.getStringExtra(Constants.REFRESH_TOKEN_EXTRA);
Date expiresAt = (Date) data.getSerializableExtra(Constants.EXPIRES_AT_EXTRA);
String scope = data.getStringExtra(Constants.SCOPE_EXTRA);
Credentials credentials = new Credentials(idToken, accessToken, tokenType, refreshToken, expiresAt, scope);

Log.d(TAG, "User authenticated!");
onAuthentication(credentials);
return new Credentials(idToken, accessToken, tokenType, refreshToken, expiresAt, scope);
}
}
13 changes: 6 additions & 7 deletions lib/src/main/java/com/auth0/android/lock/Lock.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import com.auth0.android.lock.internal.configuration.Options;
import com.auth0.android.lock.internal.configuration.Theme;
import com.auth0.android.lock.provider.AuthResolver;
import com.auth0.android.lock.utils.LockException;
import com.auth0.android.lock.utils.SignUpField;
import com.auth0.android.provider.AuthHandler;
import com.auth0.android.provider.CustomTabsOptions;
Expand Down Expand Up @@ -148,15 +147,15 @@ private void initialize(@NonNull Context context) {
}

private void processEvent(@NonNull Intent data) {
if (data.hasExtra(Constants.EXCEPTION_EXTRA)) {
callback.onError((AuthenticationException) data.getSerializableExtra(Constants.EXCEPTION_EXTRA));
return;
}
String action = data.getAction();
switch (action) {
case Constants.AUTHENTICATION_ACTION:
Log.v(TAG, "AUTHENTICATION action received in our BroadcastReceiver");
if (data.hasExtra(Constants.EXCEPTION_EXTRA)) {
callback.onError(new LockException((AuthenticationException) data.getSerializableExtra(Constants.EXCEPTION_EXTRA)));
} else {
callback.onEvent(LockEvent.AUTHENTICATION, data);
}
callback.onEvent(LockEvent.AUTHENTICATION, data);
break;
case Constants.SIGN_UP_ACTION:
Log.v(TAG, "SIGN_UP action received in our BroadcastReceiver");
Expand All @@ -168,7 +167,7 @@ private void processEvent(@NonNull Intent data) {
break;
case Constants.INVALID_CONFIGURATION_ACTION:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a "public" event type for this. So we raise an exception instead.

Log.v(TAG, "INVALID_CONFIGURATION_ACTION action received in our BroadcastReceiver");
callback.onError(new LockException(data.getStringExtra(Constants.ERROR_EXTRA)));
callback.onError(new AuthenticationException("a0.invalid_configuration", data.getStringExtra(Constants.ERROR_EXTRA)));
break;
}
}
Expand Down
5 changes: 3 additions & 2 deletions lib/src/main/java/com/auth0/android/lock/LockCallback.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@
package com.auth0.android.lock;

import android.content.Intent;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;

import com.auth0.android.lock.utils.LockException;
import com.auth0.android.authentication.AuthenticationException;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
Expand Down Expand Up @@ -68,5 +69,5 @@ public interface LockCallback {
*
* @param error describing what happened.
*/
void onError(@NonNull LockException error);
void onError(@NonNull AuthenticationException error);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes the type of exception. Helps to deliver the actual exception and not wrapping everything again.

}
15 changes: 7 additions & 8 deletions lib/src/main/java/com/auth0/android/lock/PasswordlessLock.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import com.auth0.android.lock.internal.configuration.Options;
import com.auth0.android.lock.internal.configuration.Theme;
import com.auth0.android.lock.provider.AuthResolver;
import com.auth0.android.lock.utils.LockException;
import com.auth0.android.provider.AuthHandler;
import com.auth0.android.provider.CustomTabsOptions;
import com.auth0.android.util.Auth0UserAgent;
Expand Down Expand Up @@ -146,24 +145,24 @@ private void initialize(Context context) {
lbm.registerReceiver(this.receiver, filter);
}

private void processEvent(Intent data) {
private void processEvent(@NonNull Intent data) {
if (data.hasExtra(Constants.EXCEPTION_EXTRA)) {
callback.onError((AuthenticationException) data.getSerializableExtra(Constants.EXCEPTION_EXTRA));
return;
}
String action = data.getAction();
switch (action) {
case Constants.AUTHENTICATION_ACTION:
Log.v(TAG, "AUTHENTICATION action received in our BroadcastReceiver");
if (data.hasExtra(Constants.EXCEPTION_EXTRA)) {
callback.onError(new LockException((AuthenticationException) data.getSerializableExtra(Constants.EXCEPTION_EXTRA)));
} else {
callback.onEvent(LockEvent.AUTHENTICATION, data);
}
callback.onEvent(LockEvent.AUTHENTICATION, data);
break;
case Constants.CANCELED_ACTION:
Log.v(TAG, "CANCELED action received in our BroadcastReceiver");
callback.onEvent(LockEvent.CANCELED, new Intent());
break;
case Constants.INVALID_CONFIGURATION_ACTION:
Log.v(TAG, "INVALID_CONFIGURATION_ACTION action received in our BroadcastReceiver");
callback.onError(new LockException(data.getStringExtra(Constants.ERROR_EXTRA)));
callback.onError(new AuthenticationException("a0.invalid_configuration", data.getStringExtra(Constants.ERROR_EXTRA)));
break;
}
}
Expand Down
42 changes: 0 additions & 42 deletions lib/src/main/java/com/auth0/android/lock/utils/LockException.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public void shouldCallOnCanceled() {
callback.onEvent(LockEvent.CANCELED, data);

assertThat(callback, isCanceled());
assertThat(callback, hasNoError());
assertThat(callback, hasError());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ public void describeTo(Description description) {
}

public static AuthenticationCallbackMatcher isCanceled() {
return new AuthenticationCallbackMatcher(is(nullValue(Credentials.class)), equalTo(true), is(nullValue(Throwable.class)));
return new AuthenticationCallbackMatcher(is(nullValue(Credentials.class)), equalTo(true), is(notNullValue(Throwable.class)));
}

public static AuthenticationCallbackMatcher hasAuthentication() {
return new AuthenticationCallbackMatcher(is(notNullValue(Credentials.class)), equalTo(false), is(nullValue(Throwable.class)));
}

public static AuthenticationCallbackMatcher hasError() {
return new AuthenticationCallbackMatcher(is(nullValue(Credentials.class)), equalTo(false), is(notNullValue(Throwable.class)));
return new AuthenticationCallbackMatcher(is(nullValue(Credentials.class)), any(Boolean.class), is(notNullValue(Throwable.class)));
}

public static AuthenticationCallbackMatcher hasNoError() {
Expand Down
Loading