using event.preventDefault() in ui-router causes infinite loop - javascript

error:
Yes i know there have been posts similar to this one but they do not address my issue. I want to take full control of the app's routing.My code is as follows:
a few things to note would be that i have attached a custom property to my states called authenticate which has a true or false value. I have also created a simple function, get user. All it does is retrieve the user from the api.
$rootScope.$on('$stateChangeStart', function(event, toState) {
event.preventDefault();
let token = $cookies.get('token');
if (toState.authenticate) {
if (token) {
getUser()
.then(user => {
$rootScope.user = user;
$state.go(toState.name);
})
.catch(err => console.log(err));
} else {
$state.go('login');
}
} else {
$state.go(toState.name);
}
});
I first check if the state requires authentication. If it does not we simply continue to the state. If it does require authentication we check if there is a token. if there is we fetch the user using the function I mentioned earlier. If there isn't a token we send the user to the login state.

Related

Firebase ID Token expiration in an hour

so I am using redux-saga in my react-native app and tried to use refresh token but didn't work, so my approach was the following in app.js in order to get the token specifically for each request and force refresh it:
handleResponse = async () => {
const {dispatch} = this.store;
await axios.interceptors.request.use(config => {
// Important: request interceptors **must** return the request.
console.log("refreshToken")
let user = firebase.auth().currentUser;
firebase.auth().onAuthStateChanged(function(user) { if (user) {
console.log("auth changed: ",user)
user.getIdToken(true).then((token) => {
setAccessToken(token);
config.headers.authorization = token;
}
);
} else { console.log("didn't auth change") } });
console.log("req in handle response: ",JSON.stringify(config));
return config;
});
axios.interceptors.response.use(config => config, (err) => {
if (err.response) {
const response = err.response;
const state = this.store.getState();
if (
response.status === 401
&& state.auth.isAuthenticated
) {
dispatch(logout());
}
}
return Promise.reject(err);
});
};
But it always ends up after an hour throwing me the following error::
Firebase ID token has expired. Get a fresh token from your client app and try again (auth/id-token-expired). See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.
so I was wondering if there's another approach I can try to solve the issue from my side?
Thanks in advance.
Firebase auth tokens automatically refresh every hour. That's a function of the SDK, and you don't have to do anything to enable it.
You definitely do not want to call firebase.auth().onAuthStateChanged for each request. That starts a persistent listener, and adds a new callback every time it's used. Typically you add just one listener globally for your app, and use its updates as they happen.
If you need to know when the SDK refreshes the token in order to get a new one immediately, you should instead use onIdTokenChanged to set up a callback that will be invoked every time the user's token changes. Again, you should only set up one of these globally for your app, and use its current value at the time of the request.

Firebase Auth setCustomClaims() not working

