sabyasachibiswal / angular5-social-login

Social authentication module for Angular 5. Includes Facebook and Google login with AOT compatibility.
40 stars 74 forks source link

Dynamically get config (app IDs) from backend #24

Open MikeDabrowski opened 6 years ago

MikeDabrowski commented 6 years ago

Hi, thank you for such a nice util library. I need to dynamically create AuthServiceConfig by fetching app ids from backend. How can I do that ?

In app.module how can I provide settings as observable/promise ?

kavithamadhavaraj commented 6 years ago

@MikeDabrowski Did you find any workaround for this?

MikeDabrowski commented 6 years ago

@kavithamadhavaraj Yes, I got a workaround which works so far, but I can't guarantee it won't stop at some point. I really 'feel' some race conditions there. The trick is to use global variable and APP_INITIALIZER

in app.module.ts:

export let APP_IDS = {
  fb: '',
  gp: ''
};
export function getAuthServiceConfigs() {
  return new AuthServiceConfig(
    [
      {
        id: FacebookLoginProvider.PROVIDER_ID,
        provider: new FacebookLoginProvider(APP_IDS.fb)
      },
      {
        id: GoogleLoginProvider.PROVIDER_ID,
        provider: new GoogleLoginProvider(APP_IDS.gp)
      }
    ]);
}
export function init_app(fas: FetchApiService) {
  return () => new Promise((resolve, reject) => {
    fas.getEnv()
      .pipe(take(1))
      .subscribe(env => {
          if (!env.fbAppId || !env.gpAppId) {
            console.error('Unable to initialize social media apps (wrong id).');
          }
          APP_IDS.fb = env.fbAppId;
          if (!env.gpAppId.endsWith('.apps.googleusercontent.com')) {
            env.gpAppId = env.gpAppId + '.apps.googleusercontent.com';
          }
          APP_IDS.gp = env.gpAppId;
          resolve();
        },
        err => reject(err));
  });
}
... 
// in providers:
    {provide: APP_INITIALIZER, useFactory: init_app, deps: [FetchApiService], multi: true},
    {provide: AuthServiceConfig, useFactory: getAuthServiceConfigs}
kavithamadhavaraj commented 6 years ago

@MikeDabrowski But I still see the App IDs in app.module.ts. It is not a good idea to expose the secret information to client side. What I was thinking is to get it from the server side code. Thanks anyways.

MikeDabrowski commented 6 years ago

Well, I'm fetching ids from backend because I want them to be easily swapped without changing the code. I don't think you can completely hide id from the client. If you worry about the ID that stays in that global variable APP_IDS you can alwas clean it up after library has been initialized, though, I think it would be hard to dig through bundled code to get those ids. Also I think on majority of big sites that use social media login, the ids are stored on frontend.

kavithamadhavaraj commented 6 years ago

@MikeDabrowski Understood :+1: Thanks for explaining :)

kavithamadhavaraj commented 6 years ago

@MikeDabrowski If your intention is to get the App IDs without changing the code, why can't they go into environment.ts file? You can read from them like this.

export function getAuthServiceConfigs() {
  const config = new AuthServiceConfig(
      [
        {
          id: GoogleLoginProvider.PROVIDER_ID,
          provider: new GoogleLoginProvider(environment.google_client_id)
        },
        {
          id: FacebookLoginProvider.PROVIDER_ID,
          provider: new FacebookLoginProvider(environment.facebook_client_id)
        }
      ]);
  return config;
}

Just being curious to know, if this won't work for your case.

MikeDabrowski commented 6 years ago

Well it should work but in our project's frontend part it would be the first and only prop set that way. All others are loaded from backend and people are used to maintain them between environments.

Another reason is that this exact frontend app is a bit crippled - it is embeded in sort of 'hacky' way into vue app wich caused problems in the past. To solve them we cut few parts of bootstraping process. I'm afraid using environment could simply not work here.