Update ClaimsPrincipal with OpenIDConnect Middleware, MVC Client, Cookies

Is there a standard way to ask the MVC client to use ID4 OIDC middleware to update ClaimsPrincipal when using cookies? It would be nice to ask the middleware to update the ClaimsPrincipal, but I don't think this functionality exists.

The code below works, however the example below does not use a nonce, so I'm not sure if it's safe. I'm not sure how the middleware creates the nonce.

Does anyone have an example of how to properly update ClaimsPrincipal in an MVC client application using cookies with ID4 OIDC middleware?

Check id token and return ClaimsPrincipal from id

private ClaimsPrincipal ValidateIdentityToken(string idToken, DiscoveryResponse disco  )
    {


        var keys = new List<SecurityKey>();
        foreach (var webKey in disco.KeySet.Keys)
        {
            var e = Base64Url.Decode(webKey.E);
            var n = Base64Url.Decode(webKey.N);

            var key = new RsaSecurityKey(new RSAParameters { Exponent = e, Modulus = n });
            key.KeyId = webKey.Kid;

            keys.Add(key);
        }

        var parameters = new TokenValidationParameters
        {
            ValidIssuer = disco.TryGetString(OidcConstants.Discovery.Issuer),
            ValidAudience = "mvc.hybrid",
            IssuerSigningKeys = keys,

            NameClaimType = JwtClaimTypes.Name,
            RoleClaimType = JwtClaimTypes.Role
        };

        var handler = new JwtSecurityTokenHandler();
        handler.InboundClaimTypeMap.Clear();

        SecurityToken token;
        var user = handler.ValidateToken(idToken, parameters, out token);

        //var nonce = user.FindFirst("nonce")?.Value ?? "";
        //if (!string.Equals(nonce, "random_nonce")) throw new Exception("invalid nonce");
       //nonce is always ""
        return user;
    }

      

Check the cookie expiration date. Use refresh token to refresh ID and access token. Use the above validation to return a ClaimsPrincipal

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {


        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationScheme = "Cookies",
            AutomaticAuthenticate = true,
            ExpireTimeSpan = TimeSpan.FromMinutes(60),

            Events = new CookieAuthenticationEvents()
            {
                OnValidatePrincipal = async cookiecontext =>
                {
                    if (cookiecontext.Properties.Items.ContainsKey(".Token.expires_at"))
                    {
                        var expire = DateTime.Parse(cookiecontext.Properties.Items[".Token.expires_at"]);
                        if (expire <= DateTime.Now.AddMinutes(-5) || DateTime.Now > expire)
                        {
                            var disco = await DiscoveryClient.GetAsync("http://localhost:5000");
                            if (disco.IsError) throw new Exception(disco.Error);


                            var refreshToken = cookiecontext.Properties.Items[".Token.refresh_token"];
                            var tokenClient = new TokenClient(disco.TokenEndpoint,
                                "mvc.hybrid",
                                "secret");
                            var response = await tokenClient.RequestRefreshTokenAsync(refreshToken);
                            if (!response.IsError)
                            {
                                cookiecontext.Properties.Items[".Token.access_token"] = response.AccessToken;
                                cookiecontext.Properties.Items[".Token.refresh_token"] = response.RefreshToken;
                                cookiecontext.Properties.Items[".Token.expires_at"] = DateTime.Now.AddSeconds((int)response.ExpiresIn).ToString();
                                cookiecontext.Properties.Items["NextAccessTokenRefresh"] = DateTime.Now.AddMinutes(5).ToString();

                                var _Princ = ValidateIdentityToken(response.IdentityToken, disco);

                                cookiecontext.ReplacePrincipal(_Princ);                                    

                                cookiecontext.ShouldRenew = true;

                            }
                            else
                            {
                                cookiecontext.RejectPrincipal();
                            }
                        }
                    }
                }
            }
        });

      

Wired ID4 middleware

 JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

        app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
        {
            AuthenticationScheme = "oidc",
            SignInScheme = "Cookies",

            Authority = "http://localhost:5000", 
            RequireHttpsMetadata = false,

            ClientId = "mvc.hybrid",
            ClientSecret = "secret",


            ResponseType = "code id_token",
            Scope = { "openid", "profile", "email", "api1", "offline_access", "role" },
            GetClaimsFromUserInfoEndpoint = true,
            Events = new OpenIdConnectEvents()
            {
                OnTicketReceived = notification =>
                {
                    notification.Response.Cookies.Append("NextAccessTokenRefresh", DateTime.Now.AddMinutes(5).ToString());
                    return Task.FromResult(0);
                }
            },

            SaveTokens = true,

            TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
            {
                NameClaimType = JwtClaimTypes.Name,
                RoleClaimType = JwtClaimTypes.Role,
            }
        });


    }

      

+3


source to share





All Articles