title: Refresh ClaimsPrincipal with OpenIDConnect Middleware, MVC Client, Cookies
body: <p>Is there a standard way to ask an MVC client using ID4 OIDC middleware to refresh the ClaimsPrincipal when using cookies? It would be nice to just ask the middleware to refresh the ClaimsPrincipal but I don't think that functionality exists. </p>
  
  <p>The code below does work, however, there is no nonce used in the example below - so I'm not sure if that's secure. I'm not sure how the middleware creates the nonce.</p>
  
  <p>Does anyone have an example of properly refreshing the ClaimsPrincipal in an MVC client application using cookies with ID4 OIDC middleware?</p>
  
  <h2>Validate ID token and Return ClaimsPrincipal from ID Token</h2>
  
  <pre><code>private ClaimsPrincipal ValidateIdentityToken(string idToken, DiscoveryResponse disco  )
      {
  
  
          var keys = new List&lt;SecurityKey&gt;();
          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;
      }
  </code></pre>
  
  <h2>Check cookie expiration. Use the refresh token to refresh ID and Access token. Use the above validation to return ClaimsPrincipal</h2>
  
  <pre><code> 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 =&gt;
                  {
                      if (cookiecontext.Properties.Items.ContainsKey(".Token.expires_at"))
                      {
                          var expire = DateTime.Parse(cookiecontext.Properties.Items[".Token.expires_at"]);
                          if (expire &lt;= DateTime.Now.AddMinutes(-5) || DateTime.Now &gt; 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();
                              }
                          }
                      }
                  }
              }
          });
  </code></pre>
  
  <h2>Wireup ID4 middleware</h2>
  
  <pre><code> 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 =&gt;
                  {
                      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,
              }
          });
  
  
      }
  </code></pre>