Overview
Ory Actions are an extensibility mechanism provided by the Ory Network that allows you to integrate with third-party services:
- CRM platforms, such as Mailchimp or HubSpot
- Payment gateways, such as Stripe
- Business analytics tools, such as Google Analytics, Mixpanel, or Segment
- Integration platforms, such as Zapier or IFTT
With Ory Actions, you can define custom business logic and automate the behavior of the system in response to events that occur in your Ory-powered applications. You can write Actions in any programming language and trigger them through events such as user registration, or users resetting their passwords. This gives you a flexible way to extend the capabilities of Ory Network, integrate with other services to streamline your workflows, and improve the overall experience of your users.
Ory Actions is a feature supported by two of the Ory services:
- Ory Identities: Execute actions in response to user-related events such as login, registration, account recovery, account verification, or user settings update.
- Ory OAuth2 and OpenID Connect: Execute actions in response to refreshing OAuth 2.0 Access Tokens.
Actions in Ory Identities
Ory Identities is an identity management solution that supports actions for user-related events: login, registration, account recovery, account verification, or user settings update.
Actions triggered after events
- Login actions allow you to automate behavior in response to users logging in to your application. For example, you can use Ory Actions to update user information in your database or send welcome emails to users that log in for the first time.
- Registration actions allow you to automate behavior in response to users registering in your application. For example, you can use Ory Actions to automatically create a user account in your database or add the user to your mailing list.
- Account recovery actions allow you to automate behavior in response to users initiating the account recovery process. For example, you can use Ory Actions to send a password reset email to the user or update user information in your database.
- Verification actions allow you to automate behavior in response to users verifying their accounts. For example, you can use Ory Actions to update user information in your database or send welcome emails to users who verified their accounts.
- Settings actions allow you to automate behavior in response to users updating their account settings. For example, you can use Ory Actions to update user information in your database or send confirmation or summary emails to users.
Actions triggered before events
You can use Ory Actions before events such as user login, registration, triggering account recovery or verification, and updating account settings.
For example, you can enforce invite-only registration in your application by triggering an action that checks if certain criteria are met before the registration flow starts. This can be useful for controlling the number of users that have access to your application and ensuring that only authorized users can register.
You can also use Ory Actions to add additional security checks when users initiate login, registration, account recovery or verification, and settings update flows. For example, you can create logic that checks the IP address of the user to ensure that the request is coming from a trusted location or to verify that the user's email address is associated with a valid domain.
By using Ory Actions you can have a high degree of control over the flow of events in your application and improve the overall security and user experience.
Action triggers
Ory Identities supports the following action triggers:
beforelogin: The hook runs when the user starts the login flow.submitlogin: The hook runs each time the user submits the login flow, before Ory checks what the user submitted.afterlogin: The hook runs when the user is successfully authenticated, before the system issues an Ory Session.failurelogin: The hook runs in the background when Ory rejects a login attempt's credentials.beforeregistration: The hook runs when a registration flow starts.afterregistration: The hook runs when a user successfully registers in the system.beforerecovery: The hook runs when the user starts the recovery flow.afterrecovery: The hook runs when the user successfully recovers their password.beforesettings: The hook runs when the user starts the account settings flow.aftersettings: The hook runs when the user successfully changes their account settings.beforeverification: The hook runs when the user starts the verification flow.afterverification: The hook runs when the user verifies their account.
before actions run when Ory Kratos Identities creates the flow, not when the user submits it. Their payload has no
transient_payload, no identity, and no credentials, because none of that exists yet. To act on data the user submits, such as a
CAPTCHA or risk token, use the submit login trigger or the after registration trigger with
can_interrupt: true. The submit login action runs before Ory Kratos Identities checks the submitted credentials. The after
login action runs only after Ory Kratos Identities verified them. It can still block the login, but it never runs for a wrong
password. The after registration action runs before Ory Kratos Identities persists the identity, so it can still block the flow.
Login submit trigger
The submit trigger is available on Ory Network and in the Ory Enterprise License (OEL). Ory Open Source (OOS) doesn't include
it.
Use the submit login trigger to check a login attempt before Ory Kratos Identities acts on it, for example to ask a fraud
detection service whether to allow it. Ory Kratos Identities runs the trigger's hooks on every login submission that a login
method accepts. The hooks run after Ory Kratos Identities decoded the request, checked its CSRF token, and, where it applies,
brute-force protection allowed the attempt. They run before Ory
Kratos Identities looks up the identifier, checks a credential, sends a code, or redirects the user to an identity provider.
The hooks run once per request, not once per flow. An identifier-first password login runs them twice: once for the identifier and once for the password. Every retry runs them again.
ctx.submission.step tells your endpoint what Ory Kratos Identities is about to do:
| Step | Ory Kratos Identities is about to | Methods |
|---|---|---|
identifier | Look up the identifier and start the next step, such as showing the login methods or sending a login code | Identifier-first login, login code (including a resend), and WebAuthn when the user submits only the identifier |
verify | Check a submitted credential or proof | Password, login code, passkey, WebAuthn, TOTP, lookup secret (recovery code), social sign-in with an id_token from a native app, FedCM, and device authentication |
redirect | Redirect the user to the identity provider | Social sign-in in the browser, enterprise SSO (SAML), and IdP-initiated login |
provider_verified | Sign in a user whom the identity provider already authenticated | A social sign-in or SAML registration that turns into a login because the account already exists |
The trigger doesn't run for:
- Flow creation, which runs the
beforetrigger instead. This includes the code that Ory Kratos Identities sends when it creates a flow for a second-factor code login. - The identity provider's callback after the
redirectstep. The provider sends that request, not your client. - A passkey request without an assertion, which only asks Ory Kratos Identities for the passkey challenge.
- Test flows that check a social sign-in provider's configuration.
Only the web_hook action runs on this trigger.
selfservice:
flows:
login:
submit:
hooks:
- hook: web_hook
config:
url: https://example.com/login-precheck
method: POST
body: base64://ENCODED_JSONNET
can_interrupt: true
The trigger has no hooks per authentication method. To skip steps or methods that your endpoint doesn't need, cancel the web hook in the Jsonnet template. A canceled web hook sends no request, and the submission continues:
function(ctx)
if ctx.submission.method == "code" && ctx.submission.step == "identifier" then
error "cancel"
else
{
method: ctx.submission.method,
step: ctx.submission.step,
identifier: std.get(ctx.submission, "identifier"),
risk_token: std.get(std.get(ctx.flow, "transient_payload", {}), "risk_token"),
}
The Jsonnet context has the fields that every login web hook gets, such as flow, request_headers, request_url, location,
ip_labels, and asn. It has no identity or session. Instead, ctx.submission describes the submission:
{
"method": "password",
"step": "verify",
"identifier": "[email protected]"
}
methodis the authentication method of the submission, with the same values asctx.failure.methodin thefailuretrigger:password,code,identifier_first,passkey,webauthn,totp,lookup_secret,oidc,saml, ordeviceauthn.identifier_firstis the identifier step of identifier-first login. FedCM reportsoidc.stepisidentifier,verify,redirect, orprovider_verified.identifieris the identifier as the user submitted it, such as an email address. It's present only for thepassword,code, andidentifier_firstmethods, and for passwordless WebAuthn login.provideris the ID of the social sign-in or SAML provider that the user chose. It's present only for theoidcandsamlmethods.
ctx.flow.transient_payload is the transient_payload of the submitted request. Ory Kratos Identities doesn't keep it between
requests, so your client has to send the data your endpoint needs, such as a risk token, with every submission. At the
provider_verified step of a social sign-in, it's the transient_payload of the registration request that started the sign-in.
Providers on the native SAML engine and IdP-initiated logins have no
transient_payload.
The context doesn't contain the password, login code, TOTP code, lookup secret, id_token, nonce, or WebAuthn assertion that the
user submitted. At the provider_verified step of a social sign-in, the request is the provider's callback, so ctx.request_url
can include the authorization code and state in its query parameters.
Your endpoint can block a submission only when the hook sets can_interrupt: true. The configuration rejects
response.parse: true, because there's no identity to update. To block, answer with HTTP status 400 or 403 and a messages body,
as described in
flow-interrupting webhooks. Ory Kratos
Identities shows the messages on the flow like a validation error and doesn't check the credential, send the code, or redirect the
user. An IdP-initiated login has no form to return to, so a blocked submission shows the error page instead. A blocked submission
doesn't count toward brute-force protection and doesn't run the failure trigger.
Don't answer with 429 or a 5xx status to block. Ory Kratos Identities retries most of them, as described in
webhook retries, and when the retries run out, the
submission fails with a generic error. Your messages never reach the flow. Other errors also fail the submission, such as an error
status without valid messages, a timeout, or an endpoint that can't be reached. With the retries, a submission waits up to about
93 seconds for an endpoint that doesn't answer, and up to 150 seconds for one that answers 429 or 503 with a Retry-After header.
With response.ignore: true instead of can_interrupt: true, the hook runs in the background and can't block. Its payload shows
the flow as it was at the submission.
Your endpoint receives every attempt that a login method accepts, including attempts with an unknown identifier or a wrong password. Failed attempts can outnumber successful logins many times over, so plan your endpoint's capacity for all login attempts, not only for successful ones. Attempts that brute-force protection rejects don't reach your endpoint.
Each synchronous submit hook adds to the time that every login submission takes: Ory Kratos Identities encodes the context,
renders your Jsonnet template, and waits for your endpoint's answer. In a local benchmark that rendered one template at a time, a
template that copies the flow ID, request headers, cookies, and transient_payload from a password login context of 2 KB took
about 0.7 ms to render. The same template wrapped in std.prune took about 1.5 ms, and larger contexts take longer. An
identifier-first login pays this cost at least twice. A hook with response.ignore: true still encodes the context during the
request, but renders the template and calls your endpoint in the background.
Login failure trigger
The failure trigger is available on Ory Network and in the Ory Enterprise License (OEL). Ory Open Source (OOS) doesn't include
it.
Use the failure login trigger to report rejected login attempts to your own endpoint, for example a fraud detection service. Ory
Kratos Identities runs the trigger's hooks once for every login attempt that it rejects because of one of these:
- A wrong password or TOTP code, or a lookup secret (recovery code) that is wrong or already used. A password for an identifier that has no account counts as wrong.
- A wrong or already used login code.
- An identifier that Ory Kratos Identities rejects because no account matches it, in identifier-first login and code login. For identifier-first login, this applies only when account enumeration mitigation is off.
- A passkey, WebAuthn, or device authentication assertion that fails verification.
- An account that has no security key, passkey, or DeviceAuthn device registered for the method the user chose.
- A social sign-in provider that denies the login, or a provider response that Ory Kratos Identities rejects. This includes a
native
id_tokenthat fails verification. - A social sign-in that Ory Kratos Identities can't complete with the provider, for example because the provider is unavailable or misconfigured. This covers failures of the token exchange, the user info request, and the signing key fetch.
- A login that Ory Kratos Identities rejects because the identity is disabled, including a social sign-up that turns into a login
because the account already exists.
ctx.identitythen hasstate: "inactive".
The trigger doesn't run for:
- Requests that Ory Kratos Identities can't process, such as malformed submissions, failed CSRF checks, and expired flows.
- Users who are already signed in.
- Attempts that brute-force protection refuses.
- Attempts that a web hook blocks.
- Internal errors.
- Test flows that check a social sign-in provider's configuration.
- Failures on a registration flow, including a social sign-up that fails before it turns into a login.
- Enterprise SSO (SAML) sign-in failures.
Only the web_hook action runs on this trigger, and it always runs in the background. The response to the user doesn't wait for
it, and the web hook can't change that response. The configuration rejects can_interrupt: true and response.parse: true, and
response.ignore has no effect.
Ory Kratos Identities ignores your endpoint's response and makes one delivery attempt with a 10-second timeout. It doesn't retry a failed delivery.
selfservice:
flows:
login:
failure:
hooks:
- hook: web_hook
config:
url: https://example.com/login-failed
method: POST
body: base64://ENCODED_JSONNET
The trigger has no hooks per authentication method. To handle only some methods, read ctx.failure.method in the Jsonnet template
and cancel the web hook for the others.
The Jsonnet context has the fields that every login web hook gets, such as flow, request_headers, request_url, location,
ip_labels, and asn. It has no session. ctx.failure describes the rejected attempt:
{
"method": "password",
"identifier": "[email protected]",
"identity_id": "9f425a8d-7efc-4768-8f23-7647a74fdf13"
}
methodis the authentication method of the attempt, for examplepassword,code,totp, oroidc.provideris the ID of the social sign-in provider. It's present only for theoidcmethod.identifieris the identifier that the user submitted, such as an email address. It's present only for thepassword,code, andidentifier_firstmethods, and for passwordless WebAuthn login.identity_idis the ID of the identity that Ory Kratos Identities matched to the attempt, andnullwhen the attempt wasn't matched to an identity. For a second factor, such as a TOTP code, it's the ID of the signed-in identity.
When ctx.failure.identity_id is set, ctx.identity is that identity, in the same format as in the after login web hooks. It
includes traits, metadata_public, external_id, and the identifiers of each credential, but no passwords, keys, or other
credential secrets, and no metadata_admin. When ctx.failure.identity_id is null, the context has no identity field. When a
social sign-in provider rejects the login, Ory Kratos Identities hasn't looked up an identity yet, so identity_id is null.
This template sends the identity's external ID, and falls back to the identity ID for identities without one:
function(ctx) {
method: ctx.failure.method,
identifier: std.get(ctx.failure, "identifier"),
user_id:
if std.objectHas(ctx, "identity") then
std.get(ctx.identity, "external_id", ctx.identity.id)
else
null,
}
ctx.flow.transient_payload is the transient_payload of the rejected request. For a social sign-in in the browser, it's the
transient_payload of the request that started the sign-in.
The context doesn't contain the password, code, token, or assertion that the user submitted. On a failed social sign-in callback,
ctx.request_url is the callback URL with its query parameters, including the authorization code and state. Every web hook
that runs on that request gets the same URL.
The failure trigger and the LoginFailed event in live event streams complement each other.
LoginFailed also covers failed login flows that this trigger skips, such as throttled or malformed attempts, but doesn't carry
the transient_payload. Use the failure trigger when your endpoint needs the transient_payload or the submitted identifier
for each rejected attempt.
Triggers based on authentication methods
You can further customize the behavior of the system by defining what action to trigger based on the authentication method used to sign in, register, and update user settings.
For example, when a user signs in with a password, you can use Ory Actions to send a welcome email to the user or update user information in your database. When a user signs in using OIDC, you can use Ory Actions to enrich your CRM with data from the social sign-in provider.
| Authentication method | Description |
|---|---|
password | Sign-in and sign-up with username/email and password combo. |
oidc | Sign-in and sign-up through OIDC-compliant OAuth2 identity providers. |
totp | MFA Sign-in with a TOTP code from apps such as Google Authenticator. |
webauthn | MFA Sign-in with WebAuthn-compatible factors (FaceID, YubiKey) or paswordless sign-up and sign-in. |
lookup_secret | MFA Sign-in with recovery codes. |
Available actions
There are 6 actions you can use to extend self-service user flows. The web_hook action allows you to trigger any custom,
external logic.
Some actions can only be used for specific flows and methods.
| Action | Description | Details |
|---|---|---|
session | Signs in the user immediately after they create an account. | For use only with the after registration flow. To use it, you must define secrets for secret rotation. |
revoke_active_sessions | Revokes all other active sessions of the user. | For use only with the after login flow, the after recovery flow, and the after settings flow for authentication methods such as password. |
require_verified_address | Allows users to sign in only when they verified their email address. | For use only with the after login flow, password method only. |
verify_new_address | Changes the user's address after they verify the new address. | For use only with the after settings flow, profile method only. |
notify_previous_addresses | Notifies the user's previous addresses when they change a verifiable address. | For use only with the after settings flow, profile method only. Accepts a recipients configuration. |
web_hook | Allows to trigger external and custom logic. Can be used with all flows and methods except error and logout. | Requires providing webhook configuration. It is the most common action type for the after settings flow. See an example of using webhooks here. |
Trigger precedence
The graph below shows when triggers happen.
- Ory executes the
beforeactions when the user starts a flow. - Ory executes the
afteractions when the user submits or completes the flow. - When an authentication method specifies actions, it overrides the default actions for the flow.
With the following configuration, hook_3 is executed when the user logs in with a password, hook_2 is executed when the user
logs in with any other method, for example through social sign-in, and hook_1 is executed for all login flows when the user
starts the flow.
selfservice:
flows:
login: # Defines for which flow triggers the action.
before: # When the user starts the flow
hooks:
- hook: hook_1 # Specifies which hook is triggered.
after: # When the user submits the flow
hooks:
- hook: hook_2 # is executed for all authentication methods except password
password:
hooks:
- hook: hook_3 # is executed only for password method
Actions in Ory OAuth2 & OpenID Connect
Read OAuth2 webhooks to learn more about Actions in Ory OAuth2 & OpenID Connect.