fix: pass sessionID to OTP email link (#8745)

# Which Problems Are Solved

OTP Email links currently could not use / include the sessionID they
belong to. This prevents an easy use for redirecting and handling OTP
via email through the session API.

# How the Problems Are Solved

Added the sessionID as placeholder for the OTP Email link template.

# Additional Changes

List all available placeholders in the url_templates of V2 endpoints.

# Additional Context

- discussed in a customer meeting
This commit is contained in:
Livio Spring 2024-10-10 15:53:32 +02:00 committed by GitHub
parent 222915ca3d
commit 16171ce3b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 23 additions and 7 deletions

View File

@ -61,7 +61,7 @@ func (c *Commands) OTPSMSSent(ctx context.Context, sessionID, resourceOwner stri
}
func (c *Commands) CreateOTPEmailChallengeURLTemplate(urlTmpl string) (SessionCommand, error) {
if err := domain.RenderOTPEmailURLTemplate(io.Discard, urlTmpl, "code", "userID", "loginName", "displayName", language.English); err != nil {
if err := domain.RenderOTPEmailURLTemplate(io.Discard, urlTmpl, "code", "userID", "loginName", "displayName", "sessionID", language.English); err != nil {
return nil, err
}
return c.createOTPEmailChallenge(false, urlTmpl, nil), nil

View File

@ -20,16 +20,18 @@ type OTPEmailURLData struct {
LoginName string
DisplayName string
PreferredLanguage language.Tag
SessionID string
}
// RenderOTPEmailURLTemplate parses and renders tmpl.
// code, userID, (preferred) loginName, displayName and preferredLanguage are passed into the [OTPEmailURLData].
func RenderOTPEmailURLTemplate(w io.Writer, tmpl, code, userID, loginName, displayName string, preferredLanguage language.Tag) error {
func RenderOTPEmailURLTemplate(w io.Writer, tmpl, code, userID, loginName, displayName, sessionID string, preferredLanguage language.Tag) error {
return renderURLTemplate(w, tmpl, &OTPEmailURLData{
Code: code,
UserID: userID,
LoginName: loginName,
DisplayName: displayName,
PreferredLanguage: preferredLanguage,
SessionID: sessionID,
})
}

View File

@ -442,7 +442,7 @@ func (u *userNotifier) reduceSessionOTPEmailChallenged(event eventstore.Event) (
if e.URLTmpl != "" {
urlTmpl = e.URLTmpl
}
if err := domain.RenderOTPEmailURLTemplate(&buf, urlTmpl, code, user.ID, user.PreferredLoginName, user.DisplayName, user.PreferredLanguage); err != nil {
if err := domain.RenderOTPEmailURLTemplate(&buf, urlTmpl, code, user.ID, user.PreferredLoginName, user.DisplayName, e.Aggregate().ID, user.PreferredLanguage); err != nil {
return "", err
}
return buf.String(), nil

View File

@ -42,13 +42,16 @@ message RequestChallenges {
}
message OTPEmail {
message SendCode {
// Optionally set a url_template, which will be used in the mail sent by ZITADEL to guide the user to your verification page.
// If no template is set, the default ZITADEL url will be used.
//
// The following placeholders can be used: Code, UserID, LoginName, DisplayName, PreferredLanguage, SessionID
optional string url_template = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"https://example.com/otp/verify?userID={{.UserID}}&code={{.Code}}\"";
description: "\"Optionally set a url_template, which will be used in the mail sent by ZITADEL to guide the user to your verification page. If no template is set, the default ZITADEL url will be used.\""
}
];
}

View File

@ -15,13 +15,16 @@ enum PasskeyAuthenticator {
}
message SendPasskeyRegistrationLink {
// Optionally set a url_template, which will be used in the mail sent by ZITADEL to guide the user to your passkey registration page.
// If no template is set, the default ZITADEL url will be used.
//
// The following placeholders can be used: UserID, OrgID, CodeID, Code
optional string url_template = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"https://example.com/passkey/register?userID={{.UserID}}&orgID={{.OrgID}}&codeID={{.CodeID}}&code={{.Code}}\"";
description: "\"Optionally set a url_template, which will be used in the mail sent by ZITADEL to guide the user to your passkey registration page. If no template is set, the default ZITADEL url will be used.\""
}
];
}

View File

@ -39,13 +39,16 @@ message HumanEmail {
}
message SendEmailVerificationCode {
// Optionally set a url_template, which will be used in the verification mail sent by ZITADEL to guide the user to your verification page.
// If no template is set, the default ZITADEL url will be used.
//
// The following placeholders can be used: UserID, OrgID, Code
optional string url_template = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"https://example.com/email/verify?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}\"";
description: "\"Optionally set a url_template, which will be used in the verification mail sent by ZITADEL to guide the user to your verification page. If no template is set, the default ZITADEL url will be used.\""
}
];
}

View File

@ -37,13 +37,16 @@ message HashedPassword {
message SendPasswordResetLink {
NotificationType notification_type = 1;
// Optionally set a url_template, which will be used in the password reset mail sent by ZITADEL to guide the user to your password change page.
// If no template is set, the default ZITADEL url will be used.
//
// The following placeholders can be used: UserID, OrgID, Code
optional string url_template = 2 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"https://example.com/password/changey?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}\"";
description: "\"Optionally set a url_template, which will be used in the password reset mail sent by ZITADEL to guide the user to your password change page. If no template is set, the default ZITADEL url will be used.\""
}
];
}

View File

@ -286,6 +286,8 @@ enum AuthFactorState {
message SendInviteCode {
// Optionally set a url_template, which will be used in the invite mail sent by ZITADEL to guide the user to your invitation page.
// If no template is set, the default ZITADEL url will be used.
//
// The following placeholders can be used: UserID, OrgID, Code
optional string url_template = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {