Base solution for your next web application
Open Closed

Asp.net Core 2 + Angular 6: Session timeout with OIDC (inactive users) #6958


User avatar
0
larsfk created

Hi!

Im trying to figure out how session timeout works with OIDC in Aspnet Zero. In WebCoreModule you can change session timeout for the auth-cookies, but this is not for inactivity right? So my question is how to build session timeout for inactive users? Maybe this is best done in Angular 6? Any thoughts?

Thanks :)


16 Answer(s)
  • User Avatar
    0
    larsfk created

    What happens now is this: After the time set in WebCoreModule the session expires regardless of user activity. The user is not redirected to any login page and can stille see the application page its currently on.

    I want to redirect the user to the OIDC-providers logout endpoint, but cant find the configurations for this. I also want the session to be "renewed" for every http request to the backend (dynamic session).

    Really hope you can help with this :)

    Thanks!

  • User Avatar
    0
    maliming created
    Support Team

    The user is not redirected to any login page and can stille see the application page its currently on.

    see: https://github.com/aspnetzero/aspnet-zero-core/issues/2347#issuecomment-485424307

    I also want the session to be "renewed" for every http request to the backend (dynamic session).

    try use SlidingExpiration https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.cookies.cookieauthenticationoptions.slidingexpiration?view=aspnetcore-2.2#Microsoft_AspNetCore_Authentication_Cookies_CookieAuthenticationOptions_SlidingExpiration

  • User Avatar
    0
    larsfk created

    Thanks for quick response!

    The first one is for login and not for session logout. My problem is that when session is timing out the user is not redirected to the main login page or to the ID-providers logout endpoint, which makes the user uavailable to re-login or use the application.

    I'll look into SlidingExpiration :)

  • User Avatar
    0
    larsfk created

    Session expiration: After some diging it seems that its the Abp.AuthToken which desides the timeout and triggers it. The problem is that it seems that I have no control over it when its set so I cant just implement SlidingExpiration on it. Any ideas on how to make this easy? My customer wants logout after 15 minutes on inactivity.

    Logout when timeout: When session is timed out is hows a popup window, but does not redirect to login-page. I have tried to find this popup so I can rewrite the flow, but cannot find out where its use. Only trace I found was in XML for language (CurrentUserDidNotLoginToTheApplication).

    All help will be appriciated :)

  • User Avatar
    0
    maliming created
    Support Team

    Session expiration

    Sorry, you are using JWT. It can't be SlidingExpiration.

    It is invalid at a fixed time. https://github.com/aspnetzero/aspnet-zero-core/blob/c1133c2a7a9bd227317235e9c0466fab4df20ab8/aspnet-core/src/MyCompanyName.AbpZeroTemplate.Web.Core/AbpZeroTemplateWebCoreModule.cs#L101

    Logout when timeout

    Does your component route use RouteGuard?

  • User Avatar
    0
    larsfk created

    I have not added any of my urls to the auth-route-guard, so I dont know yet how that works, but I got another idea: I implemented a middleware that adds time to Session Expiry and if the expiry has passed it will return a 401. Then I though I could change the code that runs when the frontend app gets a 401, but its nowhere to be found. If I had that code (its opens a modal with an error message) I could force a logout. Any ideas on where or how to find the 401 errorhandler?

  • User Avatar
    0
    maliming created
    Support Team

    JWT is self-contained information, it cannot (easily) be updated.

    Can you share your component routing code? By default, the Token will automatically jump to the login page after it expires.

  • User Avatar
    0
    larsfk created

    shared/common/auth/auth-route-guard.ts

    import { PermissionCheckerService } from '@abp/auth/permission-checker.service';
    import { Injectable } from '@angular/core';
    import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router';
    import { AppSessionService } from '@shared/common/session/app-session.service';
    import { UrlHelper } from '@shared/helpers/UrlHelper';
    
    @Injectable()
    export class AppRouteGuard implements CanActivate, CanActivateChild {
    
        constructor(
            private _permissionChecker: PermissionCheckerService,
            private _router: Router,
            private _sessionService: AppSessionService,
        ) { }
    
        canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    
            if (state && UrlHelper.isInstallUrl(state.url)) {
                return true;
            }
    
            if (!this._sessionService.user) {
                this._router.navigate(['/account/login']);
                return false;
            }
    
            if (!route.data || !route.data['permission']) {
                return true;
            }
    
            if (this._permissionChecker.isGranted(route.data['permission'])) {
                return true;
            }
    
            this._router.navigate([this.selectBestRoute()]);
            return false;
        }
    
        canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
            return this.canActivate(route, state);
        }
    
        selectBestRoute(): string {
    
            if (!this._sessionService.user) {
                return '/account/login';
            }
    
            if (this._permissionChecker.isGranted('Pages.Administration.Host.Dashboard')) {
                return '/app/admin/hostDashboard';
            }
    
            if (this._permissionChecker.isGranted('Pages.Tenant.Dashboard')) {
                return '/app/main/dashboard';
            }
    
            if (this._permissionChecker.isGranted('Pages.Tenants')) {
                return '/app/admin/tenants';
            }
    
            if (this._permissionChecker.isGranted('Pages.Administration.Users')) {
                return '/app/admin/users';
            }
    
            return '/app/notifications';
        }
    }
    
    
  • User Avatar
    0
    maliming created
    Support Team

    Which module does your component belong to? Is AdminModule?

  • User Avatar
    0
    larsfk created

    AppRouteGard is imported in app-routing.module and app-common.module

  • User Avatar
    0
    maliming created
    Support Team

    @larsfk Which module does your component belong to?

  • User Avatar
    0
    larsfk created

    Im not sure what component you are talking about...

  • User Avatar
    0
    maliming created
    Support Team

    Solve problems remotely.

  • User Avatar
    0
    larsfk created

    Another idea for the sliding expiration: If we set the current timeout to 2 hours and use the http context in a middleware pipeline to find validate and modify a session-variable and then add 15 minutes from current time for every http request if the user is logged in. Is this possible?

  • User Avatar
    0
    maliming created
    Support Team

    hi

    As I said before, JWT is self-contained information, it cannot (easily) be updated.

    You can consider using RefreshToken.

    E.g: The token validity period is: 1 hour. After getting the token, use RefreshToken to get a new token before 1 hour.

    If no request is made within 1 hour, the RefreshToken is no longer used to get the new token, and the application will jump to the login page.

  • User Avatar
    0
    larsfk created

    Yes, and you cannot use RefreshTokens (if we talk about same RefreshTokens) with ID-tokens in OIDC. But you can make another cookie for holding information about the session and use the JWT-cookie for "long term"-session.