├── .gitignore ├── README.md ├── package.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Invisible Recaptcha Server-Side Validator 2 | Simple Express Server for invisible reCaptcha server-side validation. Works nicely for static websites, in my case — a Jekyll website hosted on GitHub Pages. 3 | 4 | 5 | ## Instructions 6 | 1. Register your site/ get your reCaptcha keys [here](https://www.google.com/recaptcha) 7 | 2. Create a new [Heroku App](https://dashboard.heroku.com/apps) 8 | 3. In your new Heroku App, go to settings and create a new Config Var called RECAPTCHA_SECRET and enter your secret key in the value field 9 | 4. Clone this repo 10 | 5. Deploy your app via the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) or hook up your GitHub repository via the Deploy tab in your Heroku App 11 | 6. After you deploy your app, your app url should display 'reCaptcha verification' 12 | 13 | 14 | ## Client-Side Instructions 15 | 1. Paste this snippet in the `head` of your html template: `` 16 | 2. Choose your [method for integration](https://developers.google.com/recaptcha/docs/invisible#explicit_render). I ultimately went with the 'Programmatically invoke the challenge' method to have control over when the reCaptcha validation happens (I needed it to happen after the form field validation). 17 | 3. Whichever method you choose, set your `callback-funtion` to `onSubmit`. 18 | 4. Here is what your onSubmit funtion should look like: 19 | 20 |
function onSubmit(token) {
21 |   submitForm();
22 | }
23 | 
24 | 25 | 5. Now we need to grab our token and send it to our Heroku app. Our app will read the token, send it to Google along with our secret key, get a response and send it back to us with a pass or fail. 26 |
function submitForm(){
27 |   console.log('Initialize Server-Side Validation');
28 |   
29 |   // Note that we grab the value of '#g-recaptcha-response' and not just '#g-recaptcha'
30 |   var captcha = document.querySelector('#g-recaptcha-response').value;
31 | 
32 |   fetch('YOUR HEROKU APP URL HERE', {
33 |     method:'POST',
34 |     headers: {
35 |       'Accept': 'application/json, text/plain, */*',
36 |       'Content-type':'application/json'
37 |     },
38 |     body:JSON.stringify({captcha: captcha})
39 |   })
40 |   .then((res) => res.json())
41 |   .then((data) => {
42 |     console.log(data.success);
43 |     if( data.success === true ){
44 |       document.getElementById("my-form").submit();
45 |     }
46 |   });
47 | }
48 | 
49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "recaptcha", 3 | "version": "1.0.0", 4 | "description": "Recaptcha server", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "body-parser": "^1.18.2", 13 | "express": "^4.16.2", 14 | "request": "^2.83.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const request = require('request'); 4 | const app = express(); 5 | 6 | 7 | app.use(bodyParser.urlencoded({extended: false})); 8 | app.use(bodyParser.json()); 9 | var port = process.env.PORT || 4000; 10 | 11 | app.use(function(req, res, next) { 12 | // Important 13 | res.header("Access-Control-Allow-Origin", "*"); 14 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 15 | next(); 16 | }); 17 | 18 | app.get('/', (req, res, next) => { 19 | res.send('reCaptcha verification'); 20 | }); 21 | 22 | app.post('/', (req, res) => { 23 | if( 24 | req.body.captcha === undefined || 25 | req.body.captcha === '' || 26 | req.body.captcha === null 27 | ){ 28 | return res.json({"success": false, "msg":"Please select captcha"}); 29 | } 30 | 31 | // Secret Key from Heroku Config Variable 'RECAPTCHA_SECRET' 32 | const secretKey = process.env.RECAPTCHA_SECRET; 33 | 34 | console.log(secretKey); 35 | 36 | // Google's verification URL: https://developers.google.com/recaptcha/docs/verify 37 | const verifyUrl = `https://google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${req.body.captcha}&remoteip=${req.connection.remoteAddress}`; 38 | 39 | // Make Request To VerifyURL 40 | request(verifyUrl, (err, response, body) => { 41 | body = JSON.parse(body); 42 | 43 | // If Not Successful 44 | if(body.success !== undefined && !body.success){ 45 | return res.json({"success": false, "msg":"Failed captcha verification from live server"}); 46 | } 47 | 48 | //If Successful 49 | return res.json({"success": true, "msg":"Captcha passed from live server"}); 50 | }); 51 | }); 52 | 53 | 54 | app.listen(port, function () { 55 | console.log('App listening on port ' + port); 56 | }); 57 | --------------------------------------------------------------------------------