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

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.
});
}
});
}

Related

Firebase Auth Refresh Token?

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);
});

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 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.

getIdToken() is not a function, even if It is used like a function in firebase document

I am dealing with firebase auth now and I was following this Firebase document.
Visit https://firebase.google.com/docs/auth/admin/manage-cookies#sign_in
// When the user signs in with email and password.
firebase.auth().signInWithEmailAndPassword('user#example.com', 'password').then(user => {
// Get the user's ID token as it is needed to exchange for a session cookie.
return user.getIdToken().then(idToken = > {
// Session login endpoint is queried and the session cookie is set.
// CSRF protection should be taken into account.
// ...
const csrfToken = getCookie('csrfToken')
return postIdTokenToSessionLogin('/sessionLogin', idToken, csrfToken);
});
})
I expected that I could get a token by using that function. But It doesn't work because user in the code doesn't have getIdToken() function.
Seems like things changed since 7.* version. To get it:
firebase.auth().signInWithEmailAndPassword('user#example.com', 'password').then(({ user }) => {
// Get the user's ID token as it is needed to exchange for a session cookie.
return user.getIdToken().then(idToken = > {
// Session login endpoint is queried and the session cookie is set.
// CSRF protection should be taken into account.
// ...
const csrfToken = getCookie('csrfToken')
return postIdTokenToSessionLogin('/sessionLogin', idToken, csrfToken);
});
})
Note, that you need to use user.user.getIdToken() now, or just use destructuring as I did in the example.
To get the id token, just call auth's currentUser#getIdToken directly.
const idToken = await firebase.auth().currentUser.getIdToken()

Firebase Custom Claims doesn't propagate

I'm working in an Angular6 app with angularfire2. I'm setting the roles as custom claims in user creation, but it doesn't seem to propagate.
When I'm creating the user I send the userid, businessid and role to a cloud function:
bid > businessid
urole > role
req.body.uid > userid
const customClaims = {
roles: { [bid]: urole }
}
admin.auth().setCustomUserClaims(req.body.uid, customClaims)
.then(result => {
res
.status(200)
.send()
})
The problem is when the call to cloud function finishes and I want to redirect the user to a route which requires the user to have the custom claim set, but it fails. After some debugging, I've found out that if run:
this.angularFireAuth.auth.currentUser.getIdTokenResult(true).then(result => {
return result.claims.roles
})
immediately after the call to the cloud function "result.claims.roles" is undefined, but if I refresh the page, "result.claims.roles" have the data I set before.
I've already tried the reload method, and getIdToken(true) but I'm getting the same problem.
Is there a way to avoid refreshing the page and get the custom claims?
Thank you!
When the user is signed in, they get an ID token that is valid for about an hour. If you set a custom claim, their (server-side) profile is updated immediately, but their ID token is not auto-updated. So you'll need to refresh their ID token to get the new custom claims.
As far as I know this ID token is only refreshed by calling getIdTokenResult if it has expired. If that's the cause, calling user.reload() and then getting the ID token should give you the updated claims.
For me it simply worked taking the advice from one of the comments:
// --------
// Frontend
// --------
// Triggering the cloud function
const url: string = 'url-to-your-cloud-function'
await this.http.post<unknown>(url, {}).toPromise();
// After cloud function was run and custom claim was set -> refresh the id token
// The 'currentUser' is a reference to the firebase user
await this.authService.currentUser.getIdToken(true);
// --------
// Cloud Function - createSubscription
// --------
const createSubscription = () => {
await admin.auth().setCustomUserClaims(userId, {
subscriber: true
})
}

Categories

Resources