Azure / static-web-apps

Azure Static Web Apps. For bugs and feature requests, please create an issue in this repo. For community discussions, latest updates, kindly refer to the Discussions Tab. To know what's new in Static Web Apps, visit https://aka.ms/swa/ThisMonth
https://aka.ms/swa
MIT License
333 stars 57 forks source link

Stay Logged In? #213

Open aa00518 opened 4 years ago

aa00518 commented 4 years ago

I am using aad authentication and it is working fine. However, when I close the browser/reopen/navigate to my site, I do not stay logged in, I have to login again. How can I automatically keep my users logged in?

mkarmark commented 4 years ago

Hi, the auth flow for Static Web Apps relies on cookie-based authentication. These cookies are session based, so it makes sense to me that you have to relogin after closing your session and open up a new one. Is this blocking your use case in any way?

aa00518 commented 4 years ago

I open my browser with two tabs, outlook.com on one and my Azure Static Web App on the other. outlook.com always logs me right back in automatically. Azure Static Web App does not. I would think it is fair for a user to expect both web apps to behave similarly.

mkarmark commented 4 years ago

I think at the moment, we plan on keeping this session cookie based auth design. There are things you can do to make the experience more seamless for the user, by adding platform error overrides to their routes file to configure the behavior to log the user in instead of responding with Unauthorized. More information for that can be found here: https://docs.microsoft.com/en-us/azure/static-web-apps/routes#custom-error-pages

arthubms commented 2 years ago

Hi We are now experiencing the exact oposite. In a Static Web App with a Custom OpenID Connect Authentication provider, sessions stay persistent even after the browser has be closed and reopened. We notice in Fiddler that the StaticWebAppsAuthCookie is given an explicit 8 hours lifetime (which to our understanding prevents it from acting as a session cookie). This leads to sessions staying open and is very insecure. How can we make the Auth Cookie act as a session cookie (again)?

scottkuhl commented 2 years ago

While logging in with Azure AD can be quite easy for a user, it's not as good an experience as keeping the user logged in. This is especially apparent in a PWA which is designed to feel more like an app than a site.

scottkuhl commented 2 years ago

It's been close to 2 years since there was an official response on this issue.

@mkarmark Is this even an issue anymore? When I inspect the client I see an authentication cookie. Testing this from a Blazor Wasm application, you can reload the authentication information from the /.auth/me path between browser sessions.

phranger commented 1 year ago

@mkarmark , it is now another year, is there likely to be any recognition and response on this issue?

@scottkuhl have you resolved this? Reloading /.auth/me does not refresh, or update any expiry on the StaticWebAppsAuthCookie

scottkuhl commented 1 year ago

@phranger I have dug back into the code on the project we needed this for and found this, which might help you. It's been almost a year so forgive me if I forget the specifics. I believe our issue was failing to call var data = await http.GetFromJsonAsync<AuthenticationData>("/.auth/me"); every time a new browser session started. I thought that refreshed the timeout, but I could be wrong. As you can see I never got a response to my question.

I am also tagging in @nitya since she is the other author on the article, Securing Static Web Apps, and may be able to help.

public class ClientPrincipal
{
    public string IdentityProvider { get; set; } = string.Empty;
    public string UserDetails { get; set; } = string.Empty;
    public string UserId { get; set; } = string.Empty;
    public IEnumerable<string> UserRoles { get; set; } = new List<string>();
}

public class StaticWebAppsAuthenticationStateProvider : AuthenticationStateProvider
{
    private readonly NavigationManager _nav;

    public StaticWebAppsAuthenticationStateProvider(NavigationManager nav)
    {
        _nav = nav;
    }

    public static ClaimsPrincipal GetClaimsFromClientClaimsPrincipal(ClientPrincipal principal)
    {
        principal.UserRoles = principal.UserRoles?.Except(new[] { "anonymous" }, StringComparer.CurrentCultureIgnoreCase) ?? new List<string>();
        if (!principal.UserRoles.Any())
        {
            return new ClaimsPrincipal();
        }
        var identity = AdaptToClaimsIdentity(principal);
        return new ClaimsPrincipal(identity);
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        try
        {
            var clientPrincipal = await GetClientPrincipal();
            var claimsPrincipal = GetClaimsFromClientClaimsPrincipal(clientPrincipal);
            return new AuthenticationState(claimsPrincipal);
        }
        catch
        {
            return new AuthenticationState(new ClaimsPrincipal());
        }
    }

    private static ClaimsIdentity AdaptToClaimsIdentity(ClientPrincipal principal)
    {
        var identity = new ClaimsIdentity(principal.IdentityProvider);
        identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, principal.UserId!));
        identity.AddClaim(new Claim(ClaimTypes.Name, principal.UserDetails!));
        identity.AddClaims(principal.UserRoles!.Select(r => new Claim(ClaimTypes.Role, r)));
        return identity;
    }

    private async Task<ClientPrincipal> GetClientPrincipal()
    {
        var http = new HttpClient { BaseAddress = new Uri(_nav.BaseUri) };
        var data = await http.GetFromJsonAsync<AuthenticationData>("/.auth/me");
        return data?.ClientPrincipal ?? new ClientPrincipal();
    }
}
phranger commented 1 year ago

Thanks @scottkuhl , in my testing fetching '/.auth/me' doesn't extend the timeout or refresh the cookie so I'm hoping someone can help figure out a solution.

nitya commented 1 year ago

Thanks for the tag folks - am not actively in that team but can try to connect to the right folks. Can you clarify which aspect of this discussion you are looking for clarity on?

There was the original issue in 2020 (asking about persistence of auth across sessions given session-based cookie design) and a somewhat different issue in 2022 (indicating behavior was the opposite) and a discussion later on explicitly reloading auth credentials in between sessions.

What is the current use case that you are trying to resolve?

scottkuhl commented 1 year ago

@nitya I can't speak for everyone on this thread but I think it comes down to documenting how you do the following:

1 - Set the timeout on authentication to longer than 8 hours so users are not frequently being asked to login. 2 - Set the authentication so the user is logged out as soon as they end the session / close the browser.

hajkio commented 1 day ago

Are there any updates on this issue? We are facing similar problems wth the user being logged in even if they close the browser.