firebase / firebase/firebase-android-sdk

Custom provider getToken() creates infinite loop when device time is tempered

Open
#3,935 35 comments 0 reactions 0 assignees View on GitHub
api: app-check internal-bug-filed needs-attention
Dominant language
Java
Stars
2.6k
Forks
710
Avg merge
2d 23h
Merged PRs (30d)
34

Description

### [READ] Step 1: Are you in the right place?

Issues filed here should be about bugs in __the code in this repository__.
If you have a general question, need help debugging, or fall into some
other category use one of these other channels:

* For general technical questions, post a question on [StackOverflow](http://stackoverflow.com/)
with the firebase tag.
* For general Firebase discussion, use the [firebase-talk](https://groups.google.com/forum/#!forum/firebase-talk)
google group.
* For help troubleshooting your application that does not fall under one
of the above categories, reach out to the personalized
[Firebase support channel](https://firebase.google.com/support/).

### [REQUIRED] Step 2: Describe your environment

* Android Studio version: Chipmunk 2021.2.1
* Firebase Component: App Check
* Component version: bom 30.2.0

### [REQUIRED] Step 3: Describe the problem
I have implemented a custom provider using Firebase Functions and the firebase-admin sdk which return a token and expiration time using some custom logic, the implementation works perfectly when the time on the device is correct and not tempered with, but as soon as the time on the device is being tempered, for example a user set the clock to +2 hours using the device settings, Android App Check SDK gets into infinite loop as the token expiration time from the server is current time + 60 minutes but the device time is current time + 2 hours (due to settings change), which leads to the SDK to think the token is expired and start an infinite refresh loop

#### Steps to reproduce:
Configuring a token TTL to 60 minutes and changing the device clock to +1 hour should reproduce it

#### Relevant Code:
`public class YourCustomAppCheckProvider implements AppCheckProvider {

private final Context applicationContext;

public YourCustomAppCheckProvider(Context applicationContext) {
this.applicationContext = applicationContext;
}

@Override
public Task getToken() {

TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>();

try {
String token = customLogicToGetToken()
int expirationFromServer = expiration received from the server endpoint...

long expMillis = expirationFromServer * 1000L - 60000;

taskCompletionSource.setResult(new CustomAppCheckToken(token,expMillis));
} catch (IOException | JSONException e) {
taskCompletionSource.setException(e);
}

return taskCompletionSource.getTask();
}
}
`

### The Firebase function to generate the token + expiration time:

`
```
exports.fetchAppCheckToken = functions.https.onCall((authenticityData, context) => {

//Custom logic to decide if the request is valid or not, in case not return "error"...

return admin.appCheck().createToken(APP ID)
.then(function (appCheckToken) {
const expiresAt = Math.floor(Date.now() / 1000) + 60 * 60;

return {token: appCheckToken.token, expiresAt: expiresAt, ttlMillis: appCheckToken.ttlMillis}
})
.catch(function (err) {
console.error("Unable to create App Check token.");
console.error(err);

return "error"
});
});

````

Now of course I can just check if the "expiresAt" received from the function is smaller than System.currentTimeInMills() and then return exception in the getToken() method, but that means any user who changed his device time in settings wont be able to user my app.
Is it a bug or just something I am doing wrong?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.