Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% set product_name = "WSO2 Identity Platform" %}
{% set product_url_format = "https://api.asgardeo.io/t/{organization_name}" %}
{% set product_url_sample = "https://api.asgardeo.io/t/bifrost" %}
{% set asgardeo_auth_script_warning =

' !!! warning "Important"

Check warning on line 6 in en/asgardeo/docs/guides/authentication/conditional-auth/detect-ai-agents.md

View workflow job for this annotation

GitHub Actions / Vale style check

[vale] reported by reviewdog 🐶 Try to keep sentences short (< 30 words). Raw Output: {"message":"Try to keep sentences short (< 30 words).","location":{"path":"en/asgardeo/docs/guides/authentication/conditional-auth/detect-ai-agents.md","range":{"start":{"line":6,"column":10},"end":{"line":6,"column":17}}},"severity":"INFO","code":{"value":"WSO2-IAM.SentenceLength"}}
As a security measure, WSO2 Identity Platform does not allow the usage of two consecutive periods (`..`) in authentication scripts.'
%}
{% include "../../../../../includes/guides/authentication/conditional-auth/detect-ai-agents.md" %}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ The available templates are categorized as follows:
- Access Control - These templates restrict user login to the application based on specified conditions.
- Adaptive MFA - These templates prompt two-factor authentication for login attempts based on specific conditions.
- Passkey Enrollment - These templates allows users to progressively enroll with passkey authenticator.
- AI Agents - These templates block AI agents or require a human to complete the sign-in.

The pre-defined templates are listed below.

Expand All @@ -74,6 +75,7 @@ The pre-defined templates are listed below.
| [Group-Based (Adaptive MFA)]({{base_path}}/guides/authentication/conditional-auth/group-based-template/) | This login flow prompts two-factor authentication (2FA) for users who belong to any of the given set of groups. |
| [IP-Based]({{base_path}}/guides/authentication/conditional-auth/ip-based-template/) | This login flow prompts two-factor authentication for users who log in from outside the given IP range. |
| [OTP Retry and Resend Limits]({{base_path}}/guides/authentication/conditional-auth/otp-retry-resend-limits/) | Limit how many times users can resend an OTP or enter a wrong OTP per application using the conditional authentication script. |
| [Detect AI agents]({{base_path}}/guides/authentication/conditional-auth/detect-ai-agents/) | Block AI agents or require a human-only verification step when a sign-in request is identified as coming from an AI agent. |
| [Passkey-Progressive-Enrollment-Based]({{base_path}}/guides/authentication/conditional-auth/passkey-progressive-enrollment-based-template/) | This login flow allows users to progressively enroll with passkey authenticator. |

If required, you can also use the script editor to introduce new functions and fields to an authentication script based on your requirement. See the instructions on [writing a custom authentication script]({{base_path}}/guides/authentication/conditional-auth/write-your-first-script/).
Expand Down
1 change: 1 addition & 0 deletions en/asgardeo/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ nav:
- Add push notification device progressive enrollment: guides/authentication/conditional-auth/push-device-progressive-enrollment-based-template.md
- Add on-demand silent password migration: guides/authentication/conditional-auth/on-demand-silent-password-migration-template.md
- OTP Retry and Resend Limits: guides/authentication/conditional-auth/otp-retry-resend-limits.md
- Detect AI agents: guides/authentication/conditional-auth/detect-ai-agents.md
- Write a custom authentication script: guides/authentication/conditional-auth/write-your-first-script.md
- App-native authentication:
- App-native authentication: guides/authentication/app-native-authentication/index.md
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% set product_name = "WSO2 Identity Server" %}
{% set product_url = "https://localhost:9443" %}

Check warning on line 2 in en/identity-server/7.3.0/docs/guides/authentication/conditional-auth/detect-ai-agents.md

View workflow job for this annotation

GitHub Actions / Vale style check

