Skip to content

Commit aa6c473

Browse files
Document Turnstile fraud protection and new sign-up rule conditions
1 parent 0886586 commit aa6c473

File tree

3 files changed

+88
-4
lines changed

3 files changed

+88
-4
lines changed

docs/content/docs/(guides)/concepts/sign-up-rules.mdx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Sign-up Rules
33
description: Control who can sign up for your application with customizable rules.
44
icon: ShieldCheck
5-
lastModified: "2026-02-24"
5+
lastModified: "2026-03-20"
66
---
77

88
Sign-up rules let you control who can sign up for your application. You can create rules that evaluate sign-up attempts based on conditions like email domain or authentication method, then allow, reject, or restrict users accordingly.
@@ -31,6 +31,9 @@ When building rule conditions, you have access to these context variables:
3131
| `emailDomain` | string | The domain part of the email (after @) |
3232
| `authMethod` | string | The authentication method: `password`, `otp`, `oauth`, or `passkey` |
3333
| `oauthProvider` | string | The OAuth provider ID if using OAuth (e.g., `google`, `github`), empty string otherwise |
34+
| `countryCode` | string | ISO 3166-1 alpha-2 country code detected at sign-up (e.g., `US`, `DE`, `JP`). Empty string if unavailable. |
35+
| `riskScores.bot` | number | Bot risk score from 0-100. Higher values indicate higher likelihood of automated sign-up attempts. |
36+
| `riskScores.free_trial_abuse` | number | Free trial abuse risk score from 0-100. Higher values indicate abuse patterns like disposable emails or repeated sign-ups. |
3437

3538
The condition builder supports these operations on string values:
3639

@@ -39,6 +42,9 @@ The condition builder supports these operations on string values:
3942
- `endsWith("suffix")` - Check if value ends with a suffix
4043
- `matches("regex")` - Check if value matches a regular expression
4144
- `==` and `!=` - Exact equality comparisons
45+
- `in` - Check if value is in a list (e.g., `countryCode in ["US", "CA"]`)
46+
47+
For numeric fields like risk scores, you can use comparison operators: `>`, `>=`, `<`, `<=`.
4248

4349
You can combine multiple conditions using AND/OR logic.
4450

@@ -100,6 +106,27 @@ Allow password sign-ups from any domain, but restrict OAuth sign-ups:
100106
2. Rule 2: `authMethod == "oauth"` → Restrict
101107
3. Default: Allow
102108

109+
### Block high-risk bot sign-ups
110+
111+
Block sign-ups with a high bot risk score:
112+
113+
- Condition: `riskScores.bot > 70`
114+
- Action: Reject
115+
116+
### Restrict sign-ups from specific countries
117+
118+
Require manual review for sign-ups from certain countries:
119+
120+
- Condition: `countryCode in ["XX", "YY"]` (replace with actual country codes)
121+
- Action: Restrict
122+
123+
### Combined fraud signals
124+
125+
Block sign-ups with multiple fraud indicators:
126+
127+
- Condition: `riskScores.bot > 50 && riskScores.free_trial_abuse > 50`
128+
- Action: Reject
129+
103130
## Analytics
104131

105132
The dashboard shows analytics for each rule, including how many times it's been triggered over the past 48 hours. Use this to understand your sign-up patterns and tune your rules.

docs/content/docs/(guides)/others/self-host.mdx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Self-host
3-
lastModified: "2026-01-10"
3+
lastModified: "2026-03-20"
44
---
55

66
<Info type="danger">
@@ -121,3 +121,23 @@ To manage your dashboard configs with this account, manually go into the databas
121121
Go back to the dashboard, refresh the page, and you should see the "Stack Dashboard" project. We recommend disabling new user sign-ups to your internal project to avoid unauthorized account and project creations.
122122

