Keycloak Implement Reset password flow same as forgot password flow - keycloak

I am facing an issue with Keycloak:
When user clicks on Forget password button, he is asked to enter basic details. Once details are entered, the user receives a mail with link to change his password. User Changes his password, and is redirected to Login page of the application.
Users account gets locked. Admin uses application to unlock the account. User gets email, clicks on link, and generates new password. User now sees a message : Your account is successfully updated.
What I want to do is that the second flow should work in same way as the first one. i.e when user has given new password, he'd be redirected to login page.
Can someone guide me about how to proceed with this?
Difference I've noticed in two flows is the URL that I receive in both of them is different.
First flow, I get this in mail: http://[keycloak-host]/auth/realms/[realm]/login-actions/reset-credentials?code=[code]
Second flow, I get this URL: http://[keycloak-host]/auth/realms/[realm]/login-actions/execute-actions?key=[key]

Related

Can you send a link to the specific page where a user resets their password via Keycloak's API?

We have a PHP/MySQL based User Management System and are integrating it with Keycloak version 16 where we will store users credentials.
Our application does not allow users to self register. We create user accounts on the system. When we do this we do NOT specify a password because we want users to set up their own password.
The current system sends 2 separate emails in 2 different circumstances regarding passwords:
If it's a completely new user who does NOT have an existing password, we send them a link to set up a password.
If it's an existing user who already has a password, the system allows them to reset it, e.g. if they forget their password and can't login.
Keycloak seems to cater for scenario (2) because the login forms have a forgotten password link which opens a form where the user can enter their email address and receive a link which lets them do (2).
Unfortunately it doesn't deal with scenario (1) very well and that's where our problem starts. This has been asked a while ago Send password forgotten mail but it seems that Keycloak didn't support this very well in 2020 and perhaps still doesn't now.
Our "workaround" to this was that we added custom email templates and a custom page (reference: Themes on https://www.keycloak.org/docs/latest/server_development/#emails) which includes wording that caters for both scenarios, e.g. "set your password" rather than "reset your (existing) password". The result of this is that our email and form now reads appropriately for both scenarios (1) and (2).
The problem
We want to be able to send a link to the user that allows them to set their initial password to cover scenario (1).
We know that this page exists because on the login page for Keycloak there is a link to the forgotten password form that handles scenario (2). However, the form requires the user to enter their email address and submit the form. The user then receives an email from Keycloak which contains a URL to the page where they can do this. The URL has the following format:
https://example.com/auth/realms/foo/login-actions/action-token?key=...
The key= contains a ~945 character token. Going to the URL above redirects to the form where the user can reset their password. This next URL does not contain a token but a cookie has been set in the browser - by the previous URL - which makes it functional:
https://example.com/auth/realms/foo/login-actions/required-action?execution=UPDATE_PASSWORD
We can't send either of these URLs to the user because the first one (containing key=) has no API method for us to find out what it is - it's only possible to generate this by going through the "forgotten password" step during login, in the browser.
The second URL (/login-actions/required-action...) won't work either because it relies on the previous URL (containing key=) setting the cookie in the browser. If you try and go to this second URL directly (i.e. bypassing the first URL) it will error.
So neither of these URLs will work because we can't find what the first one is programmatically, and we can't use the second one without knowing the first one.
I found https://lists.jboss.org/pipermail/keycloak-user/2018-October/015910.html and the suggestion is using the Keycloak API to trigger a password reset email. This works - sending an HTTP PUT request containing 'UPDATE_PASSWORD' along with the relevant user ID sends the user an email. The request endpoint has the format PUT /{realm}/users/{id}/execute-actions-email which is documented on the link above.
Up to here all is fine - the user gets an email. However, this email does NOT contain a link that goes directly to the "reset password" page! Instead it sends them an email containing the following text:
Your administrator has just requested that you update your account by performing the following action(s): Update Password. Click on the link below to start this process.
Link to account update
When the user clicks "Link to account update" it then shows them a web page like this:
It is only when they click on the link on this page (the one that says "click here to proceed" on the screenshot) that they arrive at the form where they can reset their password.
This is a really poor user experience because the user gets sent a (badly worded) email with a link to... a page with another link! It should just take them to the password reset page directly. What's more frustrating is the fact that Keycloak is clearly capable of generating/sending the exact email we'd like in this scenario: the one which gets sent when a user manually does a password reset via their browser.
So the problem seems that Keycloak's API doesn't support this incredibly important and common use-case of a user being able to set an initial password, in a user-friendly manner.
I am adding the js script in the template to automatically click "click here to proceed". It's ugly but at least the user doesn't see the page

Keycloak Forgot password duplicate emails

Keycloak sends out duplicate emails when you hit Forgot password button right after user session expired and you want to login again.
It might be configuration issue with Keycloak but it is quite annoying so any help would be appreciated.
Keycloak client is set to public and used in combination javascript adapter on mobile app.
Steps to reproduce:
Login with your user account using public client.
Wait for your access token to expire and you will need to login again.
Go to login page and instead of login hit Forgot password button.
Enter your email and hit submit.
You get your first forgot password email.
You will be redirected to login-page-expired and on "click here" link.
You get your second password email (which shouldn't happen).
Used Keycloak version is 12.0.1.

Keycloak automatic login after email confirmation with disabled user

We're using keycloak (KC) with custom providers for the registration flow. At the end of the registration flow, before the confirmation email is sent to the user (as a default KC functionality), we disable the user as it fits our use case.
When user clicks on the email confirmation, mail is confirmed and user is automatically logged in, despite the fact he/she is disabled at that point. Logins after that work as expected (if user is disabled, login is forbidden, else it succeeds).
Upon reviewing Keycloak source, it seems as if session id is sent in the confirmation mail and if session already exists in KC, it is automatically reused and user proceeds as if logged in. If session doesn't exist, "email confirmed" page is shown and user is not logged in (as expected).
To confirm my theory of KC not checking user status (enabled/disabled) in the middle of an existing session, I've disabled a user that's currently been active in the application. User was not logged out or anything of the like.
My conclusion is that when user complets the registration, session exists and that session is then automatically "hijacked" upon clicking on the confirmation link. Nowhere in the middle of that, does KC check if user is actually enabled or not. Same as if you disable user while he/she is logged in and is browsing the protected application.
Does anyone have any workaround of the issue? My next step is somehow to programatically invalidate session at the end of the registration, so user won't have any when clicking on the confirmation mail. I am not sure how to track this bug on KC jira either, since they don't seem to have any public bug tracker. Regardless, this is not the point of this question - my question is if anyone else already had this problem and if yes, how was it solved?
I have solved a similar issue writing a custom Required Action. The required action is triggered after email validation, so you can check if user is enabled or not (Secret question required action example).
In my case if user validation is not ok, I redirect to error page:
Response challenge =
context.form().setError(MessagesIDs.NOT_VALIDATED_ID).createErrorPage(Status.UNAUTHORIZED);
context.challenge(challenge);
return;

SigninwithIntuit with multiple user of the same QuickBook Company

I've successfully Integrated my application with QuickBook Online. I successfully implemented DirectConnectToIntuit, SigninWithIntuit, Disconnect scenario and Test according to https://developer.intuit.com/docs/#api/deki/files/3143/recipe_for_review_success.pdf. I have a situation with DirectConnectToIntuit, SigninWithIntuit for multiple user. Consider the SigninWithIntuit scenerio:
When a first user comes, they click SigninWithIntuit in my application, add their username and password, authorize by Intuit and comeback in my site. As the user is new and his email address is not in my database, I show him the account creation form. When this user submits the form after filling it in then I the create database entry, create the user etc, then login and show ConnectToQuickBook button(G. in the above doc). Everything is OK up to now.
When another user is created in the same QuickBooks online company, then this new user clicks on SignInWithIntuit in my application, and they come back to my app after authorization. For this user, I will not show the account Creation form, I just create this new user and assign as a user of the previous created company, login and show the ConnectToIntuit button. But how can I determine the company of the user? I don't have an access token or access token secret yet to do that.
It is answered here (Intuit's live community) -
https://intuitdeveloper.lc.intuit.com/questions/1188167-signinwithintuit-with-multiple-user-of-the-same-quickbook-company?jump_to=answer_2643393

What is a secure and efficient method for website users to reset their password?

Many sites implement different methods and I am having a hard time deciding on which method would work best for my site.
My user profiles contain the following data:
username
password (in hash/digest form)
email
I'd like the password reset method to be secure, user-friendly, and efficient.
You should add two fields, reset_code and reset_expiry
This is the process for a secure password reset functionality.
User selects "Forgot password".
User prompted for email/username.
If valid, generates a GUID, and stores it in reset_code and also stores Now()+24 hours in reset_expiry in the database against that particular user.
Then it sends an email to the email address with a link to confirm the password reset. This email would contain a link to your website with the user's username AND reset_code embedded. (This stops a malicious user resetting a third parties password just by knowing their email)
Once the user clicks on the link in the email, they will be directed to your website.
Your website will validate that: the username and reset_code matches, and the current time hasn't exceeded the reset_expiry time.
If all is okay, we can complete the password reset. This can be done by either:
a) Onscreen a new randomly generated password
b) A new randomly generated password via email
c) The ability to enter a password of his/her own choosing
You should not store the passwords of your users, not even in encrypted form. You should only store the hash/digest necessary for authentication. Then, you can't "recover" the password (because you don't know it), you can just reset it, and/or give the user a temporary one-time password that allows him to set a new password.
Update: if you are doing the above, the standard procedure is to have a "require-password-reset" form. The user enters his id (typically his email) and a "token" (eg, a random string) is generated, stored in some table with some expiration date, and sent to his email along with a link to the "password-reset" form. In this form the token is checked, the user is allowed to enter a new password, and instructed to attempt a new login.
Update 2: A small privacy issue might arise: What should we do if the user id (email, user name, or whatever) entered in the request form does not exist in our database? To output a message "User does not exist. Check the id and retry." may be ok, but in some cases it would cause a privacy problem: anyone can check if other someone is registered in your database! If you want to avoid that, you must output the same message ("a mail has been sent with instructions...") even if the user wasnt found (and hence a mail was not actually sent).
Similar privacy issues advise to just output the message "login incorrect : bad user or password" when the user tries to login unsuccessfully - don't disclose if it was an incorrect user or password.
I agree with Leonbloy. Storing the password leads to trouble like the Gawker incident from a few weeks ago (1.5 million userid/pwd combinations were discovered and published).
You should, however, have a "reset password" function that e-mails the new password to the original e-mail address used to open the account.
There should be no provision for changing the e-mail address during the password reset. If the user doesn't have access to the old e-mail account anymore, too bad. Abandon the account and start over.
And use a good Captcha on the reset screen.