v1.25.0
logto-io/logtov1.25.0Feb 28, 2025by silverhand-bot
AI Summary
Enabled custom email templates in multiple languages, introduced new context variables, and added legacy password hashing support.
Key Highlights
- Multi-language email templates via Management API
- New context variables (user, application, organization, inviter) for templates
- Legacy password hashing support (JSON format) for custom algorithms
- TOTP secret length adjusted to 20 bytes (standard compliance)
New Features
- Multi-language email templates
- Email context variables
- Legacy password hashing
- TOTP standardization
Full Release Notes

## Support custom email templates in multiple languages via Management API
Introduce localized email template customization capabilities. This update allows administrators to create and manage multiple email templates for different languages and template types (e.g., SignIn, ForgotPassword) via the management API.
Email connectors now support automatic template selection based on the user's preferred language. If a template is not available in the user's preferred language, the default template will be used.
- For client-side API requests, like experience API and user account API, the user's preferred language is determined by the `Accept-Language` header.
- For server-side API requests, like organization invitation API, email language preference can be set by passing extra `locale` parameter in the `messagePayload`.
- The email template selection logic is based on the following priority order:
1. Find the template that matches the user's preferred language detected from the request.
2. Find the template that matches the default language set in the sign-in experience settings.
3. Use the default template set in the email connector settings.
### Management API
- `PUT /email-templates`: Bulk create or update email templates.
- `GET /email-templates`: List all email templates with filter by language and type support.
- `DELETE /email-templates`: Bulk delete email templates by language and type.
- `GET /email-templates/{id}`: Get a specific email template by ID.
- `DELETE /email-templates/{id}`: Delete a specific email template by ID.
- `PATCH /email-templates/{id}/details`: Update email template details by ID.
### Supported email connectors
- `@logto/connector-aliyun-dm`
- `@logto/connector-aws-ses`
- `@logto/connector-mailgun`
- `@logto/connector-sendgrid-email`
- `@logto/connector-smtp`
### Unsupported email connectors
The following email connectors have their templates managed at the provider side and do not support reading templates from Logto.
The user's preferred language will be passed to the provider as the `locale` parameter in the email sending request payload. For i18n support, administrators must manage the template selection logic at the provider side.
- `@logto/connector-postmark`
- `@logto/connector-http-email`
## Pass additional context variables to email templates
Enhanced email template customization by introducing additional context variables that developers can utilize in message templates. These new variables provide deeper contextual information about the authentication workflow, enabling more personalized and scenario-specific email content.
- `user`: `UserInfo` - Contains basic user profile data (name, primaryEmail, etc.) for personalization
- `application`: `ApplicationInfo` - Contains basic application-specific data (name, logo, etc.) for personalization
- `organization`: `OrganizationInfo` - Contains basic organization-specific data (name, logo, etc.) for personalization
- `inviter`: `UserInfo` - Contains basic inviter profile data (name, primaryEmail, etc.) for personalization
| usageType | Scenario | Variables |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| SignIn | Users sign in using their email and verify by entering verification code instead of entering a password. | code: string<br/>application: `ApplicationInfo`<br/>organization?: `OrganizationInfo` |
| Register | Users create an account using their email and verify it by entering a verification code sent by Logto to their email. | code: string<br/>application: `ApplicationInfo`<br/>organization?: `OrganizationInfo` |
| ForgotPassword | If users forget their password during login, they can choose to verify their identity using the email they've already verified with Logto. | code: string<br/>application: `ApplicationInfo`<br/>organization?: `OrganizationInfo` |
| Generic | This template can be used as a general backup option for various scenarios, including testing connector configurations and so on. | code: string |
| OrganizationInvitation | Use this template to send users an invitation link to join the organization. | link: string<br/>organization: `OrganizationInfo`<br/>inviter?: `UserInfo` |
| UserPermissionValidation | During app usage, there may be some high-risk operations or operations with a relatively high risk level that require additional user verification, such as bank transfers, deleting resources in use, and canceling memberships. The `UserPermissionValidation` template can be used to define the content of the email verification code users receive in these situations. | code: string<br/>user: `UserInfo`<br/>application?: `ApplicationInfo` |
| BindNewIdentifier | When a user modifies their profile, they may bind an email address to their current account. In this case, the `BindNewIdentifier` template can be used to customize the content of the verification email. | code: string<br/>user: `UserInfo`<br/>application?: `ApplicationInfo` |
Check [Email templates](https://docs.logto.io/connectors/email-connectors/email-templates) for more information on how to use these new context variables in your email templates.
## Improvements
- [1c7bdf9ba](https://github.com/logto-io/logto/commit/1c7bdf9ba53ab795e6ccb3e99a60b7be39d4f8d4): add legacy password type supporting custom hasing function, credits @fre2d0m
You can now set the type of `password_encryption_method` to `legacy`, and store info with a JSON string format (containing a hash algorithm, arguments, and an encrypted password) in the `password_encrypted` field. By doing this, you can use any hash algorithm supported by Node.js, this is useful when migrating from other password hash algorithms, especially for the ones that include salt.
The format of the JSON string is as follows:
```json
["hash_algorithm", ["argument1", "argument2", ...], "expected_hashed_value"]
```
And you can use `@` as the input password in the arguments.
For example, if you are using SHA256 with a salt, you can store the password in the following format:
```json
[
"sha256",
["salt123", "@"],
"c465f66c6ac481a7a17e9ed5b4e2e7e7288d892f12bf1c95c140901e9a70436e"
]
```
Then when the user uses the password (`password123`), the `legacyVerify` function will use the `sha256` algorithm with the `salt123` and the input password to verify the password.
In this case, `salt123` is the first argument, `@` is the input password, then the following code will be executed:
```ts
const hash = crypto.createHash("sha256");
hash.update("salt123" + "password123");
const expectedHashedValue = hash.digest("hex");
```
- [b0135bcd3](https://github.com/logto-io/logto/commit/b0135bcd3c7385245ec3edc000ede8470b82b006): enhanced handlebars template processing in the connector to support nested property access in email template variables
### Updates
- Updated `replaceSendMessageHandlebars` logic to handle nested property paths in template variables
- Latest template processing logic now supports:
- Direct replacement of primitive values (string/number/null/undefined)
- Deep property access using dot-notation (e.g., `organization.branding.logoUrl`)
- Graceful handling of missing properties (replaces with empty string)
- Preservation of original handlebars when variables aren't provided in payload
### Examples
1. Direct replacement
```ts
replaceSendMessageKeysWithPayload("Your verification code is {{code}}", {
code: "123456",
});
// 'Your verification code is 123456'
```
2. Deep property access
```ts
replaceSendMessageKeysWithPayload(
"Your logo is {{organization.branding.logoUrl}}",
{ organization: { branding: { logoUrl: "https://example.com/logo.png" } } }
);
// 'Your logo is https://example.com/logo.png'
```
3. Missing properties
```ts
replaceSendMessageKeysWithPayload(
"Your logo is {{organization.branding.logoUrl}}",
{ organization: { name: "foo" } }
);
// 'Your logo is '
```
4. Preservation of missing variables
```ts
replaceSendMessageKeysWithPayload(
"Your application is {{application.name}}",
{}
);
// 'Your application is {{application.name}}'
```
- [c87424025](https://github.com/logto-io/logto/commit/c874240258a36c6c46b690e2bce98cbd71265e85): support role names alongside role IDs in organization user role assignment/replacement with merge capability
This update enhances organization user role management APIs to support role assignment by both names and IDs, improving integration flexibility.
- Added `organizationRoleNames` parameter to:
- POST `/api/organizations/{id}/users/{userId}/roles` (assign roles)
- PUT `/api/organizations/{id}/users/{userId}/roles` (replace roles)
- Make both `organizationRoleNames` and `organizationRoleIds` optional in the above APIs
- If both are not provided, or empty, an invalid data error will be thrown
- Merge logic when both parameters are provided:
- Combines roles from `organizationRoleNames` and `organizationRoleIds`
- Automatically deduplicates entries
- Validates all names/IDs exist before applying changes
- Maintains backward compatibility with existing integrations using role IDs
## Fixes
- [edeb7cc8d](https://github.com/logto-io/logto/commit/edeb7cc8daabfbedb968513485d531f0a7a6c60d): add `AuthnStatement` to SAML app assertion response
- [b2a77d79c](https://github.com/logto-io/logto/commit/b2a77d79c1c9c56c1320c4954dd5099420605bb1): add `strictPhoneRegionNumberCheck` to config with default value `false`
When this configuration is enabled, the connector will assume by default that all phone numbers include a valid region code and rely on this to determine whether the phone number belongs to mainland China. If your users' phone numbers do not include a region code due to historical reasons, their sign-in processes may be affected. Please enable this setting with caution.
- [20b61e05e](https://github.com/logto-io/logto/commit/20b61e05e7c5b0e3f4ec7ed67bfff85a9845185d): adjust TOTP secret length to 20 bytes
Update the TOTP secret generation to use 20 bytes (160 bits), following the recommendation in RFC 6238 (TOTP) and RFC 4226 (HOTP).
This aligns with the standard secret length used by most 2FA applications and provides better security while maintaining compatibility with existing TOTP validators.
Reference:
- RFC 6238 (TOTP) Section 5.1: https://www.rfc-editor.org/rfc/rfc6238#section-5.1
- RFC 4226 (HOTP) Section 4, Requirement 6: https://www.rfc-editor.org/rfc/rfc4226#section-4
- [f15602f19](https://github.com/logto-io/logto/commit/f15602f198f0dce049fec887ae6315a752263466): incorrect pagination behavior in organization role scopes APIs
- Fix `/api/organization-roles/{id}/scopes` and `/api/organization-roles/{id}/resource-scopes` endpoints to:
- Return all scopes when no pagination parameters are provided
- Support optional pagination when query parameters are present
- Fix Console to properly display all organization role scopes on the organization template page