I am facing a problem with setting custom claims for Firebase Authentication service's token. I am using Cloud function to set the custom claims for Hasura. The cloud function executes upon new user create event to set the custom claims. Here's my code running in cloud function
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.processSignup = functions.auth.user().onCreate(user => {
// create custom claims for hasura
const hasuraClaims = {
"x-hasura-default-role": "user",
"x-hasura-allowed-roles": ["user"],
"x-hasura-user-id": user.uid
}
// attach claims to user auth object
return admin.auth().setCustomUserClaims(user.uid, hasuraClaims)
.then(_ => {
functions.logger.info('SUCCESS: Custom claims attached');
})
.catch(err => {
console.log('ERROR: ', err);
})
})
In my frontend web page, I am running the following code to get the idToken
// subscribe to user state change
firebase.auth().onAuthStateChanged(async user => {
console.log('Firebase auth state changed');
if (user) {
// User is signed in.
window.User = user;
let idToken = await user.getIdTokenResult();
console.log('idToken: ', idToken);
}
})
I don't know what I'm doing wrong, but the token doesn't contain the custom claims that I've set in my Cloud function processSignup(). I know that the function executed without error because I can check my function logs and find the info entry SUCCESS: Custom claims attached.
Can anyone please help me solve this problem?
Updating claims does not trigger an onAuthStateChanged (the auth state of being logged in or not has not changed, but the users' claims have) and tokens are minted and then used for ~1h.
You are calling getIdTokenResult but not forcing a refresh, try:
let idToken = await user.getIdTokenResult(true);
which will force a new token to be fetched from the server and will (hopefully) include your custom claims.

firebase - Firebase Current User not storing the correct user

I have a project using Firebase for the authentication. When I log into my project, sometimes the firebase.auth().currentUser method returns info from some other user. Sometimes I get the info from the actual current user and sometimes the previously signed in user - when this happens, the only way to correct the problem and get data for the correct user is to logout and sign back in again.
My login method:
onLoginClick = () => {
firebase.auth().signInWithEmailAndPassword(this.state.email.trim(), this.state.password.trim())
.then((user) => {
//Some redirects depending on my users role
})
.catch((error) => {
console.log(error, error.message);
if (error.code == "auth/user-not-found" || error.code == "auth/wrong-password") {
//Handle error
}
});
}
And my Logout method:
onLogoutClick = () => {
firebase.auth().signOut().then(function () {
this.props.history.replace("/")
}).catch(function (error) {
console.log(error);
});
}
They're pretty standard but seems like I'm doing something wrong. I've tried clearing the sessionStorage and the localStorage on the logout method but that didn't help.
UPDATE:
I've tried with some suggestions like doing:
firebase.auth().signOut().then(() => {
firebase.auth().signInWithEmailAndPassword(email, password).then((user) => {
//My redirects and everything
})
})
But this doesn't work.
Also, I've noticed that when I log in and use wrong credentials, the sessionStorage gets an entry with the previously signed in user, even though I signed him out.
I'm pretty sure that during the initialization of a new login session, until it is complete, currentUser hasn't been updated yet; use the user parameter when one is passed in on those methods. Because the login is still in progress, there is not yet a currentUser, so it passes the user in progress via the user parameter. (I think this means it is likely that it will be null the first time someone logs in, and it will be the previous one thereafter, unless it's cleared on logout by some code.)
Use the user parameter when it is provided, such as in the onAuthStateChanged handler. See the first example here, and the starred note in the blue box farther down that same page.

React Native - Firebase auth persistence not working

Firebase auth does not persist logged in user and everytime I refresh or reopen app I have to sign in again.
I have tried setting persistence to local and the callback does verify its set but the persistence is still no working
For setting persistence I am using...
//set auth persistence
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL)
.then(function() {
console.log("successfully set the persistence");
})
.catch(function(error){
console.log("failed to ser persistence: " + error.message)
});
.
.
.
For signing in I am using this code
firebase.auth().signInWithEmailAndPassword(email, password)
.then((user) =>{
this.checkAccountStatus(user.uid, user.email);
})
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorMessage)
// ...
});
And here is the code I am using to check login status...
if (firebase.auth().currentUser) {
const currentUser = firebase.auth().currentUser;
console.log("Signed in username" + currentUser.displayName);
this.props.navigation.navigate('AppTab');
}else{
console.log("no user signed in");
this.props.navigation.navigate('AuthTab');
}
if there anything I am not doing right
You don't need to set persistence. Firebase handles it for you by default. You just need to call this function to check whether user is logged or not:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('user is logged');
}
});
This will not be triggered only if user has sign out or cleaned app data.
You can find more details in the official docs: https://firebase.google.com/docs/auth/web/manage-users
Hope it helps.
Make sure you do not restrict the 'Token Service API' in the console, with the API key you are using. I did not add the service to my key, and it logged me out every 3-4 hours, even with the right code suggested above.
Firebase now recommends to use firestore instead of realtime-database and it manages offline persistence by default. It is clear in its documentation here
You just need to access the user through this code:
if (auth().currentUser !== null) {
console.log('User is logged in');
console.log(auth().currentUser.email);
props.navigation.navigate('Home');
} else {
props.navigation.navigate('Login');
}
This code will prop you to home screen if user is logged-in, even when you close the app. To clear the user's credentials, you manually need to sign-out the user using this code.
try {
auth()
.signOut()
.then(props.navigation.navigate('Login'));
} catch (error) {
Alert.alert('Error', error.toString());
}
You can also check this simple app (used react hooks in it) for further assistance.

How do I get the current user's access token in AngularFire2?

In AngularFire you were able to access the providers (e.g Google) accessToken for the authenticated user.
There does not seem to be a way to access this with AngularFire2?
On initial login say like this:
this.af.auth.subscribe(user=> {
if (user) {
console.log(user.google);
}
});
It will log out the idToken, accessToken, provider,
But (on a page refresh) subsequently will log out the standard details (uid, displayName etc....)
And the accessToken is not an accessible property?
Is there a way to access the current users accessToken?
getToken is deprecated now. You should use getIdToken instead:
this.af.auth.currentUser.getIdToken(true)
.then((token) => localStorage.setItem('tokenId', token));
The access token is only accessible when the user first signs in. From the Firebase migration guide for web developers:
With the Firebase.com Authentication API, you can easily use the provider's access token to call out to the provider's API and get additional information. This access token is still available, but only immediately after the sign-in action has completed.
var auth = firebase.auth();
var provider = new firebase.auth.GoogleAuthProvider();
auth.signInWithPopup(provider).then(function(result) {
var accessToken = result.credential.accessToken;
});
So it is indeed not available on a page refresh. If you want it to remain available, you will need to persist it yourself.
With AngularFire2, you can get the token like this :
this.af.auth.getToken() // returns a firebase.Promise<any>
If you want to get an ES6 Promise instead, just use
Promise.resolve()
.then(() => this.af.auth.getToken() as Promise<string>)
This works for me:
this.af.auth.getAuth().auth.getToken(false);//true if you want to force token refresh
You can put it into a Service and then you can get the token like this:
this.authService.getToken().then(
(token) => console.debug(`******** Token: ${token}`));
Getting the auth token from storage in angularfire2
JSON.parse(JSON.stringify(this.afAuth.auth.currentUser)).stsTokenManager.accessToken
As seen in this discussion:
https://github.com/angular/angularfire2/issues/725
With AngularFire2 : ( eg : registering user with email and password combo. )
import { AngularFireAuth } from 'angularfire2/auth';
model : any = {} ;
private afAuth : AngularFireAuth,
regWithEP () {
this.afAuth.auth.createUserWithEmailAndPassword(this.model.email, this.model.password).then((user) => {
/* IMPORTANT !! */
/* EXPLICIT CHECK IF USER IS RETURNED FROM FIREBASE SERVICE !! */
if (user) {
console.log(user);
/* Here user is available and is the same as auth.currentUser */
this.afAuth.auth.currentUser.getToken().then((token) => {
//token is available here
//set token to currentUser, signIn , re-direct etc.
});
}
});
}

Categories

Resources