amplify-js: Force Token to Expire
** Which Category is your question related to? **
Authentication
** What AWS Services are you utilizing? **
AWS Amplify Authentication
** Provide additional details e.g. code snippets **
I know the login or refresh time is in the jwt but I feel like there is another way I’m missing to force a logout.
I’m having some trouble understanding the best way to log a user out after, say 5 minutes, or x amount of inactivity. I’ve seen a lot of hacky solutions, and npm packages, but I’d much rather do it correctly and efficiently as you guys suggest - without needing to add any additional packages.
Here are some of the related dependencies I’m using in package.json:
"aws-amplify": "^1.1.6",
"aws-amplify-react": "^2.0.5",
"aws-amplify-react-native": "^2.0.1",
"expo": "^30.0.0",
"react-native": "^0.55.0",
"react-navigation": "^2.13.0",
"react-redux": "^5.0.7",
"redux": "^4.0.0",
"redux-promise": "^0.6.0"
Here’s my App.js file:
import React, { Component } from 'react'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux'
import { Font, Asset, AppLoading } from 'expo'
import ReduxPromise from 'redux-promise'
import Amplify from 'aws-amplify'
import AppNavigator from './AppNavigator'
import reducers from './src/reducers'
import awsExports from './src/aws-exports'
Amplify.configure(awsExports)
const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
class App extends Component {
constructor(props) {
super(props)
this.state = {
fontLoaded: false,
isReady: false,
}
}
async componentDidMount() {
await Font.loadAsync({
'NunitoSans-Bold': require('./src/assets/fonts/NunitoSans-Bold.ttf'),
'NunitoSans-Regular': require('./src/assets/fonts/NunitoSans-Regular.ttf'),
'NunitoSans-SemiBold': require('./src/assets/fonts/NunitoSans-SemiBold.ttf'),
})
this.setState({ fontLoaded: true })
}
cacheResourcesAsync = async () => {
const images = [
require('./assets/fav.png'),
require('./assets/splash.png'),
]
const cacheImages = images.map(image => ( Asset.fromModule(image).downloadAsync()))
return Promise.all(cacheImages)
}
render() {
const store = createStoreWithMiddleware(reducers)
return (
this.state.fontLoaded && this.state.isReady ? (
<Provider store={ store }>
<AppNavigator />
</Provider>
) : (
<AppLoading
startAsync={ this.cacheResourcesAsync }
onFinish={ () => this.setState({ isReady: true }) }
onError={ console.warn }
/>
)
)
}
}
export default App
In my app’s account settings, I created a successful Logout Function, which is what I’d like to call after the user should be logged out.
handleSignOut = () => {
cognitoSignOut()
.then(() => {
AsyncStorage.clear()
this.navigate('Auth')
})
.catch(err => this.setState({ errorMessage: err.message }))
}
I guess the biggest confusion for me is that Amplify has all kinds of documentation on how to keep the user logged in and how to refresh the token, but not much on forcing the token to expire.
Any suggestions you have will be very helpful. Thanks so much.
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 5
- Comments: 37 (2 by maintainers)
We try to add things to our product roadmap based on the feature-requests we get in the issues for Amplify. I can make this issue into a feature-request and it keep it open until it gets picked up.
Yes understood… Amplify might not use the refreshToken but it still exists.
I am concerned that the following scenario is still possible on a computer that ‘Bob and Alice’ share:
I understand it is maybe a far fetched, but if the refreshToken validity is very long (1 year) the risk of this attack becomes more unacceptable. Is my concern unfounded?
How about giving us an ability to disable automatic refresh token? I guess I also don’t understand the explanation:
How does Amplify keep track of when to call the refreshToken method if it cannot keep track of it’s expiration period. Providing a way within the library the capability for the app to respect the token’s expiration and signOut should be available out of the box. What if I don’t want Cognito refreshing the token automatically?
@undefobj Thanks for considering and discussing this feature, however it is not quite the requirement. Sign out globally is not what is expected. The point here is to configure a lower accessToken expiration, which now is hardcoded to 1hour.
About “There is no way for the library to know what “inactivity” means for all applications”, Amplify triggers the refreshToken function everytime the user tab/page is active or rerendered.
Current scenario:
Expected scenario.
Moreover, thanks for the suggestion to fix the problem. I have implemented something to manage the timeout myself.
I am having the same issue as I have been working with financial institutions. Users usually are logout after 3 min of inactivity.
On top of that, the refreshToken only happens when the token is close to expire, which means close to 1 hour. Unfortunately I could not use any value from my user session to know the last activity. Auth does not have the refreshToken method available, in which I could use to reinforce my user’s activity. Also, one hour makes very hard to test the application.
It’s a long thread and I still don’t understand even the very basics Does the refresh token expire? And if so what does that do ? Does it get refreshed? In my experience tokens seem to work after many days. Finally is it possible to log out a user after the refresh token expires, presumably one day? I mean is anybody even logging users out? Can you describe your flow?
@hollyewhite @cbernardes we discussed this in a planning meeting today and having Amplify control when to call global sign out based on some timer would be a complex state tracking mechanism that could introduce unintended side effects. We would need to evaluate this very carefully before adding something like this which could be accomplished in app code that simply calls
Auth.signOut({ global: true })based on your business logic.@cbernardes one option we discussed was also providing a state mechanism for you to know the last activity that took place within an Amplify category, perhaps with updates to a session object. This also could get complex and a simple event emitter using Hub might make more sense that you could leverage in your own state management layer.
There is no way for the library to know what “inactivity” means for all applications. Is this a mouse move, an http action, or something else like form entry. Could you give more concrete details on what requirements for such a feature might look like from your perspective if we are to look at it in the future?
Yes 1 hour for the access token, but minimum 1 day expiry for the refresh token (which is kept in browser storage and so could, in theory, be used to re-authenticate & continuously refresh the session against Cognito without the need for username/password to be supplied again).
That is the security concern, which makes it hard to choose Cognito for say finance/banking apps that need to enforce short session timeouts.
Or am I missing something?
@hollyewhite if you want to expire/revoke the tokens, you can check this doc: https://aws-amplify.github.io/docs/js/authentication#sign-out
Agree with @deepku2 and so does AWS. See their docs for how to securely store data.
https://aws-amplify.github.io/docs/js/authentication#managing-security-tokens
Using that, store your data someplace more secure or encrypt it. You can even implement a storage object that filters out the refresh token so it never gets stored. This will force a new login. Maybe that’s best for banks. I’d like to think my bank is not storing my refresh token in local storage 😃
@cbernardes IdToken and AccessToken are not same. As @r-moore mentioned IdToken is just profile info about the user. AccessToken is the one used for authorization with APIs. Storing RefreshToken in browser (Local Storage or Cookie) is not a good idea from security point of view for any enterprise application (financial or otherwise)
Amplify only refreshes the token if the user is active.
When I use
Auth.signIn()in my SPA, I see the following created in browser storage:accessToken, idToken are OK but it is the refreshToken that concerns me for an SPA.
https://aws-amplify.github.io/docs/js/authentication#token-refresh “By default, Amplify will automatically refresh the tokens for Google and Facebook…”. I am assuming that in order to facilitate this Amplify keeps a refreshToken around.
According to https://auth0.com/learn/refresh-tokens/ refreshTokens are long-lived by nature (hence the minimum setting of 1 day validity within Cognito). If that’s the case I would rather not have one at all in browser storage (or at least trust that it will be destroyed when the browser window closes).
I do feel like I am missing something though, I’d really like to understand this better!
This is an issue for us too.
Overriding expiration client side with an auto-logout timer just feels wrong. e.g. how might a browser closing/reopening affect the inactivity timer?
Better to issue a token with shorter validity, so that it can expire even if the browser is closed.
Is 1 day really the shortest option?
It was already said: Banking, Sensitive data, Shared computers (forgot to logout properly) ecc.
I also think there should be a better way of handling this. Especially if you want to ensure a proper logout after a manually set timeout.
Ultimately i think a javascript solution will be the easiest to manually perform a logout. Better than hoping for an implementation change by cognito
A common way to do this would be to overwrite the XMLHttpRequest to check how much time has passed and if the user was inactive long enough , trigger a manual logout.
Example:
Note: If for your application “inactivity” also includes mouse movements, you can perform the same operation for “mousemove”
It is 1 hour the minimum. I have written an article about Cognito if it is of help.
https://medium.com/@cbernardes/serverless-things-i-wish-i-had-known-before-i-started-part-1-aws-cognito-cf5d3a0c3d9d
Hi, i came across this today as i’d like to develop an application which contains very confidential data, and the credentials should not auto-refresh on reboot or forced reset. Sure i could do some auto-logout after a while via Javascript, but when the expiration period of the refresh token is reached (e.g. on Cognito this can be set to 1DAY-3600DAY) it should re-ask for credentials. Not doing so is very bad in terms of security and should really be changed (or some easy way to set this should be given, e.g boolean flag)
@cbernardes How did you manage to fix this problem?
I’m facing the same issue, we want to kick the user out after an hour of inactivity however right now even after days the session is still valid due to the refresh token mechanism.
@choxnox You can bypass the cache:
bypassCache: trueHow can we keep the session intact but refresh user attributes? For example, I submit a form to the server which updates user attributes, then I redirect the form to another page but before displaying the page content I do
let user = await Auth.currentAuthenticatedUser();because I’d like to get updated attributes but unfortunately all this does is fetch attributes from the cache. Any workaround this use case?