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
with the firebase tag. - For general Firebase discussion, use the 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.
[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<AppCheckToken> getToken() {
TaskCompletionSource<AppCheckToken> 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?