diff --git a/docs/docs/guides/integrate/login-ui/password-reset.mdx b/docs/docs/guides/integrate/login-ui/password-reset.mdx new file mode 100644 index 000000000..b77530e32 --- /dev/null +++ b/docs/docs/guides/integrate/login-ui/password-reset.mdx @@ -0,0 +1,106 @@ +--- +title: Password Reset/Change +--- + +When your user is on the password screen and has forgotten his password you will probably want him to be able to reset by himself. + +## Flow + +![Register and Login Flow](/img/guides/login-ui/password-reset-flow.png) + +## Request Password Reset + +First you will have to make a request, to ask for a password reset. +The goal is to send the user a verification code, which he can use to verify the password reset request. + +There are two possible ways: You can either let ZITADEL send the notification with the verification code, or you can ask ZITADEL for returning the code and send the email by yourself. + +### ZITADEL sends the verification message + +When you want ZITADEL to send the verification code you can define the notification channel. +Per default the verification code will be sent to the email address of the user. + +Make sure to also include the URL Template to customize the reset link in the email sent to the user. + + +### Request + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/password_reset \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"'' \ + --header 'Content-Type: application/json' \ + --data '{ + "sendLink": { + "notificationType": "NOTIFICATION_TYPE_Email", + "urlTemplate": "https://example.com/password/changey?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}" + } + }' +``` + +### ZITADEL returns the code + +Send the request with asking for the return Code in the body of the request. + +#### Request +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/password_reset \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"'' \ + --header 'Content-Type: application/json' \ + --data '{ + "returnCode": {} +}' +``` + +#### Response + +You will get the verification code in the response: +```bash +{ + "details": { + "sequence": "625", + "changeDate": "2023-06-27T15:02:10.321773Z", + "resourceOwner": "163840776835432705" + }, + "verificationCode": "IBJMUC" +} +``` + +## Send Verification Code + +The verification code is generated and ZITADEL has sent it with the defined channel (email or sms) to your users. +If you have chosen to get the code back in the response, you should now send the code to your user. + +## Change Password + +The next screen should allow the user to enter the verification code and a new password. +From a user experience perspective it is nice to prefill the verification code, so the user doesn't have to do manually. + +As soon as the user has typed the new password, you can send the change password request. +The change password request allows you to set a new password for the user. + +:::note +This request can be used in the password reset flow as well as to let your user change the password manually. +In this case it requires additionally the current password instead of the verification code. +::: + + +### Request + +```bash +curl --request POST \ + --url https://$ZITADEL_DOMAIN/v2alpha/users/$USER_ID/password \ + --header 'Accept: application/json' \ + --header 'Authorization: Bearer '"$TOKEN"'' \ + --header 'Content-Type: application/json' \ + --data '{ + "newPassword": { + "password": "Secr3tP4ssw0rd!", + "changeRequired": false + }, + "verificationCode": "48CDAP" +}' +``` \ No newline at end of file diff --git a/docs/docs/guides/integrate/login-ui/username-password.mdx b/docs/docs/guides/integrate/login-ui/username-password.mdx index 393aacaf0..95f68d174 100644 --- a/docs/docs/guides/integrate/login-ui/username-password.mdx +++ b/docs/docs/guides/integrate/login-ui/username-password.mdx @@ -10,7 +10,7 @@ sidebar_label: Username and Password ## Register First, we create a new user with a username and password. In the example below we add a user with profile data, a verified email address, and a password. -[Create User Documentation](https://zitadel.com/docs/apis/resources/user_service/user-service-add-human-user) +[Create User Documentation](/apis/resources/user_service/user-service-add-human-user) ### Request diff --git a/docs/sidebars.js b/docs/sidebars.js index 755a57085..e19c81f8d 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -183,6 +183,7 @@ module.exports = { "guides/integrate/login-ui/username-password", "guides/integrate/login-ui/external-login", "guides/integrate/login-ui/select-account", + "guides/integrate/login-ui/password-reset", "guides/integrate/login-ui/logout", "guides/integrate/login-ui/oidc-standard" ], diff --git a/docs/static/img/guides/login-ui/password-reset-flow.png b/docs/static/img/guides/login-ui/password-reset-flow.png new file mode 100644 index 000000000..56e7f8eff Binary files /dev/null and b/docs/static/img/guides/login-ui/password-reset-flow.png differ diff --git a/proto/zitadel/user/v2alpha/user_service.proto b/proto/zitadel/user/v2alpha/user_service.proto index 1534a4d74..50562bcf5 100644 --- a/proto/zitadel/user/v2alpha/user_service.proto +++ b/proto/zitadel/user/v2alpha/user_service.proto @@ -430,8 +430,8 @@ service UserService { }; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - summary: "Request a code to reset a password"; - description: "Request a code to reset a password"; + summary: "Change password"; + description: "Change the password of a user with either a verification code or the current password."; responses: { key: "200" value: { @@ -574,7 +574,7 @@ message RegisterPasskeyRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; optional PasskeyRegistrationCode code = 2 [ @@ -598,7 +598,7 @@ message RegisterPasskeyResponse{ zitadel.object.v2alpha.Details details = 1; string passkey_id = 2 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"fabde5c8-c13f-481d-a90b-5e59a001a076\"" + example: "\"163840776835432705\"" } ]; google.protobuf.Struct public_key_credential_creation_options = 3 [ @@ -616,7 +616,7 @@ message VerifyPasskeyRegistrationRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string passkey_id = 2 [ @@ -625,7 +625,7 @@ message VerifyPasskeyRegistrationRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"fabde5c8-c13f-481d-a90b-5e59a001a076\""; + example: "\"163840776835432705\""; } ]; google.protobuf.Struct public_key_credential = 3 [ @@ -660,7 +660,7 @@ message RegisterU2FRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string domain = 2 [ @@ -674,7 +674,7 @@ message RegisterU2FResponse{ zitadel.object.v2alpha.Details details = 1; string u2f_id = 2 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - example: "\"fabde5c8-c13f-481d-a90b-5e59a001a076\"" + example: "\"163840776835432705\"" } ]; google.protobuf.Struct public_key_credential_creation_options = 3 [ @@ -692,7 +692,7 @@ message VerifyU2FRegistrationRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string u2f_id = 2 [ @@ -701,7 +701,7 @@ message VerifyU2FRegistrationRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"fabde5c8-c13f-481d-a90b-5e59a001a076\""; + example: "\"163840776835432705\""; } ]; google.protobuf.Struct public_key_credential = 3 [ @@ -736,7 +736,7 @@ message RegisterTOTPRequest { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; } @@ -762,7 +762,7 @@ message VerifyTOTPRegistrationRequest { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string code = 2 [ @@ -786,7 +786,7 @@ message CreatePasskeyRegistrationLinkRequest{ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; // if no medium is specified, an email is sent with the default url @@ -813,7 +813,7 @@ message StartIdentityProviderFlowRequest{ description: "ID for existing identity provider" min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string success_url = 2 [ @@ -855,7 +855,7 @@ message RetrieveIdentityProviderInformationRequest{ description: "ID of the intent, previously returned on the success response of the IDP callback" min_length: 1; max_length: 200; - example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; + example: "\"163840776835432705\""; } ]; string token = 2 [