amplify-android: Getting "Invalid Refresh Token" during session while device tracking is on
Before opening, please confirm:
- I have searched for duplicate or closed issues and discussions.
Language and Async Model
Kotlin - Coroutines
Amplify Categories
Authentication, REST API
Gradle script dependencies
// Put output below this line
implementation(com.amplifyframework:aws-api:2.8.7)
implementation(com.amplifyframework:aws-auth-cognito:2.8.7)
implementation(com.amplifyframework:core-kotlin:2.8.7)
coreLibraryDesugaring(com.android.tools:desugar_jdk_libs:2.0.3)
Environment information
# Put output below this line
------------------------------------------------------------
Gradle 7.5
------------------------------------------------------------
Build time: 2022-07-14 12:48:15 UTC
Revision: c7db7b958189ad2b0c1472b6fe663e6d654a5103
Kotlin: 1.6.21
Groovy: 3.0.10
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 18 (Oracle Corporation 18+36-2087)
OS: Windows 11 10.0 amd64
Please include any relevant guides or documentation you’re referencing
https://repost.aws/knowledge-center/cognito-invalid-refresh-token-error
Describe the bug
The issue I am having is happening only with live daily users. I have tried reproducing it locally on test devices but couldn’t succeed. I am using v2.8.5 currently (upgraded from 1.33.2). I encountered the issue in the old version but ignored it as a small percentage were blocked by it but after the upgrade, that percentage increased heavily.
In short, users are getting the SessionExpiredException{message=Your session has expired., cause=NotAuthorizedException(message=Invalid Refresh Token.), recoverySuggestion=Please sign in and reattempt the operation.} (on v2.8.5) and SessionExpiredException{message=Your session has expired., cause=null, recoverySuggestion=Please sign in and reattempt the operation.} (on v1.33.2) errors during their sessions when calling fetchAuthSession.
Reports couldn’t determine at what point they encounter it, but I am assuming it’s when the ID or access tokens need refreshing. I have tried reproducing the issue by logging in using the same live build and waiting for ID and access tokens to expire then launch the app once again, but tokens got refreshed normally. I also tried logging out after logging in then trying to call fetchAuthSession but that produced a different error SignedOutException{message=You are currently signed out., cause=null, recoverySuggestion=Please sign in and reattempt the operation.}.
All similar issues I found suggested I turn off device tracking to avoid getting that error, but it is crucial to one of the app’s functionalities. Some suggested I “send device key with AuthParameters” but I checked the SDK’s internal implementation and it’s already doing so.
Then I found this and double checked every point mentioned there:
- I am only using one clientId in configurations
- I am using device tracking but as far as I learned, the SDK handles sending device key with InitiateAuth call and confirm the device with ConfirmDevice call
- I am using USER_SRP_AUTH flow with device tracking
Here is a snippet of my initialization and configuration:
AWSApiPlugin.builder().configureClient(API_UNAUTHORIZED).build()
val config = AmplifyConfiguration.builder(applicationContext, R.raw.amplifyconfiguration)
.devMenuEnabled(false)
.build()
with(Amplify) {
addPlugin(AWSCognitoAuthPlugin())
addPlugin(awsApiPlugin)`
addPlugin(AWSS3StoragePlugin())
configure(config, applicationContext)
}
And here is the sign in code:
Amplify.Auth.signIn(username = username, password = password)
And the fetchAuthSession code:
val session = Amplify.Auth.fetchAuthSession() as? AWSCognitoAuthSession
val accessToken = session?.userPoolTokensResult?.value?.accessToken
if (session?.userPoolTokensResult?.error == null) {
val userAttributes = Amplify.Auth.fetchUserAttributes()
var uuid: String? = null
var username: String? = null
var phone: String? = null
userAttributes.forEach {
if (it.key.keyString == CognitoConstants.USER_UUID) {
uuid = it.value
}
if (it.key.keyString == CognitoConstants.CUSTOM_DISPLAY_NAME) {
`username = it.value
}`
if (it.key.keyString == CognitoConstants.CUSTOM_PHONE_NUMBER) {
phone = it.value
}
}
return UserSessionInfoResponse(
uuid,
username,
phone,
accessToken
)
} else throw Exception(session.userPoolTokensResult.error)
Am I missing something?
Reproduction steps (if applicable)
No response
Code Snippet
// Put your code below this line.
Configs ==========================================
val awsApiPlugin = AWSApiPlugin.builder().configureClient(API_UNAUTHORIZED).build()
val config =
AmplifyConfiguration.builder(applicationContext, R.raw.amplifyconfiguration)
.devMenuEnabled(false)
.build()
with(Amplify)
{
addPlugin(AWSCognitoAuthPlugin())
addPlugin(awsApiPlugin)
addPlugin(AWSS3StoragePlugin())
configure(config, applicationContext)
}
Sign in ==========================================
Amplify.Auth.signIn(username = username, password = password)
FetchAuthSession ==========================================
val session = Amplify.Auth.fetchAuthSession() as? AWSCognitoAuthSession
val accessToken = session?.userPoolTokensResult?.value?.accessToken
if (session?.userPoolTokensResult?.error == null) {
val userAttributes = Amplify.Auth.fetchUserAttributes()
var uuid: String? = null
var username: String? = null
var phone: String? = null
userAttributes.forEach {
if (it.key.keyString == CognitoConstants.USER_UUID) {
uuid = it.value
}
if (it.key.keyString == CognitoConstants.CUSTOM_DISPLAY_NAME) {
username = it.value
}
if (it.key.keyString == CognitoConstants.CUSTOM_PHONE_NUMBER) {
phone = it.value
}
}
return UserSessionInfoResponse(
uuid,
username,
phone,
accessToken
)
} else throw Exception(session.userPoolTokensResult.error)
Log output
// Put your logs below this line
SessionExpiredException{message=Your session has expired., cause=NotAuthorizedException(message=Invalid Refresh Token.), recoverySuggestion=Please sign in and reattempt the operation.} on v2.8.5
AND
SessionExpiredException{message=Your session has expired., cause=null, recoverySuggestion=Please sign in and reattempt the operation.} on v1.33.2
amplifyconfiguration.json
{
"UserAgent": "aws-amplify-cli/2.0",
"Version": "1.0",
"api": {
"plugins": {
"awsAPIPlugin": {
"fantoken": {
"endpointType": "REST",
"endpoint": "https://********.com",
"region": "us-east-1",
"authorizationType": "NONE"
}
}
}
},
"auth": {
"plugins": {
"awsCognitoAuthPlugin": {
"UserAgent": "aws-amplify/cli",
"Version": "0.1.0",
"IdentityManager": {
"Default": {}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "us-east-1:xxxxx-xxxxxx-xxxxxxxx",
"Region": "us-east-1"
}
}
},
"CognitoUserPool": {
"Default": {
"PoolId": "us-east-1_xxxxxx",
"AppClientId": "xxxxxxxxxxxxxxxxxx",
"Region": "us-east-1"
}
},
"Auth": {
"Default": {
"authenticationFlowType": "USER_SRP_AUTH",
"socialProviders": [],
"usernameAttributes": [
"PHONE_NUMBER"
],
"passwordProtectionSettings": {
"passwordPolicyMinLength": 8,
"passwordPolicyCharacters": [
"REQUIRES_NUMBERS",
"REQUIRES_SYMBOLS"
]
},
"mfaConfiguration": "OFF",
"mfaTypes": [
"SMS"
],
"verificationMechanisms": [
"PHONE_NUMBER"
]
}
}
}
}
},
"apiKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
GraphQL Schema
// Put your schema below this line
Additional information and screenshots
No response
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 1
- Comments: 18 (6 by maintainers)
@gpanshu We have intercepted refresh token API through Charles proxy and compared the request payload of success and failure scenario. We noticed that Android SDK doesn’t send the DEVICE_KEY when calling refresh token API and it’s returning 400 error. Herewith I have attached my payloads for both success and failure scenarios. Could you help to further investigate and advise us how to resolve this issue.
payload_when_fail:
payload_when_success
Note: We tried to intercept iOS client’s cognito API calls through proxy settings but we couldn’t detect the API calls for iOS
CC: @tylerjroach
@gpanshu just a friendly follow up on this. I am well aware you mentioned you would update us once you are done but I am required to report back to our management when the device tracking can be used without issues to plan ahead. So please let us know if there is a scheduled date to address that issue.
Thanks in advance.
@sameera26 no we haven’t faced any issues after disabling device tracking on iOS AFAIK. We got some complaints from users, however, that implied same issue existed on iOS when device tracking was on but wasn’t covered in reports
@sameera26 and @Gesraha101 cognito mandates all new devices that logs in to be confirmed using the ConfirmDevice API call otherwise they will not let the refresh token refresh the access token. Having said that the sign in call for flows other than hostedUI should automatically call the confirm device api. I am now digging deep using the examples provided by @Gesraha101 to understand what might be going on here as it might be a bug but I am investigating and will report back here once I am done. Thank you so much for your patience.