CAPTCHA

A portal's account pages accept submissions from anybody: a script can create accounts, or make the portal mail password-reset and confirmation links to addresses it chooses. A CAPTCHA asks each visitor to show they are a person before the form is sent. Power Portals Pro supports Cloudflare Turnstile, Google reCAPTCHA (v2 and v3) and hCaptcha, and is off until you configure one.

Note

The server checks the challenge, not just the page. Once a provider is configured, the auth endpoints and the server-rendered account pages refuse a submission of a protected form without a solved challenge, whatever the browser sends.

Which forms are protected

CaptchaOptions.Forms chooses the forms, as a combination of CaptchaForms values. The default protects the forms an automated caller can abuse without knowing any password.

CaptchaForms Form By default
Register Creating a local account. On
ForgotPassword Asking for a password-reset link. On
ResendEmailConfirmation Asking for another email-confirmation link. On
Login Signing in with an email address and password. Turn it on to slow down password guessing; repeated wrong passwords also lock the account for a while. Off
ExternalLogin Completing a sign-in through Microsoft, Google or another provider with an email address the provider didn't verify, which the portal then mails a confirmation to. A sign-in whose address the provider verified completes without a challenge. Off

Choosing a provider

The three providers work the same way as far as the portal is concerned; they differ in what the visitor sees and in whose account you need. Each has a free tier.

Provider Account you need What the visitor sees Links
Cloudflare Turnstile A free Cloudflare account. Your portal does not have to be hosted on Cloudflare or use its DNS. Usually nothing to do: the check runs by itself and only occasionally asks for a click. Dashboard · Documentation
Google reCAPTCHA v2 A Google account. The “I'm not a robot” checkbox, sometimes followed by an image puzzle. Admin console · Documentation
hCaptcha A free hCaptcha account. A checkbox, sometimes followed by an image puzzle. Dashboard · Documentation
Google reCAPTCHA v3 A Google account. Nothing at all: Google scores each submission, and Google's badge sits in the page's corner. A visitor scored too low is refused and can't prove otherwise. Admin console · Documentation

Whichever you choose, the provider gives you two keys for your site: a site key, which is public and is sent to every browser to draw the widget, and a secret key, which only the server uses to check a visitor's answer. Keep the secret key out of source control.

Setting up Cloudflare Turnstile

  1. Sign up for a free account at dash.cloudflare.com. You don't need to add a website or move any DNS.
  2. Open Turnstile from the dashboard's menu and choose Add widget.
  3. Name the widget and add every hostname the portal is served from — its production domain, any deployment slot's, and localhost if you test with real keys.
  4. Choose the Managed widget mode, which only asks for a click when Cloudflare isn't sure.
  5. Create the widget and copy its Site Key and Secret Key.

Setting up Google reCAPTCHA v2

  1. Sign in to the reCAPTCHA admin console with a Google account and create a new site.
  2. Choose Challenge (v2) and then “I'm not a robot” Checkbox.
  3. Add every domain the portal is served from, and localhost if you test with real keys.
  4. Leave Verify the origin of reCAPTCHA solutions on, so a token solved on another site is refused. Submit, and copy the site key and the secret key.

Important

Use provider ReCaptchaV2 and the Captcha:ReCaptchaV2 section only for a v2 “I'm not a robot” checkbox key — the widget shows “Invalid key type” for any other. A v3 key goes under ReCaptchaV3, below; the invisible v2 badge isn't supported. Google may ask you to attach the key to a Google Cloud project; that doesn't change how the portal uses it.

Setting up Google reCAPTCHA v3

v3 shows no challenge. The page asks Google for a token when the form is submitted, tagged with the form it came from, and the server refuses a token scored below MinimumScore or tagged for another form. Use provider ReCaptchaV3 and its own section, Captcha:ReCaptchaV3: a v3 key is a different key from a v2 one.

  1. In the reCAPTCHA admin console, create a new site and choose Score based (v3).
  2. Add every domain the portal is served from, and localhost if you test with real keys. Leave Verify the origin of reCAPTCHA solutions on.
  3. Submit, and copy the site key and the secret key into Captcha:ReCaptchaV3.
  4. Set MinimumScore, from 0.0 to 1.0. It defaults to 0.5, Google's suggested starting point; the admin console shows the scores your visitors get, to tune it by.

