How to implement sign in with google in Angular

21.7k Views Asked by At

I am trying to implement google sign-in functionality in my angular app. I have used two packages here @abacritt/angularx-social-login and angular-oauth2-oidc.

I have created a custom provider called google-authentication.service.ts same as from this repository Link. With this approach after a successful sign-in the dialog is not closed and also I am not able to get the logged-in user details.

Question: Please suggest a way to close the dialog after a successful sign-in and get the logged-in user credentials

google-authentication.service.ts:

@Injectable()
export class GoogleAuthenticationService implements LoginProvider {
    constructor(private readonly _oAuthService: OAuthService) {
        this.createConfiguration();
    }

    private readonly _tokenReceived$ = this._oAuthService.events.pipe(
        filter((e) => e.type === 'token_received'),
        map(() => true as const)
    );

    private createConfiguration(): void {
        let redirectUri = window.location.origin + window.location.pathname;
        if (redirectUri.endsWith('/')) {
            redirectUri = redirectUri.substring(0, redirectUri.length - 1);
        }

        this._oAuthService.configure({
            issuer: 'https://accounts.google.com',
            strictDiscoveryDocumentValidation: false,
            redirectUri,
            silentRefreshRedirectUri: redirectUri,
            useSilentRefresh: true,
            clientId: environment.googleClientId,
            scope: 'openid profile email'
        });
    }

    async initialize(autoLogin?: boolean): Promise<void> {
        await this._oAuthService.loadDiscoveryDocument();
        if (autoLogin) {
            await this._oAuthService.tryLoginImplicitFlow();
        }
    }

    async signIn(): Promise<SocialUser> {
        const tokenReceivedPromise = firstValueFrom(this._tokenReceived$);

        await this._oAuthService.initImplicitFlowInPopup();
        await tokenReceivedPromise;

        return this.createUser(this._oAuthService.getIdToken());
    }

    async getLoginStatus(): Promise<SocialUser> {
        if (this._oAuthService.hasValidIdToken()) {
            return this.createUser(this._oAuthService.getIdToken());
        } else {
            throw `No user is currently logged in`;
        }
    }

    async signOut(revoke?: boolean): Promise<void> {
        if (revoke) {
            this._oAuthService.revokeTokenAndLogout(true, true);
        } else {
            this._oAuthService.logOut(true);
        }
    }

    private createUser(idToken: string): SocialUser {
        const user = new SocialUser();
        const payload = JSON.parse(window.atob(idToken.split('.')[1]));
        user.idToken = idToken;
        user.id = payload.sub;
        user.name = payload.name;
        user.email = payload.email;
        user.photoUrl = payload.picture;
        user.firstName = payload['given_name'];
        user.lastName = payload['family_name'];
        return user;
    }
}

Login-component.ts

ngOnInit(): void {
    this._googleAuthService.initialize();
}

signUpWithGoogle(event: Event): void {
    this._googleAuthService
        .signIn()
        .then((user) => {
            //not showing anything in console
            console.log(user);
        })
        .catch((error) => {
            console.log(error);
        });
}
1

There are 1 best solutions below

2
Dimitar Stojanovski On

It's work for me in this way. According to the new documentation of Google (https://developers.google.com/identity/gsi/web/guides/overview), you should follow next steps:

  1. Create a google app in google cloud console platform and generate a client id.

  2. Load the client library. Add this script "<script src="https://accounts.google.com/gsi/client" async defer>" between the <head></head> tags of your index.html file of Angular project.

  3. Add this code on ngOnInit() function in the component that you would like to have "Sign in with Google button."

ngOnInit() {
  // @ts-ignore
  google.accounts.id.initialize({
    client_id: "YOUR GOOGLE CLIENT ID",
    callback: this.handleCredentialResponse.bind(this),
    auto_select: false,
    cancel_on_tap_outside: true,

  });
  // @ts-ignore
  google.accounts.id.renderButton(
  // @ts-ignore
  document.getElementById("google-button"),
    { theme: "outline", size: "large", width: "100%" }
  );
  // @ts-ignore
  google.accounts.id.prompt((notification: PromptMomentNotification) => {});
}  
async handleCredentialResponse(response: any) {
  // Here will be your response from Google.
  console.log(response);
}
  1. Add div or button element to the html file of this component, with the same id that you mentioned into the initialization. ( "google-button" ):

<div class="" id="google-button"></div>.

Let me know if you have any issues.