[vale] reported by reviewdog 🐶 Did you really mean 'product_url'? Raw Output: {"message":"Did you really mean 'product_url'?","location":{"path":"en/identity-server/7.3.0/docs/guides/authentication/conditional-auth/detect-ai-agents.md","range":{"start":{"line":2,"column":8},"end":{"line":2,"column":19}}},"severity":"WARNING","code":{"value":"Vale.Spelling"}}
{% set product_url_format = "https://localhost:9443" %}
{% set product_url_sample = "https://localhost:9443" %}
{% set asgardeo_auth_script_warning = "" %}

{% include "../../../../../../includes/guides/authentication/conditional-auth/detect-ai-agents.md" %}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ The available templates are categorized as follows:
- Environment
- Analytics
- IdP
- AI Agents

The pre-defined templates are listed below.

Expand All @@ -77,6 +78,7 @@ The pre-defined templates are listed below.
| [New-Device-Based]({{base_path}}/guides/authentication/conditional-auth/new-device-based-template/) | This login flow sends an email notification and/or prompts two-factor authentication for users who are logged in from a previously unused device. |
| [IP-Based]({{base_path}}/guides/authentication/conditional-auth/ip-based-template/) | This login flow prompts two-factor authentication for users who log in from outside the given IP range. |
| [OTP Retry and Resend Limits]({{base_path}}/guides/authentication/conditional-auth/otp-retry-resend-limits/) | Limit how many times users can resend an OTP or enter a wrong OTP per application using the conditional authentication script. |
| [Detect AI agents]({{base_path}}/guides/authentication/conditional-auth/detect-ai-agents/) | Block AI agents or require a human-only verification step when a sign-in request is identified as coming from an AI agent. |
| [Passkey-Progressive-Enrollment-Based]({{base_path}}/guides/authentication/conditional-auth/passkey-progressive-enrollment-based-template/) | This login flow permits users to seamlessly enroll their passkey on-the-fly, when Passkey is designated as the first authentication factor. |

If required, you can also use the script editor to introduce new functions and fields to an authentication script based on your requirement. See the instructions on [writing a custom authentication script]({{base_path}}/guides/authentication/conditional-auth/write-your-first-script/).
Expand Down
1 change: 1 addition & 0 deletions en/identity-server/7.3.0/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,7 @@ nav:
- Add push notification device progressive enrollment: guides/authentication/conditional-auth/push-device-progressive-enrollment-based-template.md
- Add on-demand silent password migration: guides/authentication/conditional-auth/on-demand-silent-password-migration-template.md
- OTP Retry and Resend Limits: guides/authentication/conditional-auth/otp-retry-resend-limits.md
- Detect AI agents: guides/authentication/conditional-auth/detect-ai-agents.md
- Write a custom authentication script: guides/authentication/conditional-auth/write-your-first-script.md
- Configure multi-attribute login: guides/authentication/multi-attribute-login.md
- App-native authentication:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% set product_name = "WSO2 Identity Server" %}
{% set product_url = "https://localhost:9443" %}

Check warning on line 2 in en/identity-server/next/docs/guides/authentication/conditional-auth/detect-ai-agents.md

View workflow job for this annotation

GitHub Actions / Vale style check

[vale] reported by reviewdog 🐶 Did you really mean 'product_url'? Raw Output: {"message":"Did you really mean 'product_url'?","location":{"path":"en/identity-server/next/docs/guides/authentication/conditional-auth/detect-ai-agents.md","range":{"start":{"line":2,"column":8},"end":{"line":2,"column":19}}},"severity":"WARNING","code":{"value":"Vale.Spelling"}}
{% set product_url_format = "https://localhost:9443" %}
{% set product_url_sample = "https://localhost:9443" %}
{% set asgardeo_auth_script_warning = "" %}

{% include "../../../../../../includes/guides/authentication/conditional-auth/detect-ai-agents.md" %}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ The available templates are categorized as follows:
- Environment
- Analytics
- IdP
- AI Agents

The pre-defined templates are listed below.

Expand All @@ -77,6 +78,7 @@ The pre-defined templates are listed below.
| [New-Device-Based]({{base_path}}/guides/authentication/conditional-auth/new-device-based-template/) | This login flow sends an email notification and/or prompts two-factor authentication for users who are logged in from a previously unused device. |
| [IP-Based]({{base_path}}/guides/authentication/conditional-auth/ip-based-template/) | This login flow prompts two-factor authentication for users who log in from outside the given IP range. |
| [OTP Retry and Resend Limits]({{base_path}}/guides/authentication/conditional-auth/otp-retry-resend-limits/) | Limit how many times users can resend an OTP or enter a wrong OTP per application using the conditional authentication script. |
| [Detect AI agents]({{base_path}}/guides/authentication/conditional-auth/detect-ai-agents/) | Block AI agents or require a human-only verification step when a sign-in request is identified as coming from an AI agent. |
| [Passkey-Progressive-Enrollment-Based]({{base_path}}/guides/authentication/conditional-auth/passkey-progressive-enrollment-based-template/) | This login flow permits users to seamlessly enroll their passkey on-the-fly, when Passkey is designated as the first authentication factor. |

If required, you can also use the script editor to introduce new functions and fields to an authentication script based on your requirement. See the instructions on [writing a custom authentication script]({{base_path}}/guides/authentication/conditional-auth/write-your-first-script/).
Expand Down
1 change: 1 addition & 0 deletions en/identity-server/next/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,7 @@ nav:
- Add push notification device progressive enrollment: guides/authentication/conditional-auth/push-device-progressive-enrollment-based-template.md
- Add on-demand silent password migration: guides/authentication/conditional-auth/on-demand-silent-password-migration-template.md
- OTP Retry and Resend Limits: guides/authentication/conditional-auth/otp-retry-resend-limits.md
- Detect AI agents: guides/authentication/conditional-auth/detect-ai-agents.md
- Write a custom authentication script: guides/authentication/conditional-auth/write-your-first-script.md
- Configure multi-attribute login: guides/authentication/multi-attribute-login.md
- App-native authentication:
Expand Down
185 changes: 185 additions & 0 deletions en/includes/guides/authentication/conditional-auth/detect-ai-agents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# Detect AI agents in login flows

AI agents can sign in to applications on behalf of users, either by driving a browser or by calling endpoints directly. {{ product_name }} lets you detect these requests with a conditional authentication script and then block them or require a human to complete the sign-in.

{{ product_name }} provides two built-in conditional authentication templates in the **AI Agents** category of the script editor.

<table>
<thead>
<tr>
<th>Template</th>
<th>Behavior</th>
</tr>
</thead>
<tbody>
<tr>
<td><b>AI Agent Blocking</b></td>
<td>Denies the sign-in when an AI agent is detected. Otherwise, the application's login steps run as usual.</td>
</tr>
<tr>
<td><b>AI Agent Human-in-the-Loop</b></td>

Check warning on line 20 in en/includes/guides/authentication/conditional-auth/detect-ai-agents.md

View workflow job for this annotation

GitHub Actions / Vale style check

[vale] reported by reviewdog 🐶 Try to keep sentences short (< 30 words). Raw Output: {"message":"Try to keep sentences short (< 30 words).","location":{"path":"en/includes/guides/authentication/conditional-auth/detect-ai-agents.md","range":{"start":{"line":20,"column":20},"end":{"line":20,"column":22}}},"severity":"INFO","code":{"value":"WSO2-IAM.SentenceLength"}}
<td>Runs the first login step, which an agent may complete, and then requires a human-only verification step when an AI agent is detected.</td>
</tr>
</tbody>
</table>

