How to Implement Google Authentication in Angular

Angular
7 minutes read

Introduction

Hello developers! Today, we’re talking about Google authentication in Angular. It’s like a digital key that lets only the right people use certain online services. Many websites use Google to help with this. Why? Because many people already have Google accounts, so it’s easier for them. It’s also safe. Google keeps user information protected. In the next sections, we’ll learn how to use Google’s system in our projects. Let’s get started!

Project Setup

Starting with the basics, we need to create our Angular project by running the following command

ng new ng-google-auth

Open the generated project, and lets create our login and dashboard components, by running the following command

ng g c login
ng g c dashboard

Now we need to create our login service, by running the following command

ng g s login

Now, we need to install a third library to help us with our authentication process. This library will bridge our Angular app with Google’s authentication system.

npm i @abacritt/angularx-social-login

One las thing, we need to import the @abacritt/angularx-social-login package, open the app.module.ts and update it as follows

import { SocialLoginModule } from '@abacritt/angularx-social-login';
import { GoogleLoginProvider } from '@abacritt/angularx-social-login';
import {environment} from "../environments/environment";

@NgModule({
  declarations: [
     ...
  ],
  imports: [
     ...

    SocialLoginModule
  ],
  providers: [
    {
      provide: 'SocialAuthServiceConfig',
      useValue: {
        autoLogin: false,
        providers: [
          {
            id: GoogleLoginProvider.PROVIDER_ID,
            provider: new GoogleLoginProvider(environment.clientId)
          },
        ]
      }
    }
   ],
  bootstrap: [AppComponent]
})
export class AppModule { }

And now, we are ready to start

Notes:

  1. environment.clientId is the ID for your app that we will get in the next section
  2. You can get the full source code from here

Google Developers Console Setup

Google Developers Console is the platform allow us to register our app and connect with Google’s vast suite of services. Let’s go through it in step-by-step

Begin by navigating to the Google Developers Console. If you haven’t logged in, do so with your Google account.

Click on the dropdown menu next to the “Google Cloud Platform” logo.

At the top-right corner, click the “+ NEW PROJECT” button.

Enter your project name and any other required details, then click “CREATE.”

Now let’s enable the Google+ API. In the left-hand menu, click “Library.”


Search for “Google+ API” in the search box.


Click on the “Google+ API” card.


Now, press the “ENABLE” button. This action lets our app interact with Google’s authentication system.

Now let’s configure OAuth 2.0. On the left sidebar, click “Credentials.”

If this is your first time using Google Auth, you might get this message, if so, follow the following steps, if not, you can skip to the next step


Press the “+ CREATE CREDENTIALS” button and select “OAuth Client ID.”

For “Application type,” choose “Web application.”

Under “Authorized redirect URIs,” provide the URI where you’d like to handle authentication. For most Angular apps, this would be something like “http://localhost:4200/auth/callback“.

Note: The provided links in the screenshot is the default angular URL and port, if you are using other port you should change the port in the Authorized JavaScript origins and Authorized redirect URLs

And now you should see your app credentials, you must save them, or you can click on the “DOWNLOAD JSON” button to download your credentials

And we’re done. Now we are ready to start connecting our app with the Google API

Designing the Login Interface

For the sake of this tutorial, our UI will be simple, just one button that will trigger the Google API when clicked, following is how our UI looks like with the code

// login.component.html

<asl-google-signin-button size="large"
                          type="standard">
  Login with Google
</asl-google-signin-button>

Note: the <asl-google-signin-button></asl-google-signin-button> component is provided by @abacritt/angularx-social-login package

Implementing the Authentication Flow

Available Data After Successful Authentication

Once a user logs in successfully through Google, the user’s data becomes available. This data helps in understanding our users better and offering personalized experiences.

Upon successful authentication, you typically get an object with this structure:

{
  id: 'google-id',
  name: 'User’s Full Name',
  provider: 'google',
  photoUrl: 'URL of the profile photo',
  firstName: 'User’s first name',
  lastName: 'User’s last name',
  authToken: 'Google Auth Token',
  email: 'User’s email'
}
  • id: A unique identifier for the user from Google.
  • name: The user’s full name as registered on Google.
  • photoUrl: A direct link to the user’s Google profile picture.
  • authToken: This is the key token that validates the user’s session.
  • email: The user’s email address, useful for communication or account setup.

We will create an interface for the user’s data to make it easy to remember what data we expect from Google to give us

export interface UserData {
  id: string
  name: string
  provider: string
  photoUrl: string
  firstName: string
  lastName: string
  authToken: string
  email: string
}

