Implementing Google Sign-In in an Angular application allows users to authenticate using their Google accounts, providing a seamless and secure login experience. Below is a comprehensive, step-by-step guide to integrating Google Sign-In using the latest Google Identity Services (GIS) library.
Table of Contents
- Prerequisites
- Create a Google Cloud Project and Configure OAuth Consent
- Install Required Dependencies
- Add Google Identity Services Script
- Create a Google Sign-In Component
- Handle Authentication
- Protect Routes (Optional)
- Logout Functionality
- Security Considerations
- Conclusion
Prerequisites
Before you begin, ensure you have the following:
- Angular CLI installed. If not, install it using:
npm install -g @angular/cli
- Node.js and npm installed on your machine.
- A Google account to access Google Cloud Console.
1. Create a Google Cloud Project and Configure OAuth Consent
- Create a New Project:
- Go to the Google Cloud Console.
- Click on the project dropdown and select New Project.
- Enter a Project Name and click Create.
- Configure OAuth Consent Screen:
- Navigate to APIs & Services > OAuth consent screen.
- Choose External for the user type and click Create.
- Fill in the App name, User support email, and other required fields.
- Add Scopes as needed (for basic sign-in, default scopes are sufficient).
- Add Test Users if you're using an external user type.
- Save and continue through the steps until completion.
- Create OAuth 2.0 Client ID:
- Go to APIs & Services > Credentials.
- Click Create Credentials > OAuth client ID.
- Select Web application as the application type.
- Enter a Name (e.g., "Angular App").
- In Authorized JavaScript origins, add your development and production URLs, e.g.,
http://localhost:4200
andhttps://yourdomain.com
. - In Authorized redirect URIs, add the redirect URI if needed (for GIS, it might not be necessary).
- Click Create and note down the Client ID.
2. Install Required Dependencies
For this implementation, we'll use the Google Identity Services (GIS) library directly without additional Angular-specific packages.
Optionally, you can install @types/google.accounts
for TypeScript support.
npm install --save @types/google.accounts
Note: If @types/google.accounts
is not available, you can declare the types manually.
3. Add Google Identity Services Script
You need to include the GIS library in your Angular application. The recommended way is to add the script in the index.html
.
Open
src/index.html
.Add the following script tag inside the
<head>
section:
<script src="https://accounts.google.com/gsi/client" async defer></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>YourApp</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<script src="https://accounts.google.com/gsi/client" async defer></script>
</head>
<body>
<app-root></app-root>
</body>
</html>
4. Create a Google Sign-In Component
Create a dedicated component for handling Google Sign-In.
- Generate a new component:
ng generate component google-sign-in
- Implement the Component:
Open src/app/google-sign-in/google-sign-in.component.ts
and update it as follows:
import { Component, OnInit, NgZone } from '@angular/core';
declare const google: any;
@Component({
selector: 'app-google-sign-in',
templateUrl: './google-sign-in.component.html',
styleUrls: ['./google-sign-in.component.css']
})
export class GoogleSignInComponent implements OnInit {
constructor(private ngZone: NgZone) { }
ngOnInit(): void {
this.initializeGoogleSignIn();
}
initializeGoogleSignIn() {
google.accounts.id.initialize({
client_id: 'YOUR_GOOGLE_CLIENT_ID',
callback: (response: any) => this.handleCredentialResponse(response)
});
google.accounts.id.renderButton(
document.getElementById('google-signin-button'),
{ theme: 'outline', size: 'large' } // customization attributes
);
google.accounts.id.prompt(); // also display the One Tap dialog
}
handleCredentialResponse(response: any) {
// response.credential is the JWT token
console.log('Encoded JWT ID token: ' + response.credential);
// You can decode the JWT token here or send it to your backend for verification
// For demonstration, we'll just log it
// If using NgZone, ensure any UI updates are run inside Angular's zone
this.ngZone.run(() => {
// Update your application state here, e.g., store user info, navigate, etc.
});
}
}
Important:
- Replace
'YOUR_GOOGLE_CLIENT_ID'
with the Client ID obtained from the Google Cloud Console. -
handleCredentialResponse
will receive a credential (JWT) that you can verify on your backend.
- Update the Component Template:
Open src/app/google-sign-in/google-sign-in.component.html
and add a container for the Google Sign-In button:
<div id="google-signin-button"></div>
You can style or position this div as needed.
- Add the Component to Your App:
For example, include it in app.component.html
:
<app-google-sign-in></app-google-sign-in>
5. Handle Authentication
After the user signs in, you'll receive a JWT (JSON Web Token) in the handleCredentialResponse
callback. You need to:
- Decode the JWT (Optional Client-Side):
For security reasons, it's recommended to verify the token on the server. However, if you need to decode it client-side:
npm install jwt-decode
import jwt_decode from 'jwt-decode';
handleCredentialResponse(response: any) {
const token = response.credential;
const decoded: any = jwt_decode(token);
console.log(decoded);
// Extract user information
const user = {
name: decoded.name,
email: decoded.email,
picture: decoded.picture,
// ... other fields
};
// Handle user data as needed
}
- Verify the Token on the Backend:
It's crucial to send the token to your backend server for verification to ensure its validity and to prevent security issues.
Example (assuming you have a backend API endpoint):
import { HttpClient } from '@angular/common/http';
constructor(private ngZone: NgZone, private http: HttpClient) { }
handleCredentialResponse(response: any) {
const token = response.credential;
// Send the token to your backend for verification
this.http.post('https://your-backend.com/api/auth/google', { token })
.subscribe({
next: (res) => {
// Handle successful authentication
},
error: (err) => {
// Handle errors
}
});
}
Backend Verification:
On your server, use Google's libraries to verify the token's integrity. For example, in Node.js:
const { OAuth2Client } = require('google-auth-library');
const client = new OAuth2Client(CLIENT_ID);
async function verify(token) {
const ticket = await client.verifyIdToken({
idToken: token,
audience: CLIENT_ID,
});
const payload = ticket.getPayload();
const userid = payload['sub'];
// If request specified a G Suite domain:
// const domain = payload['hd'];
return payload;
}
6. Protect Routes (Optional)
To protect certain routes in your Angular application and ensure that only authenticated users can access them, you can implement route guards.
- Create an Auth Service:
Generate a service to manage authentication state.
ng generate service auth
// src/app/auth.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private authState = new BehaviorSubject<boolean>(false);
authState$ = this.authState.asObservable();
constructor() { }
setAuthState(state: boolean) {
this.authState.next(state);
}
isAuthenticated(): boolean {
return this.authState.value;
}
}
- Update Auth Service on Sign-In:
In your GoogleSignInComponent
, inject and use the AuthService
:
import { AuthService } from '../auth.service';
constructor(private ngZone: NgZone, private authService: AuthService) { }
handleCredentialResponse(response: any) {
// After successful verification with backend
this.ngZone.run(() => {
this.authService.setAuthState(true);
// Navigate to a protected route, e.g.,
// this.router.navigate(['/dashboard']);
});
}
- Create an Auth Guard:
ng generate guard auth
// src/app/auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) { }
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
if (this.authService.isAuthenticated()) {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
}
}
- Protect Routes:
In your routing module, apply the guard to routes that require authentication.
// src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';
import { LoginComponent } from './login/login.component';
import { AuthGuard } from './auth.guard';
const routes: Routes = [
{ path: 'login', component: LoginComponent },
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
{ path: '', redirectTo: '/login', pathMatch: 'full' },
// ... other routes
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
7. Logout Functionality
To allow users to log out, you need to clear their authentication state and optionally revoke the token.
- Add a Logout Method in Auth Service:
// src/app/auth.service.ts
logout() {
this.authState.next(false);
// Optionally, revoke the token
google.accounts.id.disableAutoSelect();
// Remove tokens from storage if stored
}
- Create a Logout Button:
In your component (e.g., DashboardComponent
), add a logout button.
<button (click)="logout()">Logout</button>
// src/app/dashboard/dashboard.component.ts
import { Component } from '@angular/core';
import { AuthService } from '../auth.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent {
constructor(private authService: AuthService, private router: Router) { }
logout() {
this.authService.logout();
this.router.navigate(['/login']);
}
}
8. Security Considerations
Token Verification: Always verify the ID token on your backend server to ensure its integrity and to prevent malicious logins.
HTTPS: Ensure your application is served over HTTPS, especially in production, as OAuth 2.0 requires secure contexts.
Scopes: Request only the necessary scopes needed for your application to minimize privacy concerns.
Token Storage: Avoid storing tokens in localStorage or sessionStorage to prevent XSS attacks. Consider using HttpOnly cookies for storing tokens if possible.
9. Conclusion
Integrating Google Sign-In into your Angular application enhances user experience by providing a quick and secure authentication method. By following the steps outlined above, you can implement Google Sign-In using the latest Google Identity Services library, ensuring your application adheres to current best practices and security standards.
Remember to handle tokens securely and verify them on your backend to maintain the integrity and security of your authentication flow. Additionally, always keep your dependencies updated and monitor Google's documentation for any changes or updates to their authentication services.
If you encounter any issues or need further customization, refer to the Google Identity Services documentation for more detailed information and advanced configurations.
Top comments (2)
Thank you, this helped alot.
I'm glad it helped. I have yet another approach. I will write about it soon.