I have problem retrieving my authentication token from SecureStore while I develop my app in the expo client.
I’m trying to implement this authentication flow from react navigation using secureStore instead of Async storage: https://reactnavigation.org/docs/en/4.x/auth-flow.html
Currently, when I login my token is stored in SecureStore. I know this because I can then use it for authorising my requests.
My problem is when the expo client I'm developing my app in refreshes, the token seems to disappear so I have to sign in again.
Does the expo client app refreshing clear the token from secure store or is there a bug in my code that stops me from retrieving the token when I am opening my app again:
useEffect(() => {
_bootstrapAsync = async () => {
const token = await SecureStore.getItemAsync('token')
navigation.navigate(token ? 'App' : 'Auth');
};
_bootstrapAsync();
}, [])
I have a hunch what it could be.
Is the token stored correctly?
And won't the token be overwritten when reloading?
I don't know which module you use for saving but I recommend "expo-secure-store".
In my applications when I reload everything works.
Try wrapping a try-catch block around both getItemAsync and setItemAsync and see whether you're getting any errors as a start.
There's also a chance that you're using an old import syntax, make sure you're using import * as SecureStore from "expo-secure-store", this will cause an error like undefined is not an object so the data was never saved.
Solved this by adding a useEffect that would check if there is a Token, if there was a token i set it and if not i removed it.
Related
I have written a small application using React Native and TS. In my application I use authorization through access_tokens with lifetime for one hour. Every time the token expires, I launch refreshToken function where I send access_token and refresh_token that were saved previously in local storage and send it through POST method.
basically something like this:
if (token_from_storage !== is_expired) {
//assuming token is indeed in storage
return access_token;
} else {
//this Function calls an api with refresh token
const { tokens }: { tokens: ITokens } = await refreshToken(refresh_token);
saveTokens(tokens); //here we save new access_token and refresh_token
}
after refreshToken has finished the new tokens are saved locally (and were updated on DB level) and must be used if you want refresh tokens again.
For example, we launch an application with an expired token. The methods on the start will be getUserInfo() and getApplicationInfo() that get some important data. They are launched through redux-saga or something similar (async).
//first app screen
useEffect(() => {
dispatch(ACTION_GET_USER_INFO);
dispatch(ACTION_GET_APPLICATION_INFO);
},[])
first method would launch refresh_token about the same time as the second one. The tokens will be rebuilt for the first method and update on the database level. By the time second method calls refreshToken (he was launched at the same time; he also thinks that the token is dead), the refresh_token will be changed on DB level and would not answer 200 on the refreshToken() call.
What should be done to achieve proper refreshing?
If I am understanding your issue correctly it sounds like you are calling two async function that both refresh tokens if the current token has expired.
This indicates you are experiencing a race condition in your useEffect statement, and because the requests handle refreshing their token independently at least one of the request will have an invalid token.
Personally, I would not being handling tokens in the client at all especially with local storage.
If you must however, you can fix the race condition by adding a service layer that handles requests, and tokens singularly. Your dispatch functions will pass through the service layer which can determine the need to refresh a token and if a token is being refreshed already in a synchronous manner before attempting to send the requests.
I've set up the most basic implementation of firebase auth login with email and password.
firebase.auth().signInWithEmailAndPassword(email, password).then(() => {
console.log('Logged in')
window.location.href = "./home.html"
}).catch(function (error) {
console.log(error)
});
For some reason, on iOS, the login process sometimes gets stuck waiting for the promise of signInWithEmailAndPassword() to resolve. I don't get any error message.
The only way to re-enable the login mechanism is to clear the browser cache.
Is this a known problem? I've been experiencing this problem for my last two apps over the last year.
Edit: After further trial and error I found out that the problem usually happens after being logged in, letting the iPhone go to sleep, waking it back up, and then logging out. Then the same problem also happens for the signOut() function.
Turns out the problem had to do with the domain not being whitelisted in my project settings. The reason why I didn't pay attention to the console alert about oAuth was that it did work most of the times, even with it showing. So I thought it didn't have any effect on it.
The answer was suggested in this thread
I was having the same issue, but it was even more consistent when I moved to version 9 of the firebase sdk and my app was running in an Ionic-Capacitor native app on iOS. The solution was to add "localhost" to Firebase > Authentication > Sign-in method > Authorize domains (NOTE: if you use localhost make sure you have sufficient security db rules to prevent someone from adding bad data and you may not want to use this in production).
Then I needed to use intializeAuth() when running in hybrid (native app) mode. My app is also a pwa and getAuth(app) makes assumptions that its loading in a browser environment which causes this problem.
const firebaseApp = initializeApp(FirebaseConfig);
this.firebaseAuth = isPlatform('hybrid') ?
initializeAuth(firebaseApp, {persistence: indexedDBLocalPersistence}) :
this.firebaseAuth = getAuth(firebaseApp);
So I am using js-cookie in a webapplication to which I'm using it to set a jwt token. My login function does Cookies.remove('jwt') before calling the axios post for the login and in the response I Cookies.set('jwt', token,{expires:1});
Within the app the api I am calling Cookies.get('jwt'); but it is referencing a previous token from before logging in.
I check the application tab and don't see a previous reference of the old token in the cookies, I checked the documentation but is there anything that I am missing I am not sure why the old token is being used.
I am using fire base for push notification in react-native.
For getting token I am using this code
const fcmToken = await firebase.messaging().getToken();
if (fcmToken) {
this.sendFcmToken(fcmToken);
// user has a device token
}
But I am not getting token even if user have permission for token access.
I am using firebase 5.1.1
"react-native-firebase": "^5.1.1"
I don't want to upgrade version, so what I can do?
I think problem is with getToken() method as its deprecated so please suggest an alternative for it.
I'm using social authentication using the vue-google-oauth2 library. It works fine as I am able to authenticate my self and I receive a token from the backend too.
When initially I log in, and by using a function that is part of the vue-google-oauth2 library that I'm using to check if it says that I'm authorized or not, it gives the following response in my browser's console:
this.$gAuth.isAuthorized
true
When I then refresh my browser page, and since I've placed a debugger command in my code, and I print the same function again,
I get the following response:
this.$gAuth.isAuthorized
false
What can I do to ensure that switching tabs, reloading page or refreshing it won't make this happen? Or is this what is actually supposed to be happening?
Have you looked at saving it in as session data? Im not to familiar how Angular state works, but when you set original state you can look for the session key "authorized" and if it doesnt exist set auth to false, if it exists set it to the value.
localstorage.getItem(item)
and
localstorage.setItem(item)
There is also the option of making a component that handles the google auth and sends it to the state.
From the library documentation for vue-google-oauth page you linked it says you need to send that code back to your backend server to create a token to stay signed in, so it's behaving as expected. From here (https://www.npmjs.com/package/vue-google-oauth2#usage---getting-authorization-code) it states :
The authCode that is being returned is the one-time code that you can
send to your backend server, so that the server can exchange for its
own access_token and refresh_token
In other words, you need to do something with that code to make it persist in your app, otherwise it's just a one-time code, so looks to be expected.