Skip to content

Instantly share code, notes, and snippets.

@Clivern
Created February 21, 2026 20:57
Show Gist options
  • Select an option

  • Save Clivern/b63e2c25e6dcb598541abae2b4ef2180 to your computer and use it in GitHub Desktop.

Select an option

Save Clivern/b63e2c25e6dcb598541abae2b4ef2180 to your computer and use it in GitHub Desktop.
Google Recaptcha
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
// reCAPTCHA v2 "I'm not a robot" keys from https://www.google.com/recaptcha/admin
siteKey := "~~~~~~~~~~~"
secretKey := "~~~~~~~~~~~"
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprintf(w, pageHTML, siteKey)
})
http.HandleFunc("/verify", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
token := r.Header.Get("X-Recaptcha-Token")
ok, err := VerifyRecaptchaV2(secretKey, token, r.RemoteAddr)
if !ok {
writeJSON(w, map[string]any{"success": false, "error": err})
return
}
writeJSON(w, map[string]any{"success": ok})
})
addr := ":8080"
if p := os.Getenv("PORT"); p != "" {
addr = ":" + p
}
fmt.Println("Listening on http://localhost" + addr)
if err := http.ListenAndServe(addr, nil); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func writeJSON(w http.ResponseWriter, v any) {
enc := json.NewEncoder(w)
_ = enc.Encode(v)
}
const pageHTML = `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>reCAPTCHA v2 demo</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 32rem; margin: 2rem auto; padding: 0 1rem; }
</style>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body>
<h1>reCAPTCHA v2 demo</h1>
<p>Check "I'm not a robot", complete the challenge if shown, then click Submit.</p>
<form id="form">
<div class="g-recaptcha" data-sitekey="%s"></div>
<br>
<button type="submit" id="submit-btn">Submit</button>
</form>
<div id="result"></div>
<script>
document.getElementById('form').onsubmit = function(e) {
e.preventDefault();
var btn = document.getElementById('submit-btn');
btn.disabled = true;
document.getElementById('result').textContent = 'Verifying...';
var token = document.querySelector('[name="g-recaptcha-response"]').value;
if (!token) { document.getElementById('result').textContent = 'Error: complete the reCAPTCHA first'; btn.disabled = false; return; }
fetch('/verify', {
method: 'POST',
headers: { 'X-Recaptcha-Token': token },
body: new FormData(e.target)
})
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.success) {
document.getElementById('result').textContent = 'Verification passed!';
} else {
document.getElementById('result').textContent = 'Error: ' + (data.error || 'verification failed');
}
})
.catch(function(err) {
document.getElementById('result').textContent = 'Error: ' + err.message;
})
.finally(function() { btn.disabled = false; });
};
</script>
</body>
</html>
`
package main
import (
"encoding/json"
"io"
"net/http"
"net/url"
)
const (
verifyURL = "https://www.google.com/recaptcha/api/siteverify"
)
type VerifyResponse struct {
Success bool `json:"success"`
ChallengeTS string `json:"challenge_ts,omitempty"`
Hostname string `json:"hostname,omitempty"`
ErrorCodes []string `json:"error-codes,omitempty"`
}
func VerifyRecaptchaV2(secret, response, remoteIP string) (ok bool, errMsg string) {
resp, err := http.PostForm(verifyURL, url.Values{
"secret": {secret},
"response": {response},
"remoteip": {remoteIP},
})
if err != nil {
return false, err.Error()
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return false, err.Error()
}
var v VerifyResponse
if err := json.Unmarshal(body, &v); err != nil {
return false, err.Error()
}
if !v.Success {
if len(v.ErrorCodes) > 0 {
return false, v.ErrorCodes[0]
}
return false, "verification failed"
}
return true, ""
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment