-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expired Token: The Token is Expired - Managing Tokens Properly #12734
Comments
Hello @ChristopherGabba, and thank you for opening this issue. Working to reproduce this and wanted to confirm, are you seeing this behavior in both dev environment and prod when deployed/built? |
I've never experienced this on a development build, but then again I'm the only one using the development build because my partner is using a TestFlight build. The error has only appeared for him and not me. |
Good afternoon @cwomack , export function useAWSAuthentication(): { isAuthenticated: boolean; isVerified: boolean } {
const {
authenticationStore: { isAuthenticated, setProp },
userStore,
} = useStores()
const [authToggled, setAuthToggled] = useState(false)
const [tokenRefresher, setTokenRefresher] = useState(false)
const [isVerified, setIsVerified] = useState(false)
const isForeground = useIsForeground()
async function refreshUserSession(refreshToken: CognitoRefreshToken) {
Auth.currentAuthenticatedUser().then((res) => {
res.refreshSession(refreshToken, (err, data: CognitoUserSession) => {
if (err) {
alert("got an auth error so signing out:" + err)
Auth.signOut()
setProp("authToken", "")
} else {
console.log("Successfully refreshed token session")
setProp("authToken", data.getIdToken().getJwtToken())
}
})
})
}
// https://github.com/aws-amplify/amplify-js/issues/2560
useEffect(() => {
let tokenExpirationTimer: NodeJS.Timeout | undefined
;(async function manageUserAuthSession() {
// Every time we enter the foreground, clear the existing timer (useEffect return)
// Start a new timer the runs exactly when the idTokenExpires. Once it expires
// refresh the session and trigger the useEffect again to start another timer
if (isForeground) {
await Auth.currentSession()
.then((session) => {
const idTokenExpire = session.getIdToken().getExpiration()
const refreshToken = session.getRefreshToken()
const currentTimeSeconds = Math.round(+new Date() / 1000)
const timeRemainingOnToken = idTokenExpire - currentTimeSeconds
console.log("Token expires in", timeRemainingOnToken * 0.0166667, "minutes")
tokenExpirationTimer = setTimeout(() => {
refreshUserSession(refreshToken)
setTokenRefresher((prev) => !prev)
}, timeRemainingOnToken * 1000)
})
.catch((err) => {
console.log("Auth current session error: ", err)
setProp("authToken", "")
})
}
})()
return () => {
if (tokenExpirationTimer) clearTimeout(tokenExpirationTimer)
}
}, [isForeground, tokenRefresher])
useEffect(() => {
const authUnsubscribe = Hub.listen("auth", (data) => {
setAuthToggled((prev) => !prev)
const authChange = data?.payload?.event
switch (authChange) {
case "autoSignIn":
console.log("User entered in correct verification code")
setProp("authToken", data?.payload?.data?.signInUserSession?.accessToken?.jwtToken)
break
case "signIn":
console.log("user signed in normally")
setProp("authToken", data?.payload?.data?.signInUserSession?.accessToken?.jwtToken)
break
case "signOut":
console.log("user signed out")
setProp("authToken", "")
break
}
})
return () => {
authUnsubscribe()
}
}, [])
useEffect(() => {
;(async function fetchCurrentUserInfo() {
if (isAuthenticated) {
const {
username,
attributes: {
sub,
birthdate,
family_name,
given_name,
picture,
phone_number,
phone_number_verified,
},
} = await Auth.currentUserInfo()
setIsVerified(phone_number_verified)
const currentUser = {
...userStore.currentUser,
id: sub,
username,
birthdate,
phoneNumber: phone_number,
profileImage: picture,
firstName: given_name,
lastName: family_name,
}
userStore.setProp("currentUser", currentUser)
}
})()
}, [isAuthenticated, authToggled])
return { isAuthenticated, isVerified }
} |
@cwomack Hello Chris, async function uploadVideoToS3() {
// Push video to s3
// Do I need to refresh the token right here in order to avoid this bug??
setIsUploading(true)
try {
// Upload main phone media to S3
const compressedVideo = await compressVideo(videoUri) // this function uses ffmpeg to reduce the size of the video
const video = await fetchResourceFromLocalURI(compressedVideo)
const response = await Storage.put(
`${post.id}/videoUri.mp4`,
video,
{
level: "public",
contentType: "video/mp4",
},
)
const videoUri = await Storage.get(response.key, { level: "public" })
...
} catch (err) {
alert("Error during upload process:" + err)
}
setIsUploading(false)
} |
Hey Chris another update. I hard coded directly before any upload to S3 a complete refresh of the token like so: async function upload() {
// Push reactionVideoUrl to Amazon S3 storage
setIsUploading(true)
try {
// Upload main phone media to S3
await Auth.currentSession().then((session) => {
const refreshToken = session.getRefreshToken()
Auth.currentAuthenticatedUser().then((res) => {
res.refreshSession(refreshToken, (err, data: CognitoUserSession) => {
if (err) {
console.log("Error refreshing token before upload:" + err)
} else {
console.log("Successfully refreshed token before upload")
}
})
})
})
const videoBlob = await fetchResourceFromLocalURI(videoUrl)
const response = await Storage.put(
`video.mp4`,
videoBlob,
{
level: "public",
contentType: "video/mp4",
},
)
}
} catch (err) {
alert("Error during upload process:" + err)
}
setIsUploading(false)
setSuccess(true)
} That way every single time a user uploads anything to S3, they for sure have a brand new refreshed session. Today, even after doing this, we got the error again: "The provided token is expired" I have no idea what else I could try on my end to fix this. My friend can immediately send another one right after this error and he can successfully upload it. So it literally appears to be happening at random. |
@cwomack okay I was able to reproduce the bug reliably. What it seems like is occurring is that if the app is in the background for a long time without swiping out of the app (dismissing it on the iPhone), and I open it up after x amount of hours, I get this token error. What's bizarre is that I hard code a token refresh before every upload to S3 and I still get the error. So basically refreshing the token is not the solution to it. |
I've rewritten my entire authentication system in several ways and this error just keeps coming, its driving us crazy and it is actually one of the last errors that is stopping us from going to production. Essentially right when you open up the application after its been in the background for about a couple of hours and you try to upload something to S3, this error pops up. It's very replicable now. What's even weirder is that it allows us to write to DynamoDB perfectly immediately before the S3 upload. Could it be related to our bucket policy for S3:
Thanks in advance for any response... Really frustrated with this one. |
All, upgrading to Amplify v6 somehow fixed this issue, and I have not experienced it anymore. I will close it, with the comment that upgrading to v6 solved the problem. The ECONNABORTED error still comes though with v6 on occasion. |
Hi @ChristopherGabba. I am facing exactly the same issue. |
I'm facing the exact same issue as well on v5... Any updates on this @cwomack? |
@SuperSuccessTalent @uzaymacar This issue was (and still is) awful. I couldn't get rid of it for months. Finally I upgraded to V6 from V5 (which has an enormous amount of breaking changes btw, you'll basically have to redo every function altogether) and I basically replaced it with ECONNABORTED. They both come through the exact same -- during the S3 upload. I suspect that this issue and ECONNABORTED are directly related, if not the same with a different code. Occasionally on upload, it's like the server from AWS rejects the user and throws these errors, particularly during upload to S3. I apologize that you are getting them too, but I'm kind of glad that someone else is that way we can get pressure to fix these errors--they literally kill the user experience. My app relies heavily on uploads and this sometimes locks the app up and forces the user to completely swipe out and reset the app. The most annoying part about them is that you can't really make a reproducible example unless you are in production and using the app a bit. Follow the ECONNABORTED thread and you'll see that I've pinpointed it coming directly from the library. I've been in Beta on my app for about 6 months and we have gotten one of these two errors every single day. I have no idea how no one else is experiencing them unless others just aren't using Amplify Storage w/ React Native. Sounds like they may need to re-open this issue. |
Before opening, please confirm:
JavaScript Framework
React Native
Amplify APIs
Authentication
Amplify Categories
auth
Environment information
Describe the bug
I have my application submitted into TestFlight on iOS and my friend is beta testing the app and there is an issue appearing for him that I have not seen before. When he tries to upload an item to DynamoDB he is getting this error "Expired Token: The Token is Expired".
After much research, I stumbled across this particular Github issue:
#2560
And it shed some light on managing refresh tokens, etc. I built my own custom hook to determine whether or not the user is authenticated based on that issue and the Amplify docs. I figured I had it figured out and he got the alert again when trying to upload something to Dynamo DB again.
Expected behavior
This error should not appear if managed correctly.
Reproduction steps
Code Snippet
Log output
aws-exports.js
/* eslint-disable */
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
const awsmobile = {
"aws_project_region": "us-east-1",
"aws_appsync_graphqlEndpoint": "https://5tvnvesrgjfjdclupp5rzrh5gi.appsync-api.us-east-1.amazonaws.com/graphql",
"aws_appsync_region": "us-east-1",
"aws_appsync_authenticationType": "API_KEY",
"aws_appsync_apiKey": "REDACTED",
"aws_cognito_identity_pool_id": "us-east-1:a2d5d29b-d69d-46d6-81c3-c6dc71323225",
"aws_cognito_region": "us-east-1",
"aws_user_pools_id": "us-east-1_eDAImGHL9",
"aws_user_pools_web_client_id": "4uj0jgf4p8m3au9h8u6g429111",
"oauth": {},
"aws_cognito_username_attributes": [],
"aws_cognito_social_providers": [],
"aws_cognito_signup_attributes": [
"GIVEN_NAME",
"FAMILY_NAME",
"BIRTHDATE",
"PHONE_NUMBER"
],
"aws_cognito_mfa_configuration": "OFF",
"aws_cognito_mfa_types": [],
"aws_cognito_password_protection_settings": {
"passwordPolicyMinLength": 8,
"passwordPolicyCharacters": [
"REQUIRES_LOWERCASE",
"REQUIRES_UPPERCASE",
"REQUIRES_NUMBERS",
"REQUIRES_SYMBOLS"
]
},
"aws_cognito_verification_mechanisms": [
"PHONE_NUMBER"
],
"aws_user_files_s3_bucket": "reelfeelmedia",
"aws_user_files_s3_bucket_region": "us-east-1"
};
export default awsmobile;
Manual configuration
No response
Additional configuration
No response
Mobile Device
iPhone 15
Mobile Operating System
iOS 17
Mobile Browser
N/A
Mobile Browser Version
N/A
Additional information and screenshots
The text was updated successfully, but these errors were encountered: