diff --git a/en/asgardeo/docs/guides/authentication/conditional-auth/detect-ai-agents.md b/en/asgardeo/docs/guides/authentication/conditional-auth/detect-ai-agents.md new file mode 100644 index 0000000000..ab1e16311f --- /dev/null +++ b/en/asgardeo/docs/guides/authentication/conditional-auth/detect-ai-agents.md @@ -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" + 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" %} diff --git a/en/asgardeo/docs/guides/authentication/conditional-auth/index.md b/en/asgardeo/docs/guides/authentication/conditional-auth/index.md index a910f8391d..7e0f361a1c 100644 --- a/en/asgardeo/docs/guides/authentication/conditional-auth/index.md +++ b/en/asgardeo/docs/guides/authentication/conditional-auth/index.md @@ -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. @@ -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/). diff --git a/en/asgardeo/mkdocs.yml b/en/asgardeo/mkdocs.yml index e2cb416a1a..8d5c0fa2b2 100644 --- a/en/asgardeo/mkdocs.yml +++ b/en/asgardeo/mkdocs.yml @@ -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 diff --git a/en/identity-server/7.3.0/docs/guides/authentication/conditional-auth/detect-ai-agents.md b/en/identity-server/7.3.0/docs/guides/authentication/conditional-auth/detect-ai-agents.md new file mode 100644 index 0000000000..9af0e9d803 --- /dev/null +++ b/en/identity-server/7.3.0/docs/guides/authentication/conditional-auth/detect-ai-agents.md @@ -0,0 +1,7 @@ +{% set product_name = "WSO2 Identity Server" %} +{% set product_url = "https://localhost:9443" %} +{% 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" %} diff --git a/en/identity-server/7.3.0/docs/guides/authentication/conditional-auth/index.md b/en/identity-server/7.3.0/docs/guides/authentication/conditional-auth/index.md index d8298b29ed..46a8883afe 100644 --- a/en/identity-server/7.3.0/docs/guides/authentication/conditional-auth/index.md +++ b/en/identity-server/7.3.0/docs/guides/authentication/conditional-auth/index.md @@ -63,6 +63,7 @@ The available templates are categorized as follows: - Environment - Analytics - IdP +- AI Agents The pre-defined templates are listed below. @@ -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/). diff --git a/en/identity-server/7.3.0/mkdocs.yml b/en/identity-server/7.3.0/mkdocs.yml index 25dee26288..0c2d2190ce 100644 --- a/en/identity-server/7.3.0/mkdocs.yml +++ b/en/identity-server/7.3.0/mkdocs.yml @@ -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: diff --git a/en/identity-server/next/docs/guides/authentication/conditional-auth/detect-ai-agents.md b/en/identity-server/next/docs/guides/authentication/conditional-auth/detect-ai-agents.md new file mode 100644 index 0000000000..9af0e9d803 --- /dev/null +++ b/en/identity-server/next/docs/guides/authentication/conditional-auth/detect-ai-agents.md @@ -0,0 +1,7 @@ +{% set product_name = "WSO2 Identity Server" %} +{% set product_url = "https://localhost:9443" %} +{% 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" %} diff --git a/en/identity-server/next/docs/guides/authentication/conditional-auth/index.md b/en/identity-server/next/docs/guides/authentication/conditional-auth/index.md index d8298b29ed..46a8883afe 100644 --- a/en/identity-server/next/docs/guides/authentication/conditional-auth/index.md +++ b/en/identity-server/next/docs/guides/authentication/conditional-auth/index.md @@ -63,6 +63,7 @@ The available templates are categorized as follows: - Environment - Analytics - IdP +- AI Agents The pre-defined templates are listed below. @@ -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/). diff --git a/en/identity-server/next/mkdocs.yml b/en/identity-server/next/mkdocs.yml index 533a46f6ac..77c00de76b 100644 --- a/en/identity-server/next/mkdocs.yml +++ b/en/identity-server/next/mkdocs.yml @@ -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: diff --git a/en/includes/guides/authentication/conditional-auth/detect-ai-agents.md b/en/includes/guides/authentication/conditional-auth/detect-ai-agents.md new file mode 100644 index 0000000000..ae043960af --- /dev/null +++ b/en/includes/guides/authentication/conditional-auth/detect-ai-agents.md @@ -0,0 +1,186 @@ +# 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. + + + + + + + + + + + + + + + + + + +
TemplateBehavior
AI Agent BlockingDenies the sign-in when an AI agent is detected. Otherwise, the application's login steps run as usual.
AI Agent Human-in-the-LoopRuns the first login step, which an agent may complete, and then requires a human-only verification step when an AI agent is detected.
+ +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 %} + +4. Extend `detectAgent()` if needed, and click **Update** to confirm. + +{{asgardeo_auth_script_warning}} + +## 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 with the `tag="web-bot-auth"` parameter: + +```js +var detectAgent = function (context) { + // Header names are lower-case. + var headers = context.request.headers; + var signatureInput = String(headers['signature-input'] || ''); + // Match the tag parameter exactly, e.g. sig1=(...);tag="web-bot-auth". + return !!headers['signature-agent'] || /;\s*tag="web-bot-auth"\s*(;|,|$)/.test(signatureInput); +}; +``` + +**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. + + + + + + + + + + + + + + + + + + + + + + +
Step 2 optionSuitability
Push notificationRecommended. The user approves the sign-in on their own mobile device, wherever the agent runs.
PasskeyRecommended. The user verifies with biometrics or a device PIN on their own device.
TOTP, email OTP or SMS OTPNot recommended. An agent with access to the user's authenticator, mailbox or messages can complete it.
+ +!!! 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 + +**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 `/.well-known/http-message-signatures-directory`. + +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.