Both templates detect agents that identify themselves with [Web Bot Auth](#web-bot-auth). To detect other agents, extend the `detectAgent()` function with the [methods below](#ways-to-identify-ai-agents).

## Prerequisites

- You need to [register an application with {{ product_name }}]({{base_path}}/guides/applications/). You can register your own application or use one of the [sample applications]({{base_path}}/get-started/try-samples/) provided.

- Make sure your load balancers and proxies forward the Web Bot Auth headers (`Signature`, `Signature-Input` and `Signature-Agent`) to {{ product_name }}.

- To use the **AI Agent Human-in-the-Loop** template, users must be able to complete the [human-only verification step](#choose-a-human-only-verification-step), for example with a registered passkey.

## Apply a template

1. On the {{ product_name }} Console, click **Applications**.

2. Select the relevant application and go to its **Login Flow** tab.

3. Add the template using your preferred editor:

{% if product_name == "WSO2 Identity Platform" %}
=== "Classic Editor"
1. Click **Start with default configuration** to define the login flow starting with the `username and password` login.

2. Turn on **Conditional Authentication** by switching the toggle on.

3. Select the **AI Agents > AI Agent Blocking** or **AI Agents > AI Agent Human-in-the-Loop** template.

=== "Visual Editor"
1. Switch to the **Visual Editor** tab, and expand **Predefined Flows** > **Conditional Login Flows** > **AI Agents**.

2. Click **+ ADD** next to **AI Agent Blocking** or **AI Agent Human-in-the-Loop**.

3. Click **Confirm** to replace any existing script with the selected predefined script.
{% else %}
1. Go to **Predefined Flows** > **Conditional Login Flows**.

2. Click **AI Agents** > **AI Agent Blocking** or **AI Agent Human-in-the-Loop** > **ADD** to add the script.

3. Click **Confirm** to replace any existing script with the selected predefined script.
{% endif %}

{{asgardeo_auth_script_warning}}

4. Extend `detectAgent()` if needed, and click **Update** to confirm.

Check failure on line 68 in en/includes/guides/authentication/conditional-auth/detect-ai-agents.md

View workflow job for this annotation

GitHub Actions / lint

Ordered list item prefix

en/includes/guides/authentication/conditional-auth/detect-ai-agents.md:68:1 MD029/ol-prefix Ordered list item prefix [Expected: 1; Actual: 4; Style: 1/1/1] https://github.com/DavidAnson/markdownlint/blob/v0.38.0/doc/md029.md
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## How it works

Both templates call `detectAgent(context)` in `onLoginRequest`. The default `detectAgent()` returns `true` when the request has a `Signature-Agent` header, or a `Signature-Input` header that contains `web-bot-auth`:

```js
var detectAgent = function (context) {
// Header names are lower-case.
var headers = context.request.headers;
var signatureInput = String(headers['signature-input'] || '');
return !!headers['signature-agent'] || signatureInput.indexOf('web-bot-auth') >= 0;
};
```

**AI Agent Blocking** denies the sign-in with the message in the `errorMessage` parameter. For API-based (app-native) requests, the template fails the flow instead of showing an error page.

**AI Agent Human-in-the-Loop** runs step 1 for every user. When an AI agent is detected, it then runs step 2, so the sign-in can't continue until a human completes it.

### Choose a human-only verification step

Step 1 is your application's usual sign-in, and an agent may complete it. Step 2 must be a factor that only the user can complete, on their own device or with biometrics. The template uses a passkey by default.

<table>
<thead>
<tr>
<th>Step 2 option</th>
<th>Suitability</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="{{base_path}}/guides/authentication/mfa/add-push-auth-login/">Push notification</a></td>
<td>Recommended. The user approves the sign-in on their own mobile device, wherever the agent runs.</td>
</tr>
<tr>
<td><a href="{{base_path}}/guides/authentication/mfa/add-passkey-login/">Passkey</a></td>
<td>Recommended. The user verifies with biometrics or a device PIN on their own device.</td>
</tr>
<tr>
<td>TOTP, email OTP or SMS OTP</td>
<td>Not recommended. An agent with access to the user's authenticator, mailbox or messages can complete it.</td>
</tr>
</tbody>
</table>

!!! warning
Don't enable progressive enrollment for the step 2 factor in this flow. An agent that holds the user's password could enroll its own device.

!!! note
Find out more about the scripting language in the [Conditional Authentication API Reference]({{base_path}}/references/conditional-auth/api-reference/).

## Ways to identify AI agents

No single signal identifies every AI agent. Add the checks that fit your application inside `detectAgent()`, above the final `return` statement. Header names in `context.request.headers` are lower-case.

### Web Bot Auth

Check warning on line 124 in en/includes/guides/authentication/conditional-auth/detect-ai-agents.md

View workflow job for this annotation

GitHub Actions / Vale style check

[vale] reported by reviewdog 🐶 'Web Bot Auth' should use sentence-style capitalization. Raw Output: {"message":"'Web Bot Auth' should use sentence-style capitalization.","location":{"path":"en/includes/guides/authentication/conditional-auth/detect-ai-agents.md","range":{"start":{"line":124,"column":5},"end":{"line":124,"column":17}}},"severity":"INFO","code":{"value":"WSO2-IAM.SentenceStyleTitles"}}

**Recommended. Built into both templates.**

Web Bot Auth uses HTTP Message Signatures ([IETF draft-ietf-webbotauth-httpsig-protocol](https://datatracker.ietf.org/doc/draft-ietf-webbotauth-httpsig-protocol/)) so that an agent can prove who it is. A signed agent sends the `Signature`, `Signature-Input` (with `tag="web-bot-auth"`) and `Signature-Agent` headers, and publishes its public keys at `<origin>/.well-known/http-message-signatures-directory`.

Check warning on line 128 in en/includes/guides/authentication/conditional-auth/detect-ai-agents.md

View workflow job for this annotation

GitHub Actions / Vale style check

[vale] reported by reviewdog 🐶 'it is' is too wordy. Raw Output: {"message":"'it is' is too wordy.","location":{"path":"en/includes/guides/authentication/conditional-auth/detect-ai-agents.md","range":{"start":{"line":128,"column":196},"end":{"line":128,"column":201}}},"severity":"WARNING","code":{"value":"WSO2-IAM.TooWordy"}}

Declaring itself as an agent is enough to deny a request or require a step-up. It doesn't prove identity, because any client can send these headers. Authentication scripts can't verify HTTP signatures, so verify them at the edge (your WAF, CDN or reverse proxy) before you trust or allow-list an agent. Configure the edge to verify the signature against the signer's key directory, add a trusted header such as `x-verified-agent`, and strip that header from all incoming client requests. The script then reads the trusted header:

```js
// Add near the other top-level variables.
var trustedAgents = ['https://agent.example.com'];

// Add inside detectAgent(), above the declared-agent check.
var verifiedAgent = context.request.headers['x-verified-agent'];
if (verifiedAgent) {
// A verified agent is an agent, unless you trust it explicitly.
return trustedAgents.indexOf(String(verifiedAgent)) < 0;
}
```

### User agent markers

Known agents and browser automation tools often put a marker in the `User-Agent` header.

```js
// Add near the other top-level variables.
var agentUserAgents = ['HeadlessChrome', 'ChatGPT', 'Claude', 'Google-Agent', 'Perplexity', 'Playwright', 'Puppeteer', 'Selenium'];

// Add inside detectAgent().
var userAgent = String(context.request.headers['user-agent'] || '');
for (var i = 0; i < agentUserAgents.length; i++) {
if (userAgent.indexOf(agentUserAgents[i]) >= 0) {
return true;
}
}
```

!!! warning
Clients can set any `User-Agent` value, so this check is easy to spoof. Prefer [Web Bot Auth](#web-bot-auth) for agents that sign their requests.

### Agent provider IP ranges

Some AI agent providers publish the IP ranges their agents use. Get the current lists from each provider's documentation, and match `context.request.ip` against them. Copy the `convertIpToLong`, `getIpAddrInLong` and `isCorporateIP` functions from the built-in [IP-Based template]({{base_path}}/guides/authentication/conditional-auth/ip-based-template/) into your script.

```js
// Add near the other top-level variables. Replace with the ranges published by the providers.
var agentIpRanges = ['203.0.113.0/24', '198.51.100.0/24'];

// Add inside detectAgent().
if (isCorporateIP(context.request.ip, agentIpRanges)) {
return true;
}
```

!!! note
The helper functions handle IPv4 only. `context.request.ip` honors the `X-Forwarded-For` header, so configure your load balancer to overwrite this header with the real client address.

## Limitations

- Request signals such as headers and IP addresses can be spoofed. Verify cryptographic signals at the edge.

- Agents that operate the user's own browser send normal browser headers and can't be told apart from the user by request signals.
Loading