2

I've set up a firebase passport strategy on a NestJS server which works fine, but I did not like the long load times it would incur on all requests that went through it. So I decided to cache decoded tokens until they are expired, and this this massively reduced load times for valid and unexpired tokens.

However, I am concerned that there might be security risks connected to this. Mostly because this seemed like such a simple addition to me, someone must have thought about it before. I assume the people who made the firebase sdk must have considered adding it as a feature, but why haven't they?

For reference, here's the code for my passport strategy:

@Injectable()
export class FirebaseAuthStrategy extends PassportStrategy(Strategy, 'firebase-auth') {
  private defaultApp: any;

  constructor(
    private configService: ConfigService,
    @Inject(CACHE_MANAGER) private cacheManager: Cache
  ) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
    });
    const config = this.configService.get<string>('FIREBASE_CONFIG');
    if (!config) {
      throw new Error('FIREBASE_CONFIG not available. Please ensure the variable is supplied in the `.env` file.');
    }
    const firebase_params = JSON.parse(config);

    this.defaultApp = firebase.initializeApp({
      credential: firebase.credential.cert(firebase_params)
    });
  }

  async validate(token: string) {
    const cachedFirebaseUser = await this.cacheManager.get(token);
    if (cachedFirebaseUser) return cachedFirebaseUser;

    const firebaseUser: any = await this.defaultApp
      .auth()
      .verifyIdToken(token, true)
      .catch((err) => {
        console.log(err);
        throw new UnauthorizedException(err.Message);
      });

    if (!firebaseUser) {
      throw new UnauthorizedException();
    }

    /**
     * input parameter for `Date` or `moment` constructor is in milliseconds for unix timestamps.
     * input * 1000 will instantiate correct Date or moment value.
     * See here for reference: https://stackoverflow.com/a/45370395/5472560
     */
    const exp = moment(+firebaseUser['exp'] * 1000);
    const now = moment.now();
    const ttl = exp.diff(now, 'seconds');

    await this.cacheManager.set(token, firebaseUser, { ttl });

    return firebaseUser;
  }
}
H.Rahimy
  • 300
  • 3
  • 14
  • Have you checked this? [Why caching access token is consider bad in oauth2?](https://stackoverflow.com/questions/47412971/why-caching-access-token-is-consider-bad-in-oauth2) – Dharmaraj Sep 13 '21 at 11:52

1 Answers1

4

As long as you don't use the decoded as a signal of authorization after the token has expired, it is perfectly safe to cache a decoded token. Caching ID tokens is a valid approach to prevent having to decode them on each call.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807