How to logout properly ? (Invalidate session and navigate to a new view)

Hi,

I am using vaadin 14.x plain java (no Spring Boot), to logout from my application I have a view for this, like:

@Route(AppConst.LOGOUT_PAGE)
@Slf4j
public final class LogoutView extends Div implements BeforeEnterObserver {

    @Override
    public void beforeEnter(BeforeEnterEvent event) {


                // some cleanup resource code ommited
        
        
        VaadinSession.getCurrent().getSession().invalidate();
        UI.getCurrent().getPage().executeJs("window.location.href=''");
    }
}

The problem is with UI.getCurrent().getPage().executeJs("window.location.href=''");, when the user logout it starts an infinite loop where it creates a new session and it immediately destroys it and it never reach the page defined in href.
This behaviour was not always the same, it changed with new versions of Vaadin and it was different from firefox/chrome, now it’s the same in both browsers.

I see that I can use something like UI.getCurrent().navigate(AppConst.LOGIN_PAGE); instead and it seems to works but to be honest I don’t remember why I was using the executeJs approach.
For sure I found it googling from an answer to a problem about logout that I don’t remember anymore, it was time ago.

So if someone can confirm if the executeJs is needed for something that I don’t remember or I can use the navigate approach or if there is another safer approach.

Thanks for the help

do you use Spring Security?

I am not using Spring

You can take a look at https://github.com/vaadin/flow/blob/fd04f545ee3f13b0cf3cdf2b694c6d9ab215c689/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/SessionCloseLogoutView.java#L34

I replace the code in the LogoutView with

        getUI().ifPresent(ui -> {
            UI.getCurrent().getPage().setLocation("");
            ui.getSession().close();
        });

but it is not executed

assert getUI().isEmpty(); is valid, maybe because is in a BeforeEnterObserver ?

BeforeEnterObserver should have an getUI method to get a reference. Additionally, you can use the redirect function within the event instead of using setLocation

as I put in my assertion getUI() is empty

it’s not executed

this seems to work, I will test better but it seems ok:

        event.getUI().getPage().setLocation("/");
        event.getUI().getSession().close();

event is BeforeEnterEvent

what is the redirect method you mentioned ? it’s like event.forwardTo(LoginView.class ?

ForwardTo is correct

I would recommend using forward instead of setLocation within a navigation lifecircle because it’s the intended way

OK thanks I try! but why getUI() doesn’t return an UI inside a beforeEnter method ?

if event.getUI() can return it

getUI (coming from the view) is only available after the view is attached to the UI. Within the before navigation event it’s not clear if the view ends up within the UI or gets discarded (Spoiler it doesn’t end up there, see your forward)

The event.getUI() returns the UI reference the view is created for (and would be attached to later on)

Ok I got it! a last point, just to understand, it’s not wrong the order of operation to logout, the logic is not close session and then forward ? like

        event.getUI().getSession().close();
        event.forwardTo(SomeView.class);

in the example it is the reverse, forward and then close.