Skip to content

Commit f2dc873

Browse files
authored
[AppCheck] Add getLimitedUseToken support to AppCheckProvider (#8204)
Introduced the getLimitedUseToken() method to the AppCheckProvider interface and implemented it across the debug, Play Integrity, and reCAPTCHA Enterprise providers. The implementation ensures that token exchange requests include a "limited_use" flag, allowing for the generation of short-lived, single-use App Check tokens. Verified manually using debug provider
1 parent f5245c1 commit f2dc873

24 files changed

Lines changed: 258 additions & 22 deletions

File tree

appcheck/firebase-appcheck-debug-testing/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
- [unchanged] Updated to keep [app_check] SDK versions aligned.
4+
35
# 19.0.2
46

57
- [unchanged] Updated to keep [app_check] SDK versions aligned.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version=19.0.3
1+
version=19.1.0
22
latestReleasedVersion=19.0.2

appcheck/firebase-appcheck-debug/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
- [fixed] Fixed issue preventing limited use tokens from being correctly generated. (#8204)
4+
35
# 19.0.2
46

57
- [unchanged] Updated to keep [app_check] SDK versions aligned.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version=19.0.3
1+
version=19.1.0
22
latestReleasedVersion=19.0.2

appcheck/firebase-appcheck-debug/src/main/java/com/google/firebase/appcheck/debug/internal/DebugAppCheckProvider.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,22 @@ static Task<String> determineDebugSecret(
110110
@NonNull
111111
@Override
112112
public Task<AppCheckToken> getToken() {
113+
return getToken(/* isLimitedUseToken= */ false);
114+
}
115+
116+
@NonNull
117+
@Override
118+
public Task<AppCheckToken> getLimitedUseToken() {
119+
return getToken(/* isLimitedUseToken= */ true);
120+
}
121+
122+
private Task<AppCheckToken> getToken(boolean isLimitedUseToken) {
113123
return debugSecretTask
114124
.onSuccessTask(
115125
liteExecutor,
116126
debugSecret -> {
117-
ExchangeDebugTokenRequest request = new ExchangeDebugTokenRequest(debugSecret);
127+
ExchangeDebugTokenRequest request =
128+
new ExchangeDebugTokenRequest(debugSecret, isLimitedUseToken);
118129
return Tasks.call(
119130
blockingExecutor,
120131
() ->

appcheck/firebase-appcheck-debug/src/main/java/com/google/firebase/appcheck/debug/internal/ExchangeDebugTokenRequest.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,23 @@
2525
*/
2626
public class ExchangeDebugTokenRequest {
2727
@VisibleForTesting static final String DEBUG_TOKEN_KEY = "debugToken";
28+
@VisibleForTesting static final String LIMITED_USE_TOKEN_KEY = "limited_use";
2829

2930
private final String debugToken;
31+
private final boolean isLimitedUseToken;
3032

31-
public ExchangeDebugTokenRequest(@NonNull String debugToken) {
33+
public ExchangeDebugTokenRequest(@NonNull String debugToken, boolean isLimitedUseToken) {
3234
this.debugToken = debugToken;
35+
this.isLimitedUseToken = isLimitedUseToken;
3336
}
3437

3538
@NonNull
3639
public String toJsonString() throws JSONException {
3740
JSONObject jsonObject = new JSONObject();
3841
jsonObject.put(DEBUG_TOKEN_KEY, debugToken);
39-
42+
if (isLimitedUseToken) {
43+
jsonObject.put(LIMITED_USE_TOKEN_KEY, true);
44+
}
4045
return jsonObject.toString();
4146
}
4247
}

appcheck/firebase-appcheck-debug/src/test/java/com/google/firebase/appcheck/debug/internal/DebugAppCheckProviderTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@
3636
import com.google.firebase.concurrent.TestOnlyExecutors;
3737
import java.io.IOException;
3838
import java.util.concurrent.Executor;
39+
import org.json.JSONObject;
3940
import org.junit.After;
4041
import org.junit.Before;
4142
import org.junit.Test;
4243
import org.junit.runner.RunWith;
44+
import org.mockito.ArgumentCaptor;
45+
import org.mockito.Captor;
4346
import org.mockito.Mock;
4447
import org.mockito.MockitoAnnotations;
4548
import org.robolectric.RobolectricTestRunner;
@@ -70,6 +73,7 @@ public class DebugAppCheckProviderTest {
7073
@Mock NetworkClient mockNetworkClient;
7174
@Mock RetryManager mockRetryManager;
7275
@Mock AppCheckTokenResponse mockAppCheckTokenResponse;
76+
@Captor ArgumentCaptor<byte[]> requestBytesCaptor;
7377

7478
private StorageHelper storageHelper;
7579
private SharedPreferences sharedPreferences;
@@ -173,4 +177,31 @@ public void exchangeDebugToken_onFailure_setsTaskException() throws Exception {
173177
Exception exception = task.getException();
174178
assertThat(exception).isInstanceOf(IOException.class);
175179
}
180+
181+
@Test
182+
public void getLimitedUseToken_onSuccess_setsTaskResult() throws Exception {
183+
when(mockNetworkClient.exchangeAttestationForAppCheckToken(
184+
any(), eq(NetworkClient.DEBUG), eq(mockRetryManager)))
185+
.thenReturn(mockAppCheckTokenResponse);
186+
when(mockAppCheckTokenResponse.getToken()).thenReturn(APP_CHECK_TOKEN);
187+
when(mockAppCheckTokenResponse.getTimeToLive()).thenReturn(TIME_TO_LIVE);
188+
189+
DebugAppCheckProvider provider =
190+
new DebugAppCheckProvider(
191+
DEBUG_SECRET, mockNetworkClient, liteExecutor, blockingExecutor, mockRetryManager);
192+
Task<AppCheckToken> task = provider.getLimitedUseToken();
193+
194+
verify(mockNetworkClient)
195+
.exchangeAttestationForAppCheckToken(
196+
requestBytesCaptor.capture(), eq(NetworkClient.DEBUG), eq(mockRetryManager));
197+
198+
byte[] capturedBytes = requestBytesCaptor.getValue();
199+
JSONObject jsonObject = new JSONObject(new String(capturedBytes, "UTF-8"));
200+
assertThat(jsonObject.opt(ExchangeDebugTokenRequest.DEBUG_TOKEN_KEY)).isEqualTo(DEBUG_SECRET);
201+
assertThat(jsonObject.opt(ExchangeDebugTokenRequest.LIMITED_USE_TOKEN_KEY)).isEqualTo(true);
202+
203+
AppCheckToken token = task.getResult();
204+
assertThat(token).isInstanceOf(DefaultAppCheckToken.class);
205+
assertThat(token.getToken()).isEqualTo(APP_CHECK_TOKEN);
206+
}
176207
}

appcheck/firebase-appcheck-debug/src/test/java/com/google/firebase/appcheck/debug/internal/ExchangeDebugTokenRequestTest.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,26 @@ public class ExchangeDebugTokenRequestTest {
2929
@Test
3030
public void toJsonString_expectSerialized() throws Exception {
3131
ExchangeDebugTokenRequest exchangeDebugTokenRequest =
32-
new ExchangeDebugTokenRequest(DEBUG_TOKEN);
32+
new ExchangeDebugTokenRequest(DEBUG_TOKEN, false);
3333

3434
String jsonString = exchangeDebugTokenRequest.toJsonString();
3535
JSONObject jsonObject = new JSONObject(jsonString);
3636

3737
assertThat(jsonObject.getString(ExchangeDebugTokenRequest.DEBUG_TOKEN_KEY))
3838
.isEqualTo(DEBUG_TOKEN);
39+
assertThat(jsonObject.opt(ExchangeDebugTokenRequest.LIMITED_USE_TOKEN_KEY)).isNull();
40+
}
41+
42+
@Test
43+
public void toJsonString_limitedUse_expectSerialized() throws Exception {
44+
ExchangeDebugTokenRequest exchangeDebugTokenRequest =
45+
new ExchangeDebugTokenRequest(DEBUG_TOKEN, true);
46+
47+
String jsonString = exchangeDebugTokenRequest.toJsonString();
48+
JSONObject jsonObject = new JSONObject(jsonString);
49+
50+
assertThat(jsonObject.getString(ExchangeDebugTokenRequest.DEBUG_TOKEN_KEY))
51+
.isEqualTo(DEBUG_TOKEN);
52+
assertThat(jsonObject.getBoolean(ExchangeDebugTokenRequest.LIMITED_USE_TOKEN_KEY)).isTrue();
3953
}
4054
}

appcheck/firebase-appcheck-playintegrity/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
- [fixed] Fixed issue preventing limited use tokens from being correctly generated. (#8204)
4+
35
# 19.0.2
46

57
- [unchanged] Updated to keep [app_check] SDK versions aligned.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version=19.0.3
1+
version=19.1.0
22
latestReleasedVersion=19.0.2

0 commit comments

Comments
 (0)