123123
Now, create a new project for your app and follow the [normal setup process](../getting-started/setup.mdx). Add `NEXT_PUBLIC_STACK_API_URL=https://your-backend-url.com` to your app's environment variables so that it connects to your API backend instead of the default Stack Auth API backend (https://api.stack-auth.com).
124+
125+
## Bot protection (Turnstile)
126+
127+
Stack Auth uses Cloudflare Turnstile to protect sign-up flows from bots. By default, self-hosted instances use Cloudflare's development test keys, which always pass without showing a challenge.
128+
129+
For production, configure your own Turnstile keys from the [Cloudflare Dashboard](https://dash.cloudflare.com/?to=/:account/turnstile):
130+
131+
| Environment Variable | Description |
132+
|---------------------|-------------|
133+
| `NEXT_PUBLIC_STACK_BOT_CHALLENGE_SITE_KEY` | Turnstile site key for visible challenges. |
134+
| `NEXT_PUBLIC_STACK_BOT_CHALLENGE_INVISIBLE_SITE_KEY` | Turnstile site key for invisible challenges. |
135+
| `STACK_TURNSTILE_SECRET_KEY` | Turnstile secret key for server-side verification. |
136+
137+
Optional settings:
138+
139+
| Environment Variable | Description |
140+
|---------------------|-------------|
141+
| `STACK_DISABLE_BOT_CHALLENGE` | Set to `true` to disable Turnstile entirely. |
142+
| `STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE` | Set to `true` to allow sign-ups even when the visible challenge fails (not recommended for production). |
143+
| `STACK_TRUSTED_PROXY` | Set to `vercel` or `cloudflare` to trust the respective reverse proxy for reading client IP addresses. Required for accurate IP-based fraud detection when running behind a proxy. |

docs/content/docs/sdk/types/user.mdx

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,14 +1609,16 @@ The `ServerUser` object contains most `CurrentUser` properties and methods with
16091609

16101610
### Table of Contents
16111611

1612-
<ClickableTableOfContents
1612+
<ClickableTableOfContents
16131613
title="ServerUser Table of Contents"
1614-
code={`type ServerUser =
1614+
code={`type ServerUser =
16151615
// Inherits most functionality from CurrentUser
16161616
& Omit<CurrentUser, "getAuthJson" | "signOut"> //$stack-link-to:#currentuser
16171617
& {
16181618
lastActiveAt: Date; //$stack-link-to:#serveruserlastactiveat
16191619
serverMetadata: Json; //$stack-link-to:#serveruserservermetadata
1620+
countryCode: string | null; //$stack-link-to:#serverusercountrycode
1621+
riskScores: { signUp: { bot: number; freeTrialAbuse: number } }; //$stack-link-to:#serveruserriskscores
16201622
16211623
update(data): Promise<void>; //$stack-link-to:#serveruserupdate
16221624
@@ -1656,6 +1658,41 @@ code={`type ServerUser =
16561658
</MethodLayout>
16571659
</CollapsibleTypesSection>
16581660

1661+
<CollapsibleTypesSection type="serverUser" property="countryCode" defaultOpen={false}>
1662+
<MethodLayout>
1663+
<MethodContent>
1664+
The ISO 3166-1 alpha-2 country code detected at sign-up (e.g., `US`, `DE`, `JP`). Returns `null` if the country could not be determined.
1665+
</MethodContent>
1666+
<MethodAside title="Type Definition">
1667+
1668+
```typescript
1669+
declare const countryCode: string | null;
1670+
```
1671+
</MethodAside>
1672+
</MethodLayout>
1673+
</CollapsibleTypesSection>
1674+
1675+
<CollapsibleTypesSection type="serverUser" property="riskScores" defaultOpen={false}>
1676+
<MethodLayout>
1677+
<MethodContent>
1678+
Risk scores calculated at sign-up for fraud protection. Contains:
1679+
- `signUp.bot`: Bot risk score from 0-100. Higher values indicate higher likelihood of automated sign-up attempts.
1680+
- `signUp.freeTrialAbuse`: Free trial abuse risk score from 0-100. Higher values indicate abuse patterns like disposable emails or repeated sign-ups.
1681+
</MethodContent>
1682+
<MethodAside title="Type Definition">
1683+
1684+
```typescript
1685+
declare const riskScores: {
1686+
signUp: {
1687+
bot: number;
1688+
freeTrialAbuse: number;
1689+
};
1690+
};
1691+
```
1692+
</MethodAside>
1693+
</MethodLayout>
1694+
</CollapsibleTypesSection>
1695+
16591696
<CollapsibleTypesSection type="serverUser" property="update" signature="data" defaultOpen={false}>
16601697
<MethodLayout>
16611698
<MethodContent>

0 commit comments

Comments
 (0)