Prior to every call made to the backend, I used Auth.currentAuthenticatedUser() to obtain idToken.jwtToken and pass it in the header of my request to the backend server for data.
Is there a difference between using Auth.currentSession() instead of Auth.currentAuthenticatedUser() for my use-case? Does Auth.currentAuthenticatedUser() refresh the token once it has expired, similar to Auth.currentSession()?
The documentation for amplify auth is still very poor, so I looked into the source code for #aws-amplify/auth and amazon-cognito-identity-js packages and these are the findings:
currentAuthenticatedUser will try to retrieve authenticated user info from localstorage (unless your storage options is configured otherwise). If it doesn't exist in storage, then it will make api calls to retrieve user info which involves automatically refreshing the user session in the process.
currentSession will not check the local storage and always invoke the API which also involves automatically refreshing the user session if expired.
So to answer your question directly, the Auth.currentAuthenticatedUser() method doesn't always give you a valid token. If your storage contains an expired token, it will just return that. This would require you to call user.getSession() on the returned user object to request for a new session/token manually. I recommend that you use Auth.currentSession() since this handles the token refresh automatically and always returns a valid token.
Related
The use-token-model documentation states that
In the token based authorization model, there is no need to store
per-user refresh tokens on your backend server.
It also states that
In the Token model, an access token is not stored by the OS or
browser, instead a new token is first obtained at page load time, or
subsequently by triggering a call to requestAccessToken() through a
user gesture such as a button press.
The trouble I am having is during development my page is continually reloading and I am having to re-connect each time. I have workaround ideas, but I just wanted to confirm that there is no way to persist the token/session information in local storage to rehydrate gapi.client via gapi.client.setToken.
You can store the access token in local storage. When the page reloads, you can then retrieve it and use gapi.client.setToken() to set the token for use.
Note that you will have to re-auth when the token expires, after 1 hour.
const token = localStorage.getItem("u_token")
if (token) {
gapi.client.setToken({access_token:token});
}
Working on a very basic React-Native App with a login-form, fetching Data from an API and display it. (Token based OAuth2 with Password Grant Type)
Question: When is the best time to retrieve data from my REST service again?
Currently I only fetch the data once, and that is when the user logs in.
Possible Solution: My idea would be to save the user data (username,password | token) in AsyncStorage (or SecureStorage) and to query it again every x minutes - Is that the normal workflow or do I have a major security gap?
I did not include any code, because it is a question of understanding and I shouldn't have any problems with the programming part.
Storing user password is a big NO.
If your server is using standard OAuth2, normally the sign in response would include an access token and a refresh token. See the standard doc.
The access token is embedded in the app's requests to the resource server in the session.
The refresh token is used to retrieve a new access token, either when the current access token has expired, or when a new session is started. So this refresh token is what the app should save, across sessions.
The refresh token's lifespan should be reasonably long such that the client, in this case your app, doesn't have to worry about redoing user sign in.
I'm building a react native app which uses the spotify web api. I'm using the authorization code flow to authorize a user. First I get a authorization code which can be used to obtain an access token and a refresh token. Everything works!
The problem is: an access token is only valid for a limited amount of time. That's where the refresh token comes in. I understand this concept, but I'm breaking my head about how to implement this.
Let's say a users opens the app, requests an access token and uses this for some time. Then, the user closes the app. After 15 minutes, the users opens the app again. The access token has now expired, so I need to request a new access token.
I've come op with several "solutions". Can someone point me to the correct solution?
Solution 1:
Every time the user opens the app, I request a new access token and use this. Problem: when the user uses the app longer than the valid time of the access token, I won't work anymore.
Solution 2:
I use the access token that's stored in the secure storage on every request. When a request comes back with 'access token invalid' (I don't know the exact error code but you guys know what I mean), I request a new access token with the stored refresh token, and then I send the previous command again (with the new access token). But my question here is: can I use some kind of "wrapper function" which checks the response of the request, and if the response is "access token invalid", it automatically requests a new access token and runs the previous request again.
I think certainly correct solution is solution 2,and i think its clear enough.
and for using solution 2 you need somthing like wrapper function,yes its intelligently.
so you should use interceptor:
what is interceptor ?
You can intercept requests or responses before they are handled by then or catch.
in link below there is a good example of implementing refresh token in axios interceptor:
https://gist.github.com/Godofbrowser/bf118322301af3fc334437c683887c5f
I agree that Solution 2 is the best, each time you do a request you can check to see if the Access Token has expired, and if it has then you can request a new Access Token using the Refresh Token as you mentioned and then make your request, in my own project I do this in a FormatRequestHeadersAsync method which calls a CheckAndRenewTokenAsync method where I perform the following check, here shown in C#:
if(AccessToken?.Refresh != null && (AccessToken.Expiration < DateTime.UtcNow))
{
AccessToken = await GetRefreshTokenAsync(
AccessToken.Refresh,
AccessToken.TokenType,
cancellationToken);
}
You can store the Access Token and the Refresh Token and then use something similar to this before you make each request to the API this will refresh your token and then you can store the new Access Token and the existing Refresh Token.
I'm a beginner in react native and I'm creating an app. I've done some research about how to make a secured react native app, but I didn't found much information. I've come up with a "solution" myself, but I want to make sure this is the right way to do this. So I need the help of some react native/javascript/security experts if possible, to quickly check if my approach is OK or not?
I have included 3 questions in this text, but obviously they're related. I've put them in bold. Feel free to answer one or more questions, I appreciate every answer!
I'm creating an app in react native. For a user to be able to use the app, the user should create an account and sign in. I'm using an JSON web token as an access token to authorize the requests made from the app to the server, and to identify the user (I store the user ID in the JSON web token).
At my server, I first check if the access token is valid. If so, I get the user ID out of the access token and use this user ID to identify the user.
For extra security, I'm also using refresh tokens, because an access token is only valid for 10 minutes. When a user send a request with an expired access token, the server responds with a 401 not authorized status.
To make my code more "managable", I've created a wrapper function in react native. I wrap every "request function" (every function where I do a GET/POST/PUT/DELETE request to the server) with this wrapper function. This wrapper function checks the response of the request. If the response status is 200, the response is returned to the code. If the response status is 401, the refresh token is send to a specific endpoint to obtain a new access token. When the access token arrives at the app, the previous request is made again with the new access token. The wrapper function also stores the new access token in (temporary) redux (keychain or shared preferences). 1. Is a wrapper function a good idea? For me, it's more manageble because now I'm reusing the code.
Every time the user opens the app, a new access token is requested, and when a user closes the app, the current access token is deleted, even if it is not expired yet. That way, I want to make sure that every app "session" starts with a new access token. 2. Is this okay? Or should I prevent unnecessary requests to the server when I still have a (possibly) valid access token?
In my react native app, this wrapper function is located in a context component. This "authentication" context is wrapper around my other components in App.js like this:
<AuthenticationProvider>
<AppNavigator />
</AuthenticationProvider>
This way, my wrapper function is accessible to all my other components. My authentication context looks like this:
const AuthenticationContext = createContext({
accessToken: null,
wrapperFunction: () => {}
})
const AuthenticationProvider = (props) => {
let accessToken = null
const refreshToken = useSelector(state => state.auth.refreshToken)
const wrapperFunction = () => {
// wrapper function
// set the access token
// await fetch('server endpoint')...
}
return (
<AuthenticationContext.Provider value={{ accessToken, wrapperFunction }}>
{props.children}
</AuthenticationContext.Provider>
)
}
3. Is using a context a good practice to do stuff like this?
Server-side, I store every refresh token in a database. When a user requests a new access token, I check if the sent request token still exists in the database. If not, I have revoked access for this user and the user should be logged out. This way, I want to make sure I can "manage" users.
Yes, it makes sense. Actually I can't think of a better way to manage the scenario you mentioned. When you wanna temper the request before it's sent, you will need a single function to do so. You could also use some hooks e.g. onBeforeSend and onAfterReceive, but in your case I don't see any extra value for this.
I do not agree with the deletion of a valid token. You can still send request to server on every app start to get user's last data -might have changed on another device-. I don't understand the logic of starting the app with a new session -maybe more information?
I don't think you need to pass the wrapperFunction/token using context. It would be best if you could send user data by context. you wrapper function can access the token directly from asyncStorage. And each component can call the function directly by importing it.
I believe you are taking the approach of using a wrapper function since the relevant API requests are made directly in components. The best practice is to move such requests outside (E.g. Redux actions with a middleware like redux-thunk) the components.
It's better to check if the access token is expired (by decoding the token) before sending the API request and retrieve the new access token. This will reduce the amount of requests to server. You can implement a common request method which handle this check as well.
I think since your access token expires every 10 mins this is unnecessary. Is there a specific reason to start each session with a new access token?
You can pass in user access details using the context. I think it's matter of preference. Passing in the wrapper function is not needed if you're handing the requests through a common request method.
In a react native app, how do you obtain a refresh token. I see in the docs that you can call the refresh token endpoint directly via the delegation endpoint in the REST API - but is there a more abstracted way to do it using the Auth0 lock component? Perhaps some sort of setting that is "remember login" and does all the plumbing for you?
If not, then to implement it ourselves would we call the refresh token service on every app start? And if so, do we make REST call directly or should we do it through an auth0 library of some sort?
Is there sample code that uses the library that shows needed steps like
check that the existing token has not expired
obtain a refresh token
redeem refresh token for access token
Or, have these steps been abstracted away by the library in some way?
The id_token that you receive as the outcome of user authentication follows the OpenID Connect specification so it will include an exp claim that you can check in order to detect expiration.
exp: Expiration time on or after which the ID Token MUST NOT be accepted for processing. The processing of this parameter requires that the current date/time MUST be before the expiration date/time listed in the value. Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time.
(emphasis is mine; source: OpenID Connect)
If the offline_access scope is included when performing the authentication process you should get a refresh token issued alongside the ID token.
According to react-native-lock documentation you can then use the authenticationAPI() method to get an Authentication API client that can be used to refresh user's token.
The specific call can be seen in the react-native-auth0 documentation:
.authentication('{YOUR_CLIENT_ID}')
.refreshToken('user refresh_token')
.then(response => console.log(response))
.catch(error => console.log(error));