Integrate Google Authentication in NestJS with Passport
Integrating third-party authentication into your NestJS application can greatly enhance both security and user experience. Leveraging Passport, a popular authentication middleware for Node.js, you can integrate a range of social login options with ease. This article will guide you through setting up Google Authentication in a NestJS application using Passport.
What is Passport?
Passport is an authentication middleware for Node.js that provides a simple yet robust framework for handling various authentication strategies. With a wide range of strategies available, it supports many services like Google, Facebook, Twitter, and more. Since it is designed to be modular, you can easily integrate multiple authentication strategies into your application.
Why Use Google Authentication?
Using Google Authentication can offer numerous benefits:
- Improved User Experience: Allows users to log in with their Google account, reducing the need to remember another password.
- User Verification: Ensures user identities are verified through Google, boosting security.
- Quick Implementation: Simplifies the backend code, allowing for a quick setup.
Setting Up a NestJS Project
Firstly, set up a basic NestJS project. If you haven't created one yet, you can do so by running:
nest new my-nestjs-app
cd my-nestjs-app
This command will scaffold a new NestJS project. Once set up, you need to install the necessary dependencies:
npm install @nestjs/passport passport-google-oauth20 passport
npm install @nestjs/jwt bcryptjs
npm install @types/bcryptjs --save-dev
These packages will provide the tools needed to handle authentication and token management.
Setting Up Google OAuth 2.0
- Google Developer Console: Create a new project in the Google Developer Console.
- Enable APIs: Enable the Google+ API and Google Identity API.
- OAuth Credentials: Create new credentials as OAuth 2.0 Client IDs. You're required to provide an authorized redirect URI, which might look like
http://localhost:3000/auth/google/callback
.
Configuring Passport Strategy
Create a new file named google.strategy.ts
under a new folder, src/auth/strategies
:
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, VerifyCallback } from 'passport-google-oauth20';
import { AuthService } from '../auth.service';
@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
constructor(private readonly authService: AuthService) {
super({
clientID: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
callbackURL: 'http://localhost:3000/auth/google/callback',
scope: ['email', 'profile'],
});
}
async validate(accessToken: string, refreshToken: string, profile: any, done: VerifyCallback): Promise<any> {
const { name, emails } = profile;
const user = {
email: emails[0].value,
firstName: name.givenName,
lastName: name.familyName,
accessToken,
};
done(null, user);
}
}
Replace 'YOUR_CLIENT_ID'
and 'YOUR_CLIENT_SECRET'
with the respective values generated in the Google Developer Console.
Implement Authentication Service
Create an auth.service.ts
in the src/auth
folder:
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(private readonly jwtService: JwtService) {}
async validateUser(payload: any): Promise<any> {
// Perform any necessary user validation here
return { userId: payload.sub, username: payload.username };
}
login(user: any) {
const payload = { username: user.username, sub: user.userId };
return {
access_token: this.jwtService.sign(payload),
};
}
}
Create a Controller for Authentication
Now, let's build an auth.controller.ts
to handle login routes:
import { Controller, Get, Req, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { AuthService } from './auth.service';
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Get('google')
@UseGuards(AuthGuard('google'))
async googleAuth(@Req() req) {}
@Get('google/callback')
@UseGuards(AuthGuard('google'))
googleAuthRedirect(@Req() req) {
return this.authService.login(req.user);
}
}
NestJS Module Setup
Integrate everything in a module – update auth.module.ts
:
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';
import { GoogleStrategy } from './strategies/google.strategy';
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'google' }),
JwtModule.register({
secret: 'yourSecretKey',
signOptions: { expiresIn: '60m' },
}),
],
providers: [AuthService, GoogleStrategy],
exports: [AuthService],
})
export class AuthModule {}
Running the Application
Make sure your app is running on the same port and domain specified in your Google credentials. Start the application using:
npm run start
Finally, navigate to http://localhost:3000/auth/google
and test the login flow.
Conclusion
Integrating Google authentication using Passport in a NestJS application isn't just about securing your application—it's about creating a streamlined, user-friendly authentication process. This integration offers an easy way to improve both the security and accessibility of apps. Remember, the steps can be adapted for other Passport strategies to allow for varied authentication methods.
For further reading, consider exploring the official Passport documentation and the NestJS documentation, which provide detailed guides on advanced configurations and additional strategies.