Important

A visitor scored below MinimumScore is refused with nothing to solve, and is told to try again in a moment. Raise it with care, and watch the scores in the admin console after you do. Google publishes no test keys for v3.

Setting up hCaptcha

  1. Sign up for a free account at dashboard.hcaptcha.com.
  2. Under Sites, add a new site and copy its Site Key.
  3. In the site's settings, add every hostname the portal is served from. hCaptcha doesn't accept localhost or 127.0.0.1: to try real keys on your machine, map a name such as dev.example.com to 127.0.0.1 in your hosts file and add that, or use the test keys below.
  4. Copy the secret key from your account settings (or the site's own secret, where the dashboard offers one).

Test keys for local development

Each provider publishes a pair of test keys that work on any hostname, localhost included, and always pass — so you can try the portal's forms before creating an account. The widget shows that it is in test mode.

Provider Site key Secret key
Turnstile 1x00000000000000000000AA 1x0000000000000000000000000000000AA
ReCaptchaV2 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe
HCaptcha 10000000-ffff-ffff-ffff-000000000001 0x0000000000000000000000000000000000000000

Important

Test keys accept every visitor, robots included. Never deploy them: replace them with your own keys before the portal goes live.

Configuring the portal

Projects generated from the templates bind CaptchaOptions from the Captcha section of appsettings.json, which starts with Provider set to None. Each provider has a section of its own for its keys — Turnstile, ReCaptchaV2, ReCaptchaV3 and HCaptcha — and Provider chooses which is used, so you can keep several configured and switch between them with one setting. Put each provider's site key in its section. Forms takes the form names separated by commas; leave it out to keep the default.

Keep the secret keys in user secrets while developing, and in Key Vault or the App Service's settings when deployed — never in appsettings.json. In Key Vault, name them Captcha--Turnstile--SecretKey and so on:

This is the line in Program.cs that reads the section. A portal that wasn't generated from a template adds it after AddPowerPortalsProWebServer():

Or set the options in code, like any other IOptions class:

Tip

A provider set without both of its keys stops the portal at startup with a message naming what is missing, rather than starting with forms that would refuse every visitor.

Adding the challenge to your own forms

The template's account pages already carry it. On a form of your own, place the Captcha component — it renders nothing unless the form you name requires a challenge — and send the token it hands over when the form is submitted: TakeTokenAsync() in Blazor, takeToken() on the ref in React. A submission the server refused for the challenge raises CaptchaVerificationException in Blazor and CaptchaVerificationError in React.

React Blazor

A token is good for one submission, so taking it also resets the challenge: whatever the outcome — a wrong password, an address already in use — the next attempt gets a new one without the page doing anything. Under reCAPTCHA v3 there is no token until it is taken, so don't hold a submit button back until TokenChanged (Blazor) or onTokenChange (React) reports one.

A server-rendered Blazor page that calls UserManager itself, rather than going through IAuthService, checks the token with ICaptchaVerifier before acting:

Limiting attempts per address

Whether or not a CAPTCHA is configured, the portal limits how often one address submits each form anyone can submit without signing in — signing in, registering, resetting a password, resending a confirmation, accepting an invitation. By default an address may submit each 20 times a minute; past that, it is answered with 429 Too Many Requests until the minute is up. Each form is counted on its own. Change the limit under PowerPortalsPro:SignInRateLimit; a PermitLimit of 0 turns it off.

Important

The limit counts the address a request comes from. Behind a proxy or gateway that doesn't pass the visitor's address on — Azure Front Door, Application Gateway, a load balancer of your own — every visitor arrives from the proxy's, and they share one count. Forward the visitor's address with UseForwardedHeaders, naming the proxy in KnownProxies or KnownNetworks.

Content Security Policy

The widget is loaded from the provider's site. If your portal sends a Content-Security-Policy header, allow the provider's hosts in script-src and frame-src (hCaptcha also needs style-src and connect-src):

Provider Hosts
Turnstile https://challenges.cloudflare.com
ReCaptchaV2 https://www.google.com/recaptcha/, https://www.gstatic.com/recaptcha/
HCaptcha https://hcaptcha.com, https://*.hcaptcha.com

Troubleshooting