├── .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 |
--------------------------------------------------------------------------------