The ideal behavior IMO is:
1. Back button always just shows the Page expired message, with option to
continue or restart
2. Refresh always works
3. No redirect required on POSTs
My fear is how to explain "restart" action (on Expired page) to the
common user to understand it. Login flows are typically part of some
broader user flows started in the client app, users typically do not
perceive them as separate thing.
Also where exactly the user will be pointed after "restart"? Eg. what
"restart" mean when user went over registration form (initiated for
either /register OIDC endpoind or "Register" button of Login page)? Does
this mean that he lost everything he entered into registration form?
This may be really painful for more complicated reg. forms (eg. the one
we have for RHD) if user only used back button to correct something
entered into Reg form.
Other example of one flow one of our users really used:
1. User came to login page from some app
2. Used social login link (eg. Github)
3. Social account was not linked so he got a form to fill in other info
necessary to create new account
4. User used back button to get back to our login page, then used
"Register" button there. He got some error (I'm not sure in which
version of Keycloak, maybe it is resolved now, but we do not want
regression).
How will this work in the behavior you proposed? I believe this kind of
cases (switch between "login" and "register" types of flow) should
work
correctly and show usable Register form without any error page/message
in this case.
If we can't have all 3 (and it sounds like we can't) I'd
probably say #3 is
the lowest priority.
Agree, but there must be maximally one browser redirect after POST (we
complained when one historical implementation used more redirects after
one POST) due to user response time.
Vl.
I think the option to "restart" the flow is important
as the user in most cases would click back because they've done something
wrong.
So what Bill suggested would work I think:
* Have "Cache-Control: no-store, must-revalidate, max-age=0"
* I guess we need the redirect after a POST to get for the next step
* Have the execution ID in the flow as well as the current execution in the
authentication session. If requested execution ID is not equal to the one
in authentication session display the "Page expired page"
What I don't quite get though is why does the redirect after POST prevent
the "form is expired do you want to resubmit" or whatever the message is?
On 17 March 2017 at 15:08, Stian Thorgersen <sthorger(a)redhat.com> wrote:
>
> On 17 March 2017 at 11:12, Marek Posolda <mposolda(a)redhat.com> wrote:
>
>> On 17/03/17 09:40, Stian Thorgersen wrote:
>>
>>
>>
>> On 17 March 2017 at 09:22, Marek Posolda <mposolda(a)redhat.com> wrote:
>>
>>> Ok, for now just ignoring the browser limitations and fact that
>>> back/forward doesn't refresh the page automatically for POST requests :)
>>>
>>> On 17/03/17 08:45, Stian Thorgersen wrote:
>>>
>>> I repeat:
>>>
>>> Before we discuss implementation though, let's figure out what the ideal
>>> user experience would be then figure out how to implement it. What about:
>>>
>>> * Refresh just works
>>>
>>> * Back button will display a nicer page, something like "Page has
>>> expired. To restart the login process click here. To continue the login
>>> process click here.".
>>>
>>>
>>> Yeah, that will be nice for UXP.
>>>
>>> Or Back button could just go to the start of the flow always.
>>>
>>>
>>> Regarding UXP, I personally like your previous proposal better. If user
>>> is deep after confirm many authenticator forms and he accidentally
>>> clicks back-button, he will need to re-authenticate in all
>>> authenticators again. Not so great for usability though?
>>>
>>>
>> True - giving the user the option to choose is probably best.
>>
>>
>>> * Resubmitting forms will just display the page above
>>>
>>> If we do any of your previous proposal, user will never see the forms,
>>>
>>> which he already submitted? For example if he submitted
>>> username/password and now is on TOTP page, then after click "back"
he will be
>>> either on the "Page has expired" or start of the flow. The start of
the flow usually
>>> will be username/password form, but flow started from scratch, so it
>>> won't be resubmitting form, but new submit?
>>>
>>> Anyway yes, if some of previous forms is re-submitted, we can display
"page is expired" page.
>>>
>>> I'm not quite following. Is it possible to prevent the back buttons from
>> "re-submitting" forms at all? If so that's ideal as you then
don't get the
>> ugly message from the browser that the form is expired.
>>
>> Yes, as long as we don't send any "Cache-control" header, then
browser
>> back/forward buttons doesn't resubmit forms and doesn't re-send any
>> requests.
>>
>> So follow-up on the example above
>> 1) User successfully authenticated on username/password form and he is on
>> TOTP page.
>> 2) User press browser "back" button. Now he will see again the
>> username/password form
>> 3) User will try to re-submit the username/password form OR he press
>> browser "refresh" button. In both cases, we will show our nice
"Page has
>> expired. To restart the login process click here. To continue the login
>> process click here."
>>
>> Are we in agreement that this is ideal user experience?
>>
> Not quite. Clicking back shouldn't show the form again. It should rather
> just show the page expired message and ask user if they want to restart or
> continue.
>
> By the way Google's login flows are really nice. Much better than ours.
>
>
>> If yes, we can achieve that quite easily without need of javascript hacks
>> or hidden form fields though.
>>
>> Marek
>>
>>
>>
>>> Marek
>>>
>>> * No need to do redirects. Redirects is bad for performance, but also
>>> has twice the response time which is not good from a usability perspective
>>>
>>> Is this the optimal user experience? Or should we do something else?
>>>
>>> On 17 March 2017 at 08:44, Stian Thorgersen <sthorger(a)redhat.com>
wrote:
>>>
>>>> Can we please get back to discussing what the best user experience is
>>>> first. Then we can discuss implementations?
>>>>
>>>> On 16 March 2017 at 18:37, Bill Burke <bburke(a)redhat.com> wrote:
>>>>
>>>>>
>>>>> On 3/16/17 10:50 AM, Marek Posolda wrote:
>>>>>
>>>>> On 16/03/17 15:27, Bill Burke wrote:
>>>>>
>>>>> * Hidden field in a form is not a good approach. Its very brittle
and
>>>>> will not work in every situation. So huge -1 there.
>>>>>
>>>>> * browser back button is not required to resubmit the HTTP request
as
>>>>> the page can be rendered from cache. Therefore you couldn't have
a "Page
>>>>> Expired" page displayed when the back button is pressed without
setting the
>>>>> header "Cache-Control: no-store, must-revalidate,
max-age=0"
>>>>>
>>>>> Maybe we can do some javascript stuff like this:
>>>>>
http://stackoverflow.com/questions/9046184/reload-the-site-w
>>>>> hen-reached-via-browsers-back-button
>>>>>
>>>>> But that would mean that we will need to inject some common
javascript
>>>>> stuff into every HTML form displayed by authentication SPI. Could we
rely
>>>>> on that?
>>>>>
>>>>> I don't think this is a good approach as Authenticator
develoeprs
>>>>> would have to do the same thing.
>>>>>
>>>>>
>>>>>
>>>>> * Furthermore, without some type of code/information within the URL,
>>>>> you also wouldn't know if somebody clicked the back button or not
or
>>>>> whether this was a page refresh or some other GET request.
>>>>>
>>>>> Once we have the cookie with loginSessionID, we can lookup the
>>>>> loginSession. And loginSession will contain last code (same like
>>>>> clientSession now) and last authenticator. Then we just need to
compare the
>>>>> code from the loginSession with the code from request. If it matches,
we
>>>>> are good. If it doesn't match, it's likely the refresh of
some previous
>>>>> page and in that case, we can just redirect to last authenticator.
>>>>>
>>>>> This is the current behavior, but instead of using a cookie, the
>>>>> "code" is stored in the URL.
>>>>>
>>>>> With only a cookie though and no URL information, you won't know
the
>>>>> different between a Back Button and a Page Refresh for GET requests.
For
>>>>> POST requests, you won't be able to tell the differencee between
a Back
>>>>> Button, Page Refresh, or whether the POST is targeted to an actual
>>>>> Authenticator.
>>>>>
>>>>> The more I think about it, things should probably stay the way it
>>>>> currently is, with improvements on user experience. I think we can
support
>>>>> what Stian suggested with the current implementation.
>>>>>
>>>>>
>>>>> Not sure if we also need to track all codes, so we are able to
>>>>> distinct between the "expired" code, and between the
"false" code, which
>>>>> was never valid and was possibly used by some attacker for CSRF.
Maybe we
>>>>> can sign codes with HMAC, so we can verify if it is
"expired" or "false"
>>>>> code without need to track the list of last codes.
>>>>>
>>>>>
>>>>> This has been done in the past. Then it was switched to using the
>>>>> same code throughout the whole flow, then Stian switched it to
changing the
>>>>> code throughout the flow. I don't know if he uses a hash or
not.
>>>>>
>>>>> Bill
>>>>>
>>>>
>>>
>>
_______________________________________________
keycloak-dev mailing list
keycloak-dev(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/keycloak-dev
--
Vlastimil Elias
Principal Software Engineer
Red Hat Developer | Engineering