[keycloak-dev] Improve back-button and refreshes in authenticators?
bburke at redhat.com
Fri Mar 17 11:21:26 EDT 2017
The best user experience would be that the user can click the
back/forward/refresh buttons as they wanted and things would work as
they would expect, i.e. if you're on the OTP page, you could click the
back button and go to the username/password page and re-enter username
password. I didn't implement support for this approach as its really
freakin hard to get right.
The real question is, do we want to support going backwards or forwards
in a flow? If we don't, then there are considerations and limitations
on what we can do for the user experience which I was trying to get at
* Is it possible to determine the difference between the back, forward,
or refresh button event?
That is the question I struggled the most with when implementing auth
I'd say we set the bar low and minimally try to provide this experience:
* If back, forward, or refresh button is pushed, show the "Page expired"
page you suggested before Stian.
Anything different than that will be dependent on the limitations of the
browser and our auth flow implementation.
There's also another type of user experience you aren't considering that
should be involved with the discussion. Specifically the user
experience of writing an Authenticator. You want the Authenticator
development to be simple...you also want to make sure that its
implemented in a way that developers can't make mistakes and introduce
security holes by accident. All this stuff is tied together which makes
the problem really complex.
On 3/17/17 3:45 AM, 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.". Or Back button could just go to the start
> of the flow always.
> * Resubmitting forms will just display the page above
> * 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 at redhat.com
> <mailto:sthorger at 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 at redhat.com
> <mailto:bburke at 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"
>> But that would mean that we will need to inject some common
>> 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
>> 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.
More information about the keycloak-dev