Track the User’s State

Once the user clicked on the sign in button and chose the account wants to login with, the @abacritt/angularx-social-login package provides us with an observable that listens to the state change. We can use this observable to track the user’s state

  constructor(private authService: SocialAuthService,
              private router: Router) {
    this.authService.authState.subscribe((user: SocialUser) => {
      if (user) {
        console.log('User data: ', user);
        localStorage.setItem("token", user.authToken)
        localStorage.setItem("user", JSON.stringify(user))
        // Handle your authentication & routing logic here.
        this.router.navigate(['/dashboard']);
      }
    });
  }

In our application the dashboard is only allowed for the authenticated users to access it which will be handled in the next section.

Implementing Angular Route Guards for Protected Routes

To ensure only authenticated users access specific routes (e.g., dashboard), Angular offers a powerful tool called route guards. Let’s create one using the following command

ng g guard auth

You will be asked of what type of guard you want, choose the CanActivate option and hit enter

And now let’s implement our guard. The idea here is we only want the logged in users to access some routes like the dashboard route.

For this we check if the user exists then allow to continue, if not redirect the user to the login page to login first

export class AuthGuard implements CanActivate {

  constructor(private authService: SocialAuthService,
              private router: Router) {
  }

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    return this.authService.authState.pipe(
      // Convert user object to boolean (true if user exists, false otherwise)
      map(user => !!user),
      tap(isAuthenticated => {
        if (!isAuthenticated) {
          this.router.navigate(['/login']);
        }

        return isAuthenticated
      })
    );
  }
}

To use this guard, modify your routing configuration:

const routes: Routes = [
  {
    path: '',
    redirectTo: '/login',
    pathMatch: 'full'
  },
  {
    path: 'login',
    component: LoginComponent
  },
  {
    path: 'dashboard',
    component: DashboardComponent,
    // Protecting route with AuthGuard
    canActivate: [AuthGuard]
  }
];

Handling and Storing Tokens Securely

Making safe web apps is important. We need to keep special keys, called tokens, safe. If we don’t, bad people might use them. In this section, we’ll talk about how to keep these keys safe.

When it comes to storing tokens on the client side, there are two popular methods: localStorage and HttpOnly cookies.

localStorage

This web storage solution allows sites to store data as key-value pairs in a web browser with no expiration time.

// Storing a token in localStorage
localStorage.setItem('authToken', 'YOUR_TOKEN_HERE');

// Retrieving a token from localStorage
const token = localStorage.getItem('authToken');

Pros

  • Easy to use.
  • Persistent across browser sessions.

Cons

  • Vulnerable to Cross-Site Scripting (XSS) attacks, as malicious scripts can access the data stored in localStorage.

HttpOnly cookies

These are cookies that are inaccessible via JavaScript and can only be set or read by the server.

// Example of setting an HttpOnly cookie from a server-side
res.cookie('authToken', 'YOUR_TOKEN_HERE', { httpOnly: true });

Pros

  • Safe from XSS attacks due to their inaccessibility via JavaScript.

Cons

  • More complex setup compared to localStorage.
  • Vulnerable to Cross-Site Request Forgery (CSRF) attacks, though measures like using anti-CSRF tokens can help reduce this risk.

While localStorage offers convenience, HttpOnly cookies win in terms of security against XSS attacks. Your choice should weigh the risks and the specific needs of your application.

For the sake of this tutorial we will implement the localstorage method. Let’s update the signIn() method as follows

  signInWithGoogle(): void {
    this.authService.signIn(GoogleLoginProvider.PROVIDER_ID)
      .then((userData: UserData) => {
        // Add this line
        localStorage.setItem("token", userData.authToken)
        ...
      })
      .catch((error: any) => {
        console.error('Error occurred while logging in:', error);
      });
  }

Logging Out

Logging in is only half the story. Equally important is ensuring users can log out smoothly and securely. Let’s walk through the basics of how to properly implement this crucial step in our app.

In our Angular application, the logout method will help us clear the stored token, ensuring the user’s session ends.

  logout(): void {
    this.authService.signOut().then(() => {
      // Clear the token or session information
      localStorage.removeItem('token');
      this.router.navigate(['/login']);
    });
  }

In this code, we use the signOut method from the authentication service to end the user’s session. Then, we remove the token from localStorage, and redirect the user to the login page.

Further Reading

Conclusion

In conclusion, we learned how to add Google login to our app. It’s important to make login easy for users. But, we must also keep it safe. Safety is very important in online apps. Always do your best to keep your app and users safe. Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *