Firebase Auth Refresh Token? - javascript

How do I get access to the refreshed token in Firebase Auth?
I'm building a React app, and on the signin button click run Login function. This function gives me a Google API token which I use to access google drive api.
The problem is that is token expires after an hour. This post mentions:
"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."
As such I've gone ahead and set this function up. However, how do I access this new updated token so that I can pass it along to the rest of the app?
Login Function
const login = async () => {
signInWithPopup(auth, provider)
.then((result) => {
// This gives you a Google Access Token. You can use it to access the Google API.
const credential = GoogleAuthProvider.credentialFromResult(result);
const token = credential.accessToken;
}
onIdTokenChanged
onIdTokenChanged(auth, (currentUser) => {
console.log(currentUser);
setUser(currentUser);
});

Related

How to retrieve Token for API calls in cypress

Due to a lack of knowledge in JS, I do face with below problem.
I do automation testing with cypress and for external API endpoints, I need to use Dynamic Token that expires every 3600 secs.
I did some short research and find out that, for reaching to JWT Token I will need 1st SSO login (that my app has). Then use the below script.
But I don't know what to do after this.
it('the value of JWT Token should exist in localStorage', () => {
cy.getLocalStorage('JWT_DATA').then(lsData => {
cy.log('the token', lsData); // I get JWT Token in here
});
});
The result of this script is only printing the TOKEN.
But I need to store it somehow and then be able to reuse it for every different API endpoint call.
You can use Cypress.env for this. Then you can use the token throughout the test anywhere.
it('the value of JWT Token should exist in localStorage', () => {
cy.getLocalStorage('JWT_DATA').then((lsData) => {
cy.log('the token', lsData) // I get JWT Token in here
Cypress.env('token', lsData)
})
})
To use it, you can do
Cypress.env('token')

Most ideal way to call firebase getIdToken

i am implementing user authentication with the help of firebase in my React project. So, I am confused over something.
I am verifying the user from firebase and then getting a token on frontend which is sent to backend via headers and verfied there once.
I read the docs and came to know that firebase token gets expired after 1 hr by default so we have to use "getIdToken" like
firebase.auth().onAuthStateChanged(async user => {
if (user) {
console.log(user, 'user123 inside firebaseAuth')
const token = await user.getIdToken()
Cookies.set('my_token', token, { domain: domain })
}
})
but how do i manage this function , do i have to call it everytime the component updates or everytime before hitting api or first time the component renders ?
The thing is i do not want this token to get expire until the user logs out himself / herself even if he is in a different component and sitting ideal for too long.
You can get the Firebase ID Token every time you are making an API call to your server:
async function callAPI() {
const user = firebase.auth().currentUser
if (user) {
const token = await user.getIdToken()
const res = await fetch("url", {
headers: {authorization: `Bearer ${token}`}
})
} else {
console.log("No user is logged in")
}
}
You could get the ID token once when the component mounts but then you'll have to deal with onIdTokenChanged to keep it updated in your state. Using the method above you'll get a valid token always.

Firebase Web SDK: refreshing auth token so that email_verified is updated in firestore rules

Using Firebase Web SDK, I'm requiring users to verify their email before accessing Firestore documents. I have a Firestore rule that gates the document like this:
allow read: if request.auth != null && request.auth.token.email_verified;
I'd like the email verification to be reflected as soon as the user verifies his/her email without requiring the user to sign out and sign back in. Unfortunately onAuthStateChanged() doesn't fire when emailVerified changes, so I'm refreshing the client token by polling for changes to emailVerified. Something like this:
Note: My examples use the new beta Firebase Web SDK V9 (Modular Web SDK) in case the syntax is unfamiliar.
window.setInterval(() => {
reload(auth.currentUser).then(() => {
if (!auth.currentUser?.emailVerified)
return;
// unsubscribe the previous onAuthStateChanged() listener
unsubscribe();
// resubscribe to auth changes
unsubscribe = auth.onAuthStateChanged(user => {
// Yay! user.emailVerified is now true
console.log(user.emailVerified);
});
});
}, 2000);
With the code above, I can get emailVerified to be reflected property inside my web app, but the problem arises when I try to make a request to Firestore:
const unsubscribe = onSnapshot(
doc(db, 'widgets', 'widget1'),
snap => {
console.log(snap);
},
);
That request results in a Firestore permission error. Once the user signs out and signs back in, the Firestore request is accepted.
How can I get the auth token that gets sent to Firestore to be updated with the latest email_verified without the user to sign out and and sign back in?
It turns out that a series of steps need to happen to refresh the token. After email verification, you need to reload the user AND explicitly get a new id token with getIdToken(user, true) after you reload the user. Only after those 2 steps will an updated token be sent to Firestore for queries. You also need to unsubscribe and re-subscribe to onAuthStateChanged manually, as that doesn't get triggered on token change. The modified version of my example is:
window.setInterval(() => {
reload(auth.currentUser).then(() => {
if (!auth.currentUser?.emailVerified)
return;
getIdToken(auth.currentUser, true).then(() => {
// now the new token will be sent to Firestore, yay!
// unsubscribe the previous onAuthStateChanged() listener
unsubscribe();
// resubscribe to auth changes
unsubscribe = auth.onAuthStateChanged(user => {
// Yay! user.emailVerified is now true
console.log(user.emailVerified);
});
})
});
}, 2000);
Please post your answer if there's an easier way. I especially don't like the polling part.

Explicit renewal of session tokens in Firebase JS SDK

I have implemented the signin method using Firebase Auth for several providers like that:
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL).then(() => {
let provider = new firebase.auth.GoogleAuthProvider(); // + facebook, gitHub
provider.addScope('profile');
provider.addScope('email');
firebase.auth().signInWithPopup(provider).then(result => {
// app logic here
However this code gives me 60 min lasting sessions and I want to learn how to automatically renew the current user session without being forced to login every hour.
I'm also 'listening' to the current user session state using this code.
firebase.auth().onAuthStateChanged(user => if (!user) //goto LoginPage
But it doesn't 'listen' per se, it works only when I try to navigate or update the page. So I don't know how to restrict access by the exact amount of time (e.g. 15 minutes max) using Firebase methods.
The documentation says there is a getIdToken method but I can't wrap my head around where to use this code. Should it be invoked every 60 minutes just before the expiration or it should be set at the time of login? Please give some hints or any tutorials covering this very situation.
EDIT:
Also I get this code in the console after some period of inactivity (I think less than 1 hour):
auth.esm.js:121 POST https://securetoken.googleapis.com/v1/token?key=AIza... 403
Firebase tokens are set to expire after 60 min. Then it gets refreshed for you automatically. There is no way to configure the expiration time, and you don't need to do anything special in your front-end code for that.
The only trick is that, you need to grant your application API key the permission to use the Token Service API to be able to mint a new id token for you once it's expired. This is done in the GCP console, API & Services (Credentials).
So, the code should be simple as the following
Add the user authentication state change Listener
fbAuth.onAuthStateChanged(user => {
if (user) {
// User is logged in
// Proceed with your logged in user logic
} else {
// USer is not logged in
// Redirect to the login page
}
})
Implement the login logic
fbAuth.setPersistence(firebase.auth.Auth.Persistence.LOCAL)
.then(() => {
return fbAuth.signInWithEmailAndPassword(email, password)
.then(userCredential => {
// Login success path
})
.catch(error => {
// Login error path
});
})
.catch(error => {
// Persistence setting error path
})
You can set the Authentication State Persistence before the login, depending on your use cases auth-state-persistence.
Make sure that your application API key has access to the Token Service API in the GCP console
This is under
GCP Console | APIs & Services | Credentials
Then edit the corresponding key to your deployment environment to grant the API key the access to the Token Service API.
Good luck ;)
Hello first I am gonna say sorry fro my bad english. I dont really understand firebase but i think it should work if you write something like this:
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION).then(() => {
let provider = new firebase.auth.GoogleAuthProvider(); // + facebook, gitHub
provider.addScope('profile');
provider.addScope('email');
firebase.auth().signInWithPopup(provider).then(result => {
// app logic here
I meant that you should have firebase.auth.Auth.Persistence.SESSION insted of LOCAL

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