From edb75cd61e992b3cd259e8ce5f40f2ba1a854011 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Thu, 9 Jul 2026 13:08:15 +0200 Subject: [PATCH 1/2] docs: document oauth2_login_request in courier template data Kratos now includes a scoped oauth2_login_request object (challenge and the client's client_id, client_name, client_uri, logo_uri, metadata) in the login_code_valid, registration_code_valid, verification_code_valid, and verification_valid template data when the flow was started through an OAuth2 login challenge. Documents the Go template variable and the HTTP courier template_data field. See https://github.com/ory-corp/cloud/pull/12776. Co-Authored-By: Claude Fable 5 --- .../emails-sms/05_custom-email-templates.mdx | 17 +++++++++++ .../self-hosted/03_mail-courier-http.mdx | 29 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/docs/kratos/emails-sms/05_custom-email-templates.mdx b/docs/kratos/emails-sms/05_custom-email-templates.mdx index fde79541e8..3c08f3bc01 100644 --- a/docs/kratos/emails-sms/05_custom-email-templates.mdx +++ b/docs/kratos/emails-sms/05_custom-email-templates.mdx @@ -265,6 +265,23 @@ In addition to the variables listed for each template, every template can access [Transient payload in templates](#transient-payload-in-templates)) and `RequestURL` (the URL of the flow request that triggered the email). +The `login_code.valid`, `registration_code.valid`, `verification_code.valid`, and `verification.valid` templates can also access +`OAuth2LoginRequest` when the flow was started through an OAuth2 login challenge, for example when a user signs in to an OAuth2 +client. Because Ory resolves this value server-side, it can't be forged by the end user. Use it to brand messages per OAuth2 +client instead of the end-user-controlled transient payload: + +| Variable | Description | +| ------------------------------------ | ------------------------------------------------- | +| `OAuth2LoginRequest.Challenge` | the OAuth2 login challenge that started the flow | +| `OAuth2LoginRequest.Client.ClientID` | the OAuth2 client ID | +| `OAuth2LoginRequest.Client.ClientName` | the human-readable name of the OAuth2 client | +| `OAuth2LoginRequest.Client.ClientURI` | the URL of the OAuth2 client's homepage | +| `OAuth2LoginRequest.Client.LogoURI` | the URL of the OAuth2 client's logo | +| `OAuth2LoginRequest.Client.Metadata` | the metadata set on the OAuth2 client | + +For example: `{{ if .OAuth2LoginRequest }}{{ .OAuth2LoginRequest.Client.ClientName }}{{ end }}`. The variable is unset when the +flow wasn't started through an OAuth2 login challenge. + ```mdx-code-block diff --git a/docs/kratos/self-hosted/03_mail-courier-http.mdx b/docs/kratos/self-hosted/03_mail-courier-http.mdx index 006e501a01..57e7ae511a 100644 --- a/docs/kratos/self-hosted/03_mail-courier-http.mdx +++ b/docs/kratos/self-hosted/03_mail-courier-http.mdx @@ -64,12 +64,41 @@ available through a `ctx` object. `recipient` will always be the email address o - to - verification_url - identity + - oauth2_login_request (optional) - verification_code_invalid - to - verification_code_valid - to - verification_code - identity + - oauth2_login_request (optional) +- login_code_valid + - to + - login_code + - identity + - oauth2_login_request (optional) +- registration_code_valid + - to + - registration_code + - traits + - oauth2_login_request (optional) + +The `oauth2_login_request` field is only present when the flow was started through an OAuth2 login challenge, for example when a +user signs in to an OAuth2 client. Because Ory resolves it server-side, it can't be forged by the end user. Use it to brand +messages per OAuth2 client: + +```json +"oauth2_login_request": { + "challenge": "...", + "client": { + "client_id": "...", + "client_name": "...", + "client_uri": "...", + "logo_uri": "...", + "metadata": {} + } +} +``` A universal Jsonnet template that works with all flows, would look like this: From 75af697c9e42382aab21617f40dcce887fc8056b Mon Sep 17 00:00:00 2001 From: vinckr Date: Mon, 13 Jul 2026 14:01:42 +0200 Subject: [PATCH 2/2] chore: format --- .../emails-sms/05_custom-email-templates.mdx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/kratos/emails-sms/05_custom-email-templates.mdx b/docs/kratos/emails-sms/05_custom-email-templates.mdx index 3c08f3bc01..c063578346 100644 --- a/docs/kratos/emails-sms/05_custom-email-templates.mdx +++ b/docs/kratos/emails-sms/05_custom-email-templates.mdx @@ -270,14 +270,14 @@ The `login_code.valid`, `registration_code.valid`, `verification_code.valid`, an client. Because Ory resolves this value server-side, it can't be forged by the end user. Use it to brand messages per OAuth2 client instead of the end-user-controlled transient payload: -| Variable | Description | -| ------------------------------------ | ------------------------------------------------- | -| `OAuth2LoginRequest.Challenge` | the OAuth2 login challenge that started the flow | -| `OAuth2LoginRequest.Client.ClientID` | the OAuth2 client ID | -| `OAuth2LoginRequest.Client.ClientName` | the human-readable name of the OAuth2 client | -| `OAuth2LoginRequest.Client.ClientURI` | the URL of the OAuth2 client's homepage | -| `OAuth2LoginRequest.Client.LogoURI` | the URL of the OAuth2 client's logo | -| `OAuth2LoginRequest.Client.Metadata` | the metadata set on the OAuth2 client | +| Variable | Description | +| -------------------------------------- | ------------------------------------------------ | +| `OAuth2LoginRequest.Challenge` | the OAuth2 login challenge that started the flow | +| `OAuth2LoginRequest.Client.ClientID` | the OAuth2 client ID | +| `OAuth2LoginRequest.Client.ClientName` | the human-readable name of the OAuth2 client | +| `OAuth2LoginRequest.Client.ClientURI` | the URL of the OAuth2 client's homepage | +| `OAuth2LoginRequest.Client.LogoURI` | the URL of the OAuth2 client's logo | +| `OAuth2LoginRequest.Client.Metadata` | the metadata set on the OAuth2 client | For example: `{{ if .OAuth2LoginRequest }}{{ .OAuth2LoginRequest.Client.ClientName }}{{ end }}`. The variable is unset when the flow wasn't started through an OAuth2 login challenge.