├── main
└── default
│ ├── lwc
│ └── myLWC
│ │ ├── myLWC.html
│ │ └── myLWC.js
│ ├── staticresources
│ ├── reCAPTCHAv3.resource-meta.xml
│ └── reCAPTCHAv3.html
│ └── classes
│ └── reCAPTCHAv3ServerController.cls
└── README.md
/main/default/lwc/myLWC/myLWC.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/main/default/staticresources/reCAPTCHAv3.resource-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Public
4 | text/html
5 |
--------------------------------------------------------------------------------
/main/default/classes/reCAPTCHAv3ServerController.cls:
--------------------------------------------------------------------------------
1 | public with sharing class reCAPTCHAv3ServerController {
2 | public reCAPTCHAv3ServerController(){
3 |
4 | }
5 |
6 |
7 | @AuraEnabled
8 | public static Boolean isReCAPTCHAValid(String tokenFromClient) {
9 | String SECRET_KEY = 'reCAPTCHA_secret_key';
10 | String RECAPTCHA_SERVICE_URL = 'https://www.google.com/recaptcha/api/siteverify';
11 | Http http = new Http();
12 |
13 | HttpRequest request = new HttpRequest();
14 |
15 | request.setEndpoint(RECAPTCHA_SERVICE_URL + '?secret=' + SECRET_KEY + '&response' + tokenFromClient);
16 | request.setMethod('POST');
17 | request.setHeader('Content-Length', '0');
18 | HttpResponse response = http.send(request);
19 |
20 | Map mapOfBody = (Map) JSON.deserializeUntyped(response.getBody());
21 |
22 | Boolean success = (Boolean) mapOfBody.get('success');
23 |
24 | return success;
25 | }
26 | }
--------------------------------------------------------------------------------
/main/default/staticresources/reCAPTCHAv3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | reCAPTCHA html resource
4 |
5 |
6 |
7 |
8 |
21 |
22 |
--------------------------------------------------------------------------------
/main/default/lwc/myLWC/myLWC.js:
--------------------------------------------------------------------------------
1 | import { LightningElement, track, api } from 'lwc';
2 | import pageUrl from '@salesforce/resourceUrl/reCAPTCHAv3';
3 | import isReCAPTCHAValid from '@salesforce/apex/reCAPTCHAv3ServerController.isReCAPTCHAValid';
4 |
5 | export default class GoogleCapatcha extends LightningElement {
6 | @api formToken;
7 | @api validReCAPTCHA = false;
8 |
9 | @track navigateTo;
10 | captchaWindow = null;
11 |
12 | constructor(){
13 | super();
14 | this.navigateTo = pageUrl;
15 | }
16 |
17 | captchaLoaded(evt){
18 | var e = evt;
19 | console.log(e.target.getAttribute('src') + ' loaded');
20 | if(e.target.getAttribute('src') == pageUrl){
21 |
22 | window.addEventListener("message", function(e) {
23 | if (e.data.action == "getCAPCAH" && e.data.callCAPTCHAResponse == "NOK"){
24 | console.log("Token not obtained!")
25 | } else if (e.data.action == "getCAPCAH" ) {
26 | this.formToken = e.data.callCAPTCHAResponse;
27 | isReCAPTCHAValid({tokenFromClient: formToken}).then(data => {
28 | this.validReCAPTCHA = data;
29 | });
30 | }
31 | }, false);
32 | }
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # How to use Google reCAPTCHA v3 in Lightning Web Component
2 |
3 | ## Limitation of Salesforce platform
4 | Salesforce platform puts restriction on loading JS source into Lightning Web Component directly, i.e. the magic reCAPTCHA script cannot be directly used in the component.
5 |
6 |
7 | > "You can’t load JavaScript resources from a third-party site, even a CSP Trusted Site. To use a JavaScript library from a third-party site, add it to a static resource, and then add the static resource to your component. After the library is loaded from the static resource, you can use it as normal." - [Call APIs from JavaScript](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.js_api_calls)
8 |
9 | There are 4 steps to integrate reCAPTCHA v3 to a Lightning Web Component
10 | ### 1. Create html static resource with reCAPTCHA
11 | reCAPTCHAv3.html
12 | ```html
13 |
14 |
15 | reCAPTCHA html resource
16 |
17 |
18 |
19 |
20 |
33 |
34 |
35 | ```
36 | reCAPTCHAv3.resource-meta.xml
37 | ```xml
38 |
39 |
40 | Public
41 | text/html
42 |
43 | ```
44 |
45 | ### 2. Create Lightning Web Component with an iframe to load the static resource
46 | myLWC.html
47 | ```html
48 |
49 |
50 |
51 | ```
52 |
53 | ### 3. Create the Javascript controller for the Lightning Web Component
54 | myLWC.js
55 | ```javascript
56 | import { LightningElement, track, api } from 'lwc';
57 | import pageUrl from '@salesforce/resourceUrl/reCAPTCHAv3';
58 | import isReCAPTCHAValid from '@salesforce/apex/reCAPTCHAv3ServerController.isReCAPTCHAValid';
59 |
60 | export default class GoogleCapatcha extends LightningElement {
61 | @api formToken;
62 | @api validReCAPTCHA = false;
63 |
64 | @track navigateTo;
65 | captchaWindow = null;
66 |
67 | constructor(){
68 | super();
69 | this.navigateTo = pageUrl;
70 | }
71 |
72 | captchaLoaded(evt){
73 | var e = evt;
74 | console.log(e.target.getAttribute('src') + ' loaded');
75 | if(e.target.getAttribute('src') == pageUrl){
76 |
77 | window.addEventListener("message", function(e) {
78 | if (e.data.action == "getCAPCAH" && e.data.callCAPTCHAResponse == "NOK"){
79 | console.log("Token not obtained!")
80 | } else if (e.data.action == "getCAPCAH" ) {
81 | this.formToken = e.data.callCAPTCHAResponse;
82 | isReCAPTCHAValid({tokenFromClient: formToken}).then(data => {
83 | this.validReCAPTCHA = data;
84 | });
85 | }
86 | }, false);
87 | }
88 | }
89 |
90 | }
91 | ```
92 |
93 |
94 | ### 4. Create Apex class to handle the server-side verification
95 | reCAPTCHAv3ServerController.cls
96 | ```java
97 | public with sharing class reCAPTCHAv3ServerController {
98 | public reCAPTCHAv3ServerController(){
99 |
100 | }
101 |
102 |
103 | @AuraEnabled
104 | public static Boolean isReCAPTCHAValid(String tokenFromClient) {
105 | String SECRET_KEY = 'reCAPTCHA_secret_key';
106 | String RECAPTCHA_SERVICE_URL = 'https://www.google.com/recaptcha/api/siteverify';
107 | Http http = new Http();
108 |
109 | HttpRequest request = new HttpRequest();
110 |
111 | request.setEndpoint(RECAPTCHA_SERVICE_URL + '?secret=' + SECRET_KEY + '&response' + tokenFromClient);
112 | request.setMethod('POST');
113 | request.setHeader('Content-Length', '0');
114 | HttpResponse response = http.send(request);
115 |
116 | Map mapOfBody = (Map) JSON.deserializeUntyped(response.getBody());
117 |
118 | Boolean success = (Boolean) mapOfBody.get('success');
119 |
120 | return success;
121 | }
122 | }
123 | ```
124 |
--------------------------------------------------------------------------------