Bogomip
Bogomip

Reputation: 437

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?

Upvotes: 6

Views: 1970

Answers (2)

Raymond
Raymond

Reputation: 570

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

Upvotes: 1

MaxXx1313
MaxXx1313

Reputation: 620

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

}

Upvotes: 2

Related Questions