Skip to content

Commit 913c1ab

Browse files
Copilotpmathew92
andcommitted
Implement ephemeral session support for Custom Tabs
- Add ephemeralBrowsingEnabled field to CustomTabsOptions - Add withEphemeralBrowsingEnabled() method to CustomTabsOptions.Builder - Update toIntent() method to call setEphemeralBrowsingEnabled() - Update Parcelable implementation for new field - Add enableEphemeralSession() method to WebAuthProvider.Builder - Add comprehensive unit tests for new functionality - Verify backward compatibility with default behavior Co-authored-by: pmathew92 <17837162+pmathew92@users.noreply.github.com>
1 parent a1e4d72 commit 913c1ab

File tree

4 files changed

+139
-2
lines changed

4 files changed

+139
-2
lines changed

auth0/src/main/java/com/auth0/android/provider/CustomTabsOptions.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,16 @@ public class CustomTabsOptions implements Parcelable {
3030
@ColorRes
3131
private final int toolbarColor;
3232
private final BrowserPicker browserPicker;
33+
private final boolean ephemeralBrowsingEnabled;
3334

3435
@Nullable
3536
private final List<String> disabledCustomTabsPackages;
3637

37-
private CustomTabsOptions(boolean showTitle, @ColorRes int toolbarColor, @NonNull BrowserPicker browserPicker, @Nullable List<String> disabledCustomTabsPackages) {
38+
private CustomTabsOptions(boolean showTitle, @ColorRes int toolbarColor, @NonNull BrowserPicker browserPicker, boolean ephemeralBrowsingEnabled, @Nullable List<String> disabledCustomTabsPackages) {
3839
this.showTitle = showTitle;
3940
this.toolbarColor = toolbarColor;
4041
this.browserPicker = browserPicker;
42+
this.ephemeralBrowsingEnabled = ephemeralBrowsingEnabled;
4143
this.disabledCustomTabsPackages = disabledCustomTabsPackages;
4244
}
4345

@@ -88,6 +90,9 @@ Intent toIntent(@NonNull Context context, @Nullable CustomTabsSession session) {
8890
.setToolbarColor(ContextCompat.getColor(context, toolbarColor));
8991
builder.setDefaultColorSchemeParams(colorBuilder.build());
9092
}
93+
if (ephemeralBrowsingEnabled) {
94+
builder.setEphemeralBrowsingEnabled(true);
95+
}
9196
return builder.build().intent;
9297
}
9398

@@ -107,6 +112,7 @@ protected CustomTabsOptions(@NonNull Parcel in) {
107112
showTitle = in.readByte() != 0;
108113
toolbarColor = in.readInt();
109114
browserPicker = in.readParcelable(BrowserPicker.class.getClassLoader());
115+
ephemeralBrowsingEnabled = in.readByte() != 0;
110116
disabledCustomTabsPackages = in.createStringArrayList();
111117
}
112118

@@ -115,6 +121,7 @@ public void writeToParcel(@NonNull Parcel dest, int flags) {
115121
dest.writeByte((byte) (showTitle ? 1 : 0));
116122
dest.writeInt(toolbarColor);
117123
dest.writeParcelable(browserPicker, flags);
124+
dest.writeByte((byte) (ephemeralBrowsingEnabled ? 1 : 0));
118125
dest.writeStringList(disabledCustomTabsPackages);
119126
}
120127

@@ -141,6 +148,7 @@ public static class Builder {
141148
@ColorRes
142149
private int toolbarColor;
143150
private boolean showTitle;
151+
private boolean ephemeralBrowsingEnabled;
144152
@NonNull
145153
private BrowserPicker browserPicker;
146154

@@ -150,6 +158,7 @@ public static class Builder {
150158
Builder() {
151159
this.showTitle = false;
152160
this.toolbarColor = 0;
161+
this.ephemeralBrowsingEnabled = false;
153162
this.browserPicker = BrowserPicker.newBuilder().build();
154163
this.disabledCustomTabsPackages = null;
155164
}
@@ -179,6 +188,20 @@ public Builder showTitle(boolean showTitle) {
179188
return this;
180189
}
181190

191+
/**
192+
* Whether to enable ephemeral browsing for the Custom Tab session.
193+
* When enabled, the Custom Tab session will not persist browsing data, cookies, or history.
194+
* By default, ephemeral browsing is disabled.
195+
*
196+
* @param ephemeralBrowsingEnabled whether to enable ephemeral browsing or not.
197+
* @return this same builder instance.
198+
*/
199+
@NonNull
200+
public Builder withEphemeralBrowsingEnabled(boolean ephemeralBrowsingEnabled) {
201+
this.ephemeralBrowsingEnabled = ephemeralBrowsingEnabled;
202+
return this;
203+
}
204+
182205
/**
183206
* Filter the browser applications to launch the authentication on.
184207
* <p>
@@ -219,7 +242,7 @@ public Builder withDisabledCustomTabsPackages(List<String> disabledCustomTabsPac
219242
*/
220243
@NonNull
221244
public CustomTabsOptions build() {
222-
return new CustomTabsOptions(showTitle, toolbarColor, browserPicker, disabledCustomTabsPackages);
245+
return new CustomTabsOptions(showTitle, toolbarColor, browserPicker, ephemeralBrowsingEnabled, disabledCustomTabsPackages);
223246
}
224247
}
225248

auth0/src/main/java/com/auth0/android/provider/WebAuthProvider.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,20 @@ public object WebAuthProvider : SenderConstraining<WebAuthProvider> {
520520
return this
521521
}
522522

523+
/**
524+
* Enable ephemeral browsing session for the Custom Tab.
525+
* When enabled, the Custom Tab session will not persist browsing data, cookies, or history.
526+
* This enhances privacy and security by ensuring no session data is retained after authentication.
527+
*
528+
* @return the current builder instance
529+
*/
530+
public fun enableEphemeralSession(): Builder {
531+
ctOptions = CustomTabsOptions.newBuilder()
532+
.withEphemeralBrowsingEnabled(true)
533+
.build()
534+
return this
535+
}
536+
523537
/**
524538
* Launches the Login experience with a native feel (without address bar). For this to work,
525539
* you have to setup the app as trusted following the steps mentioned [here](https://github.com/auth0/Auth0.Android/blob/main/EXAMPLES.md#trusted-web-activity-experimental).

auth0/src/test/java/com/auth0/android/provider/CustomTabsOptionsTest.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public void shouldHaveDefaultValues() {
8383
assertThat(intent, is(notNullValue()));
8484
assertThat(intent.hasExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR), is(false));
8585
assertThat(intent.hasExtra(CustomTabsIntent.EXTRA_TITLE_VISIBILITY_STATE), is(true));
86+
assertThat(intent.hasExtra(CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED), is(false));
8687
assertThat(intent.getIntExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR, 0), is(0));
8788
assertThat(intent.getIntExtra(CustomTabsIntent.EXTRA_TITLE_VISIBILITY_STATE, CustomTabsIntent.NO_TITLE), is(CustomTabsIntent.NO_TITLE));
8889
assertThat(intent.getIntExtra(CustomTabsIntent.EXTRA_SHARE_STATE, CustomTabsIntent.SHARE_STATE_OFF), is(CustomTabsIntent.SHARE_STATE_OFF));
@@ -97,6 +98,7 @@ public void shouldHaveDefaultValues() {
9798
assertThat(parceledIntent, is(notNullValue()));
9899
assertThat(parceledIntent.hasExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR), is(false));
99100
assertThat(parceledIntent.hasExtra(CustomTabsIntent.EXTRA_TITLE_VISIBILITY_STATE), is(true));
101+
assertThat(parceledIntent.hasExtra(CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED), is(false));
100102
assertThat(parceledIntent.getIntExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR, 0), is(0));
101103
assertThat(parceledIntent.getIntExtra(CustomTabsIntent.EXTRA_TITLE_VISIBILITY_STATE, CustomTabsIntent.NO_TITLE), is(CustomTabsIntent.NO_TITLE));
102104
assertThat(parceledIntent.getIntExtra(CustomTabsIntent.EXTRA_SHARE_STATE, CustomTabsIntent.SHARE_STATE_OFF), is(CustomTabsIntent.SHARE_STATE_OFF));
@@ -224,4 +226,73 @@ public void shouldSetDisabledCustomTabPackages() {
224226
int resolvedColor = ContextCompat.getColor(activity, android.R.color.black);
225227
assertThat(intentWithToolbarExtra.getIntExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR, 0), is(resolvedColor));
226228
}
229+
230+
@Test
231+
public void shouldSetEphemeralBrowsingEnabled() {
232+
CustomTabsOptions options = CustomTabsOptions.newBuilder()
233+
.withEphemeralBrowsingEnabled(true)
234+
.build();
235+
assertThat(options, is(notNullValue()));
236+
237+
Intent intent = options.toIntent(context, null);
238+
239+
assertThat(intent, is(notNullValue()));
240+
assertThat(intent.hasExtra(CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED), is(true));
241+
assertThat(intent.getBooleanExtra(CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED, false), is(true));
242+
243+
Parcel parcel = Parcel.obtain();
244+
options.writeToParcel(parcel, 0);
245+
parcel.setDataPosition(0);
246+
CustomTabsOptions parceledOptions = CustomTabsOptions.CREATOR.createFromParcel(parcel);
247+
assertThat(parceledOptions, is(notNullValue()));
248+
249+
Intent parceledIntent = parceledOptions.toIntent(context, null);
250+
assertThat(parceledIntent, is(notNullValue()));
251+
assertThat(parceledIntent.hasExtra(CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED), is(true));
252+
assertThat(parceledIntent.getBooleanExtra(CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED, false), is(true));
253+
}
254+
255+
@Test
256+
public void shouldNotSetEphemeralBrowsingByDefault() {
257+
CustomTabsOptions options = CustomTabsOptions.newBuilder().build();
258+
assertThat(options, is(notNullValue()));
259+
260+
Intent intent = options.toIntent(context, null);
261+
262+
assertThat(intent, is(notNullValue()));
263+
assertThat(intent.hasExtra(CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED), is(false));
264+
265+
Parcel parcel = Parcel.obtain();
266+
options.writeToParcel(parcel, 0);
267+
parcel.setDataPosition(0);
268+
CustomTabsOptions parceledOptions = CustomTabsOptions.CREATOR.createFromParcel(parcel);
269+
assertThat(parceledOptions, is(notNullValue()));
270+
271+
Intent parceledIntent = parceledOptions.toIntent(context, null);
272+
assertThat(parceledIntent, is(notNullValue()));
273+
assertThat(parceledIntent.hasExtra(CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED), is(false));
274+
}
275+
276+
@Test
277+
public void shouldSetEphemeralBrowsingExplicitlyDisabled() {
278+
CustomTabsOptions options = CustomTabsOptions.newBuilder()
279+
.withEphemeralBrowsingEnabled(false)
280+
.build();
281+
assertThat(options, is(notNullValue()));
282+
283+
Intent intent = options.toIntent(context, null);
284+
285+
assertThat(intent, is(notNullValue()));
286+
assertThat(intent.hasExtra(CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED), is(false));
287+
288+
Parcel parcel = Parcel.obtain();
289+
options.writeToParcel(parcel, 0);
290+
parcel.setDataPosition(0);
291+
CustomTabsOptions parceledOptions = CustomTabsOptions.CREATOR.createFromParcel(parcel);
292+
assertThat(parceledOptions, is(notNullValue()));
293+
294+
Intent parceledIntent = parceledOptions.toIntent(context, null);
295+
assertThat(parceledIntent, is(notNullValue()));
296+
assertThat(parceledIntent.hasExtra(CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED), is(false));
297+
}
227298
}

auth0/src/test/java/com/auth0/android/provider/WebAuthProviderTest.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,35 @@ public class WebAuthProviderTest {
10591059
)
10601060
}
10611061

1062+
@Test
1063+
public fun shouldStartLoginWithEphemeralSession() {
1064+
login(account)
1065+
.enableEphemeralSession()
1066+
.start(activity, callback)
1067+
verify(activity).startActivity(intentCaptor.capture())
1068+
val intent = intentCaptor.firstValue
1069+
assertThat(intent, `is`(notNullValue()))
1070+
assertThat(
1071+
intent, IntentMatchers.hasComponent(
1072+
AuthenticationActivity::class.java.name
1073+
)
1074+
)
1075+
val extras = intentCaptor.firstValue.extras
1076+
assertThat(
1077+
extras?.containsKey(AuthenticationActivity.EXTRA_CT_OPTIONS),
1078+
`is`(true)
1079+
)
1080+
val customTabsOptions = extras?.getParcelable(AuthenticationActivity.EXTRA_CT_OPTIONS) as? CustomTabsOptions
1081+
assertThat(customTabsOptions, `is`(notNullValue()))
1082+
1083+
// Verify that ephemeral browsing is enabled by checking the intent that would be generated
1084+
val context = activity as Context
1085+
val testIntent = customTabsOptions?.toIntent(context, null)
1086+
assertThat(testIntent, `is`(notNullValue()))
1087+
assertThat(testIntent?.hasExtra(androidx.browser.customtabs.CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED), `is`(true))
1088+
assertThat(testIntent?.getBooleanExtra(androidx.browser.customtabs.CustomTabsIntent.EXTRA_EPHEMERAL_BROWSING_ENABLED, false), `is`(true))
1089+
}
1090+
10621091
@Test
10631092
public fun shouldStartLoginWithValidRequestCode() {
10641093
val credentials = Mockito.mock(

0 commit comments

Comments
 (0)