Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularFire getIdToken(true) not refreshing token

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?

like image 716
Bogomip Avatar asked Nov 22 '21 13:11

Bogomip


People also ask

How do I refresh my firebase 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.

Does firebase automatically refresh token?

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

When should I refresh my firebase token?

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.

What is the refresh token?

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.


Video Answer


2 Answers

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

}
like image 103
MaxXx1313 Avatar answered Oct 21 '22 07:10

MaxXx1313


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;
    }));
  }));
}
like image 40
Raymond Avatar answered Oct 21 '22 07:10

Raymond