'Nestjs and Google Recaptcha
I am trying to implement a server-side validation for reCaptcha using Nestjs and I want to if I should implement this as a module or as a service for modules(such as a self written user authentication module) that would require the use of reCaptcha.
Solution 1:[1]
I solved it by creating a seperate RecaptchaGuard.
// recaptcha.guard.ts
import {
Injectable,
CanActivate,
ExecutionContext,
HttpService,
ForbiddenException,
} from "@nestjs/common";
@Injectable()
export class RecaptchaGuard implements CanActivate {
constructor(private readonly httpService: HttpService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const { body } = context.switchToHttp().getRequest();
const { data } = await this.httpService
.post(
`https://www.google.com/recaptcha/api/siteverify?response=${body.recaptchaValue}&secret=${process.env.RECAPTCHA_SECRET}`
)
.toPromise();
if (!data.success) {
throw new ForbiddenException();
}
return true;
}
}
Next you can simply apply the recaptcha guard on a controller.
// app.controller.ts
import { Controller, Post, UseGuard } from '@nestjs/common';
import { RecaptchaGuard } from './recaptcha.guard.ts'
@Controller()
export class AppController {
@Post()
@UseGuard(RecaptchaGuard)
async postForm(){
//
}
}
Solution 2:[2]
Import HttpModule
import { Module } from '@nestjs/common';
import { HttpModule } from "@nestjs/axios";
@Module({
imports: [HttpModule],
...
})
Then create a service to validate captcha value
NOTE: You have to get the secret/site key from here (site key will get used in the client)
import { HttpService, Inject, Injectable } from "@nestjs/common";
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
import { map } from 'rxjs/operators'
@Injectable()
export class CaptchaService {
constructor(
@Inject(REQUEST) private readonly request: Request,
private httpService: HttpService) { }
public validate(value:string): Promise<any> {
const remoteAddress = this.request.socket.remoteAddress
const secretKey = "XXXXXXXXX"
const url = "https://www.google.com/recaptcha/api/siteverify?secret=" + secretKey + "&response=" + value + "&remoteip=" + remoteAddress;
return this.httpService.post(url).pipe(map(response => {
return response['data']
})).toPromise()
}
}
then in your controller :
const value="XXXXX" // client send this for you
const result = await this.captchService.validate(value)
if (!result.success) throw new BadRequestException()
Client Side
If you are using angular you can use this
Solution 3:[3]
Initially, I was following the accepted answer, and then noticed that there's an easier way to do so - and wanna share it just in case it can help anyone.
There's a NestJS module that provides easy integration with ReCAPTCHA: https://github.com/chvarkov/google-recaptcha.
- Install the module.
- In your
AppModule
create something like this:
const googleRecaptchaFactory = (
applicationConfigService: ApplicationConfigService,
) => ({
secretKey: applicationConfigService.auth.recaptcha.secretKey,
response: (req) => req.headers.recaptcha || '',
skipIf: applicationConfigService.auth.recaptcha.bypassVerification,
});
@Module({
controllers: [/* ... */],
imports: [
/* ... */
GoogleRecaptchaModule.forRootAsync({
imports: [],
inject: [ApplicationConfigService],
useFactory: googleRecaptchaFactory,
}),
],
providers: [/* ... */],
exports: [/* ... */],
})
export class Module {}
- Now, in your controller, use the
@Recapcha
guard.
You can find documentation for the entire integration process in the linked Github.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | OzB |