I have an angularfire authentication service which works absolutely fine - except it wont refresh the token.
My refresh code:
firebase.auth().currentUser.getIdToken(true).then((token: string) => {
const newUser = { token: token }; // new user details in brief
this.user.next(newUser);
});
calls the firebase service just fine and gives a response, but it only returns the current token and doesn't refresh the token - so it still logs out of the app after 1 hour.
I have read a multitude of issues regarding getIdToken but none which specifically address a token not refreshing.
I made a stackblitz: https://stackblitz.com/edit/angular-ivy-uvcdz7?file=src/app/app.component.ts so you can see the code in full (though it doesn't work for some reason, but also because I cant work out how to connect the project to firebase via SB)
edit
To help there are some other odd behaviours I dont expect, for example in my ngOnInit I have...
this.fAuth.onAuthStateChanged((state) => {
console.log(state);
})
which does nothing when I log in or out - no message to say the state has changed. None of these functions which I expect to trigger when things change in the authentication seem to do anything.
edit 2
As added info, before I added the bounty I did a full and painful update of Angular and AngularFire, so now Angular is v13 and AngularFire is 7.2.0 to see if this would make any difference, but it did not, the getIdToken still provides no refresh of the token.
edit 3
So this function was provided as an answer below:
public getToken$(): Observable<firebase.auth.IdTokenResult> {
return from(this.fAuth.currentUser).pipe(switchMap(user => {
return from(user.getIdTokenResult(true)).pipe(map(token => {
console.log(token);
return token;
}));
}));
}
which returns a user object:
{ "claims": { "name": "Bogomip", "picture": "piccie", "admin": true, "iss": "https://securetoken.google.com/repo", "aud": "repo", "auth_time": 1638464159, "user_id": "user id", "sub": "user id", "iat": 1638464323, "exp": 1638467923, "email": "[email protected]", "email_verified": true, "firebase": { "identities": { "email": [ "[email protected]" ] }, "sign_in_provider": "password" } }, "token": "THIS IS THE TOKEN", "authTime": "Thu, 02 Dec 2021 16:55:59 GMT", "issuedAtTime": "Thu, 02 Dec 2021 16:58:43 GMT", "expirationTime": "Thu, 02 Dec 2021 17:58:43 GMT", "signInProvider": "password", "signInSecondFactor": null }
this is the 'token' that is logged in that function, but is the token in this (token.token) the refresh id OR the actual token? Because it doesnt change, but that would make sense if it was the refresh token.... do we ever get to see the actual token?
You can refresh a Firebase ID token by issuing an HTTP POST request to the securetoken.googleapis.com endpoint. The refresh token's grant type, always "refresh_token". A Firebase Auth refresh token. The number of seconds in which the ID token expires.
These tokens expire after one hour, but are automatically refreshed by the Firebase SDK using the refresh token (see next numbered bullet). These are the tokens you should use to identify users on your own server (if needed; and described here).
Every time a user signs in, the user credentials are sent to the Firebase Authentication backend and exchanged for a Firebase ID token (a JWT) and refresh token. Firebase ID tokens are short lived and last for an hour; the refresh token can be used to retrieve new ID tokens.
A refresh token is a special token that is used to obtain additional access tokens. This allows you to have short-lived access tokens without having to collect credentials every time one expires.
Firebase handle the token refresh process, so there is no need to manually refresh the token. Firebase auth state can be read from 'authState' property.
@Injectable({
providedIn: 'root',
})
export class AuthenticationService implements OnInit {
public readonly userId$: Observable<string>;
public readonly profile$: Observable<MyProfile>;
constructor(
public firestore: AngularFirestore,
public fAuth: AngularFireAuth,
private router: Router,
) {
this.userId$ = this.fAuth.authState.pipe(
map(fbUser => fbUser ? fbUser.uid : null),
distinctUntilChanged(),
tap(uid => {
console.log('AuthService: userId$', uid);
}),
shareReplay(1),
);
this.profile$ = this.authService.userId$.pipe(
switchMap(authId => {
if (authId) {
return this.getById(authId);
} else {
return EMPTY;
}
}),
tap(profile => {
console.log('[AuthService] profile$', profile);
}),
shareReplay(1),
);
}
public getById(id: string): Observable<MyProfile> {
return this.firestore.doc<MyProfile>('users/'+id).get();
}
}
You can force refresh the token using Observables this way:
public getToken$(): Observable<firebase.auth.IdTokenResult> {
return from(this.angularFireAuth.currentUser).pipe(switchMap(user => {
return from(user.getIdTokenResult(true)).pipe(map(token => {
return token;
}));
}));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With