mkanakis
mkanakis

Reputation: 383

Authentication with MVC Client 4.7.1 and IdentityServer4

I am trying to integrate user authentication between an MVC 4.7.1 client and an ASP.NET Core 3.1 IdentityServer4 & ASP.NET Identity service.

I have been following this tutorial for cookie issued authentication: Refreshing your Legacy ASP.NET IdentityServer Client Applications (with PKCE)

So far, the MVC client is able to redirect to the Login page. Upon logging in, I have a null error in the following function:

private string RetrieveCodeVerifier(AuthorizationCodeReceivedNotification n)
{
        string key = GetCodeVerifierKey(n.ProtocolMessage.State);

        string codeVerifierCookie = n.Options.CookieManager.GetRequestCookie(n.OwinContext, key);
        if (codeVerifierCookie != null)
        {
            var cookieOptions = new CookieOptions
            {
                SameSite = SameSiteMode.None,
                HttpOnly = true,
                Secure = n.Request.IsSecure
            };

            n.Options.CookieManager.DeleteCookie(n.OwinContext, key, cookieOptions);
        }

        string codeVerifier;
        var cookieProperties = n.Options.StateDataFormat.Unprotect(Encoding.UTF8.GetString(Convert.FromBase64String(codeVerifierCookie)));
        cookieProperties.Dictionary.TryGetValue("cv", out codeVerifier);

        return codeVerifier;
}

Apparently the codeVerifierCookie is null.

The rest of the configuration is as follows.

 app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = "cookie"
            });

            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                ClientId = "mvc.owin",
                Authority = "https://localhost:44355",
                RedirectUri = "http://localhost:5001/Auth/",
                Scope = "openid profile scope1",

                SignInAsAuthenticationType = "cookie",

                RequireHttpsMetadata = false,
                UseTokenLifetime = false,

                RedeemCode = true,
                SaveTokens = true,
                ClientSecret = "secret",

                ResponseType = "code",
                ResponseMode = "query",

                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    RedirectToIdentityProvider = n =>
                    {
                        if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
                        {
                            // set PKCE parameters
                            var codeVerifier = CryptoRandom.CreateUniqueId(32);

                            string codeChallenge;
                            using (var sha256 = SHA256.Create())
                            {
                                var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
                                codeChallenge = Base64Url.Encode(challengeBytes);
                            }

                            n.ProtocolMessage.SetParameter("code_challenge", codeChallenge);
                            n.ProtocolMessage.SetParameter("code_challenge_method", "S256");

                            // remember code_verifier (adapted from OWIN nonce cookie)
                            RememberCodeVerifier(n, codeVerifier);
                        }

                        return Task.CompletedTask;
                    },
                    AuthorizationCodeReceived = n =>
                    {
                        // get code_verifier
                        var codeVerifier = RetrieveCodeVerifier(n);

                        // attach code_verifier
                        n.TokenEndpointRequest.SetParameter("code_verifier", codeVerifier);

                        return Task.CompletedTask;
                    }
                }
            });

And on IdentityServer4 ConfigureServices:

 services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            var builder = services.AddIdentityServer(options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;

                // see https://identityserver4.readthedocs.io/en/latest/topics/resources.html
                options.EmitStaticAudienceClaim = true;
            })
                .AddInMemoryIdentityResources(Config.IdentityResources)
                .AddInMemoryApiScopes(Config.ApiScopes)
                .AddInMemoryClients(Config.Clients)
                .AddAspNetIdentity<ApplicationUser>();

Finally, Client.cs configuration on IdentityServer4 side:

new Client
{
            ClientId = "mvc.owin",
            ClientName = "MVC Client",
            AllowedGrantTypes = GrantTypes.Code,
            ClientSecrets = {new Secret("secret".Sha256())},
            RedirectUris = {"http://localhost:5001/Auth/"},
            AllowedScopes = {"openid", "profile", "scope1"},
            AllowPlainTextPkce = false,
            RequirePkce = true,
            RequireConsent = false,
            // Token lifetimes
            AuthorizationCodeLifetime = 60,
            AccessTokenLifetime = 60,
            IdentityTokenLifetime = 60
}

AccountController and the rest is pretty much the basic IdentityServer4.Template, specifically is4aspid.

  1. Anyone tried the same and knows what fails?
  2. Is there a way to do it with JWT instead of Cookies? And, what are the drawbacks?

Edit: Apparently, this configuration works with Firefox, and I am suspecting this is a problem with Chrome's Same-Site cookie policy, hence the null in GetRequestCookie. The thing is, IdentityServer4 is running on HTTPS (otherwise, there are others) while the MVC client app is running on HTTP (note: both on localhost). I have tried using SameSite policy None, Lax, Strict and vise-versa with no success. I am not sure what else to try.

Best, mkanakis.

Upvotes: 0

Views: 1334

Answers (1)

nahidf
nahidf

Reputation: 2394

Cookies that assert SameSite=None must also be marked as Secure, this means you need to use https

Read more here

Upvotes: 2

Related Questions