34

Surprisingly-even more when both are Google products-there is no information that I can find on how to integrate Recaptcha with Firebase. Is it even possible? If not, what can I use to validate humans on a Firebase app that has no auth?

Sergi Mansilla
  • 12,495
  • 10
  • 39
  • 48
  • I'm currently looking into this too. Will come back with an answer or update when I have something. – Kieran Hall Apr 14 '17 at 15:01
  • I haven't started on my solution yet, however, I'm looking to use Cloud Functions for Firebase to https://firebase.google.com/docs/functions/ to integrate with Recaptcha. There are similar use cases here: https://github.com/firebase/functions-samples – Kieran Hall Apr 15 '17 at 14:38
  • I don't know if I am too late. Now there is Firebase's Cloud Function. You can write your own backend API in javascript on it. Instead of calling firebase database right out of the client, you call your custom API via Firebase's Cloud Function on the client and authenticate the reCaptcha there and do something with your database as an admin (firebase-admin). I tried it and it works fine. – pupuupup Apr 26 '17 at 04:45
  • 1
    This is the flow on what I did.. 1) authenticate that client is not robot using reCaptcha 2) send the token with post data to custom cloud function API 3) the reCaptcha token will be authenticated in the cloud function 4) update the data in firebase database as an admin. (the security rule can be .write: false, the cloud function will be able to write on it as a "firebase-admin", only client that passes through reCaptcha authentication will be able to write on it) – pupuupup Apr 26 '17 at 04:49

2 Answers2

26

This is a pretty old post, but here's the answer for fellow Google searchers like me. It's now built-in, and super easy to set up:

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha', {
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
})
window.recaptchaVerifier.render()

As tuananh mentions, make sure you add a <div id="recaptcha"></div>.

vstollen
  • 151
  • 1
  • 11
Alan Grainger
  • 551
  • 5
  • 8
  • 1
    To void exception "Error: reCAPTCHA container is either not found or already contains inner elements". Please add element with id="recaptcha", ex:
    – tuananh Jan 22 '18 at 04:20
  • 3
    I just want to note that this method uses "firebase.auth" which is not valid for server-side authentication or node.js implementation. It's only "built-in" for client-side javascript projects. The method above by Doug Stevenson is necessary for anyone doing server-side rendering. For example, if you want firebase functions to verify a captcha before sending the user's input over to another function to create a new user account using the admin SDK. – Matthew Rideout Jan 27 '18 at 00:21
  • 1
    I can't find how to make this work with signInWithEmailAndPassword, it doenst have a third parameter waiting for the appVerifier, as the signInWithPhoneNumber does – leoxs Nov 20 '19 at 17:39
11

I've just published a tutorial blog on how to integrate reCAPTCHA in a web site using Firebase Hosting to serve content and Cloud Functions for Firebase to validate the response received from the reCAPTCHA. The function itself looks like this, assuming that the response token is received through the query string:

const functions = require('firebase-functions')
const rp = require('request-promise')

exports.checkRecaptcha = functions.https.onRequest((req, res) => {
    const response = req.query.response
    console.log("recaptcha response", response)
    rp({
        uri: 'https://recaptcha.google.com/recaptcha/api/siteverify',
        method: 'POST',
        formData: {
            secret: 'PASTE_YOUR_SECRET_CODE_HERE',
            response: response
        },
        json: true
    }).then(result => {
        console.log("recaptcha result", result)
        if (result.success) {
            res.send("You're good to go, human.")
        }
        else {
            res.send("Recaptcha verification failed. Are you a robot?")
        }
    }).catch(reason => {
        console.log("Recaptcha request failure", reason)
        res.send("Recaptcha request failed.")
    })
})
Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • 1
    Are there any alternatives to using request promise. `const rp = require('request-promise')`? – Gal Bracha Oct 26 '17 at 18:04
  • How about if I want to use this before I allow users to OAuth with Facebook Or Google? – Gal Bracha Oct 26 '17 at 18:05
  • 2
    You can use whatever HTTP client library you like, as long as you follow the spec for the reCAPTCHA API. You can do it whenever you want as well. – Doug Stevenson Oct 26 '17 at 20:49
  • how would I format tan http request instead of window.location? what would that request be like? – SeanMC Aug 01 '18 at 01:35
  • It is important to know that even though in [Google docs](https://developers.google.com/recaptcha/docs/verify) it's said that the verification endpoint is https://www.google.com/recaptcha/api/siteverify, in the Firebase Cloud Function you should use https://recaptcha.google.com/recaptcha/api/siteverify (note that the domain is **recaptcha.google.com**) like Doug does, in order to get it working with a free plan. – José Antonio Postigo Sep 03 '19 at 07:52
  • 1
    How's this supposed to work in a web app though? Coz if I put this function call before registration, say, people can just bypass it and go straight to registration, making the recaptcha call pointless. You'd have to send the email and password from the client to this function, and do the registration server-side once recaptcha has successfully passed for this to have any credibility. – SeriousLee Apr 11 '20 at 06:29
  • Solid answer and article, I implemented to see how it works. However in my specific use case, **what we will really need is a signinwithemailandpassword & createuserwithemail with capchta built in to firebase** Otherwise in theory even if you have the registration occur within the cloud function, someone could just inject javascript using the google docs with the firebase config already present somewhere in the clientside files. That being said this function is still useful for a number of situations so appreciate it, basically couldn't be any better than it is. – WTJJ Sep 06 '20 at 23:07