Bots are bad and annoying, I hate them. I know you do too, that’s why you are here. This Google Recaptcha V3 in GoLang Tutorial will explain and walk you through how you can integrate the Google Recaptcha(V3) in websites build in Golang and get rid of Bots and spammers.
The request will be validated by Google using Captcha Response and then Google will return the authenticity score of Request. Based on the score you can decide if you want to grant access to the request. In this tutorial, we will implement the front end and backend both. If you know the entire drill and you here just for the code click the below Download button and download the code.
1. Obtaining the Google Captcha Site Key and Secret Key
First, you will need Site key and Secret Key from google Captcha dashboard. Using Site key and Secret Key you can integrate the Google Captcha in your Website. To obtain the Site key and Secret Key you have to create a Site and fill the below form,
After filling the entire form as shown in the above image, click on the submit button. After submitting the form you will get your Site Key and Secret Key as shown in the below screen,
Also read,Facebook Login in GoLang Tutorial
2. Understanding the project structure
Here we will give a very little bit of styling to our web application just to make it look presentable. And we won’t be using any frontend libraries or frameworks, for the sake of simplicity.
Since we are using plain Javascript and there is not much on the client-side to understand, hence we will focus on the Backend part only. Inside theviews
folder, we will write down the MARKUP.
Apart from the public folder we have only go files, let’s understand the purpose of each file why we need them.
db.go
:The file will have code to connect the Redis database.
routes-handlers.go
:This file will have the actual logic of the application. Here we will write code to store the Hash Key with the actual URL and the Redirection Logic will be handled here only.
routes.go
:As the name suggests, this file will contain the endpoints that we will define in this application.
structs.go
:In this file, we will write all the structs that will be used in this application.
server.go
:To create the Golang server we will use server.go file.
3. Creating a GoLang Server
Create aserver.goin the root of the project, which will be our entry point for the project. Here we will make a connection with the MongoDB database and we will define our application routes.
=>Inside themain()
function, First we are printing some information.
=>In the next line, we will createroute
variable, which will hold Route instance.
=>ThenAddApproutes()
function register application routes.
=>And at the end, usinghttp.ListenAndServe()
we will start our GO server.
server.go:
package main import ( "log" "net/http" "github.com/gorilla/mux" "github.com/joho/godotenv" ) func main() { godotenv.Load() log.Println("Server will start at http://localhost:8000/") route := mux.NewRouter() AddApproutes(route) log.Fatal(http.ListenAndServe(":8000", route)) }
4. Adding GoLang Structs
Create astructs.goin the root of the project, Here we will register all structs used in this application. The reason for creating a separate file is that your code will look more clear and it will become very easy to read.
structs.go:
package main // ErrorResponse is struct for sending error message with code. type ErrorResponse struct { Code int Message string } // SuccessResponse is struct for sending error message with code. type SuccessResponse struct { Code int Message string Response interface{} } // StoreMessageRequest is struct for requests of /storeMessage API type StoreMessageRequest struct { Message string `json:"message"` Token string `json:"token"` } // CaptchaPayloadRequest is struct for payload of verify captcha API type CaptchaPayloadRequest struct { secret string response string }
5. Adding GoLang routes in the application
Create aroutes.goin the root of the project, Here we will register application routes. Here we will usegorilla/mux
package to register routes.
=>ThenAddApproutes()
function will register all the routes in the application. Here we have only one route to add which will be used by the FrontEnd javascript.
=>/RenderHome
API will render the Form to fill and after submission, we will call the /storeMessage
API.
=>/storeMessage
API will call the Google API to verify the Captcha.
routes.go:
package main import ( "log" "github.com/gorilla/mux" ) // AddApproutes will add the routes for the application func AddApproutes(route *mux.Router) { log.Println("Loadeding Routes...") route.HandleFunc("/", RenderHome) route.HandleFunc("/storeMessage", StoreMessage).Methods("POST") log.Println("Routes are Loaded.") }
6. Rendering and Displaying the frontend
Now as you know the /RenderHome
API will render the template. This template will display a very simple form to fill the text message and there will be a submit button. In this section, we will see how that is implemented,
Now create a routes-handlers.go and write down the below code,
routes-handlers.go:
package main import ( "net/http" ) // RenderHome Rendering the Home Page func RenderHome(response http.ResponseWriter, request *http.Request) { http.ServeFile(response, request, "views/index.html") }
Explanation:
- The
RenderHome()
function will render theindex.html
file which is stored inside the/views
folder. - In this function, we make use of the
http.ServeFile
method of HTTP package to render the HTML file.
Now let’s write the template file, which will display a very simple HTML form. In this form, we will have One Textbox and a Submit button and upon click that button we will call an API to verify the Captcha Request.
=> After running the below markup you will notice, on the right end corner a Google reCAPTCHA icon.
=> Now create a index.html file inside the views
folder and write down the below code,
index.html:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style> body { font-family: 'Helvetica', sans-serif; color: #fff; margin: 0px; padding: 0px; background-color: #ffe1c1; width: 100%; height: 100vh; display: flex; flex-direction: column; justify-content: center; } .app__container { width: 420px; display: flex; flex-direction: column; margin: auto; } textarea { margin-bottom: 10px; height: 100px; font-size: 20px; } button { margin: auto; background: #4267b2; text-align: center; padding: 7px 15px; font-size: 20xpx; text-decoration: none; color: #fff; font-weight: 400; border: 0px; width: 100%; outline: none; cursor: pointer; } </style> </head> <body> <div class="app__container"> <textarea id="user-message" placeholder="Write some message"></textarea> <button id="submit-button">Submit</button> </div> <script src="https://www.google.com/recaptcha/api.js?render=----SITE_KEY-----"></script> <script> const submitButton = document.querySelector('#submit-button'); function getCaptchaToken(callback) { grecaptcha.ready( () => { grecaptcha.execute('---SITE_KEY----', {action: 'submit_message'}).then( (token) => { callback(token) });; }); } submitButton.onclick = (event) => { const userMessage = document.querySelector('#user-message').value; if(userMessage === '' || userMessage === null) { alert("Message Can't be empty"); return; } getCaptchaToken( (token) => { fetch('/storeMessage', { method: 'POST', headers: { 'Content-Type': undefined }, body: JSON.stringify({ message: userMessage, token }) }) .then((resp) => resp.json()) .then((result) => { if(result.Code === 200) { alert('Your message is submitted') } else { alert('Bots are not allowed') } }) .catch((error) => { alert(error.Message) }); }); } </script> </body> </html>
Explanation:
- In the above HTML file, first, we have very little CSS just to decorate the page so let’s skip that.
- Then we have few markups for displaying the Textbox and Button.
- Next, we have included script from google as shown below,
<script src="https://www.google.com/recaptcha/api.js?render=----SITE_KEY-----"></script>
- Then we have written few lines of javascript, which handles the form submission n all.
- First, we have created a contant
submitButton
, which contains the instance of Submit Button. - Then we have created
getCaptchaToken()
which given the Google Captcha token. - The
getCaptchaToken()
function calls thegrecaptcha.ready
. Thegrecaptcha.ready
initialize the Google Captcha Library. - Then
grecaptcha.execute
will be called, this function returns the Authentication token, and this token will be sent to the server as a captcha response. - On Click on the submit button, we will call
getCaptchaToken()
, which gives the token and then using fetch API we call/storeMessage
. - The
/storeMessage
will expect two parameters in the Request Payloadmessage
andtoken
.
7. Verifying the captcha token
As you know /storeMessage
API will call StoreMessage()
function which should be created in route-handler.go file. The StoreMessage()
function will call the google server to get a score of the authenticity of the Request.
=> Open theroute-handler.go and write down the below code,
route-handler.go:
package main import ( "encoding/json" "net/http" "net/url" "os" "strings" ) // RenderHome Rendering the Home Page func RenderHome(response http.ResponseWriter, request *http.Request) { http.ServeFile(response, request, "views/index.html") } // StoreMessage function will verify the Captcha func StoreMessage(response http.ResponseWriter, request *http.Request) { var storeMessageRequest StoreMessageRequest var captchaVerifyResponse interface{} var errorResponse = ErrorResponse{ Code: http.StatusInternalServerError, Message: "It's not you it's me.", } decoder := json.NewDecoder(request.Body) decoderErr := decoder.Decode(&storeMessageRequest) defer request.Body.Close() if decoderErr != nil { returnErrorResponse(response, request, errorResponse) } else { if storeMessageRequest.Message == "" { errorResponse.Code = http.StatusBadRequest errorResponse.Message = "Message can't be empty" returnErrorResponse(response, request, errorResponse) } else { captchaPayloadRequest := url.Values{} captchaPayloadRequest.Set("secret", os.Getenv("CAPTCHA_SECRET_KEY")) captchaPayloadRequest.Set("response", storeMessageRequest.Token) verifyCaptchaRequest, _ := http.NewRequest("POST", os.Getenv("VERIFY_CAPTCHA_GOOGLE_API"), strings.NewReader(captchaPayloadRequest.Encode())) verifyCaptchaRequest.Header.Add("content-type", "application/x-www-form-urlencoded") verifyCaptchaRequest.Header.Add("cache-control", "no-cache") verifyCaptchaResponse, _ := http.DefaultClient.Do(verifyCaptchaRequest) decoder := json.NewDecoder(verifyCaptchaResponse.Body) decoderErr := decoder.Decode(&captchaVerifyResponse) defer verifyCaptchaResponse.Body.Close() if decoderErr != nil { returnErrorResponse(response, request, errorResponse) return } var successResponse = SuccessResponse{ Code: http.StatusOK, Message: "Your request is verified", Response: captchaVerifyResponse, } successJSONResponse, jsonError := json.Marshal(successResponse) if jsonError != nil { returnErrorResponse(response, request, errorResponse) return } response.Header().Set("Content-Type", "application/json") response.WriteHeader(successResponse.Code) response.Write(successJSONResponse) } } } func returnErrorResponse(response http.ResponseWriter, request *http.Request, errorMesage ErrorResponse) { httpResponse := &ErrorResponse{Code: errorMesage.Code, Message: errorMesage.Message} jsonResponse, err := json.Marshal(httpResponse) if err != nil { panic(err) } response.Header().Set("Content-Type", "application/json") response.WriteHeader(errorMesage.Code) response.Write(jsonResponse) }
Explanation:
- First, we decode the request Payload and store the data of request into
storeMessageRequest
variable. - Then the next step is to call google server, which in return, gives the authenticity score of Request.
- The
captchaPayloadRequest
contains the payload that we will send to google server. - Using
http.NewRequest
we make the POST request to the Google Server and we store the response incaptchaVerifyResponse
variable. - After that, we return the response to API by sending the
captchaVerifyResponse
variable in the response body.
8. Running the application
To run the application, you need to build the application and then run the executable file as shown below,
> go build > Google_reCaptcha_V3_in_GoLang_Tutorial.exe
Now you can test this application by opening thelocalhost:8000
.
9. Conclusion
This Google Recaptcha V3 in GoLang Tutorial explained us how we can integrate Google Recaptcha(V3) in websites build in Golang. For now, that’s it, Meanwhile, you can play with code and if something doesn’t work let me know in comments. Feel free to share your opinions in the below comments box and if you like this article do share with your friends and colleagues.