title: Re-authorize persistent login (MVC client) without triggering login UI
body: <p>I am trying to figure out how a server-side client (MVC / ASP.NET Core 2) can query IdentityServer4 to retrieve various claims scopes for a persistent login created in some previous session <em>without prompting for login</em> if the persistent login is invalid (user inactive, cookie expired, etc).</p>
  
  <p>We're using Implicit flow with third-party auth (Google, FB, etc) but we changed the session-duration on the cookie to a more user-friendly 30 day expiration in IdentityServer's <code>ExternalLoginCallback</code>.</p>
  
  <p>Accessing claims on <code>HttpContext.User</code> (we are <strong>not</strong> using ASP.NET Identity) works great during the session that establishes login. On some later session, navigating to a client resource with an <code>[Authorize]</code> attribute also works: if the user had logged in previously, they transparently gain access to the resource, claims are populated, etc. If not, they're prompted for login, which is ok in response to a user-initiated action.</p>
  
  <p>However, we have a requirement for the client landing page to alter the content depending on whether the user is anonymous or authenticated. A simple example would be "Register" and "Log in" links for anonymous users, but "Account" and "Log out" links for authenticated users. </p>
  
  <p>Hence the reason to retrieve claims and jump-start the persistent login if it's valid, but do nothing (no login prompt) if invalid: we don't want the landing page to force every anonymous user to a login screen.</p>
  
  <p>Nothing special to say about our setups on either end of the pipeline. Client:</p>
  
  
  
  <pre class="lang-cs prettyprint-override"><code>services.AddAuthentication(options =&gt;
  {
      options.DefaultScheme = "Cookies";
      options.DefaultChallengeScheme = "oidc";
  })
  .AddCookie("Cookies")
  
  .AddOpenIdConnect("oidc", options =&gt;
  {
      options.SignInScheme = "Cookies";
      options.Authority = "https://localhost:5000";
      options.RequireHttpsMetadata = true;
      options.ClientId = "example.com.webserver";
      options.ClientSecret = "examplesecret";
      options.ResponseType = "id_token";
      options.SaveTokens = true;
      options.GetClaimsFromUserInfoEndpoint = true;
      options.Scope.Add("example.com.identity");
  });
  </code></pre>
  
  <p>IdentityServer client resource definition:</p>
  
  <pre class="lang-cs prettyprint-override"><code>new Client
  {
      ClientId = "example.com.webserver",
      ClientName = "example.com",
      ClientUri = "https://localhost:5002",
      AllowedGrantTypes = GrantTypes.Implicit,
      ClientSecrets = {new Secret("examplesecret".Sha256())},
      RequireConsent = false,
      AllowRememberConsent = true,
      AllowOfflineAccess = true,
      RedirectUris = { "https://localhost:5002/signin-oidc"},
      PostLogoutRedirectUris = { "https://localhost:5002/signout-callback-oidc"},
      AllowedScopes = new List&lt;string&gt;
      {
          IdentityServerConstants.StandardScopes.OpenId,
          IdentityServerConstants.StandardScopes.Profile,
          IdentityServerConstants.StandardScopes.Email,
          IdentityServerConstants.StandardScopes.Phone,
          IdentityServerConstants.StandardScopes.Address,
          "example.com.identity"
      }
  }
  </code></pre>
  
  <p>The client runs an intentional login (user clicks "Log in" link) like so:</p>
  
  <pre class="lang-cs prettyprint-override"><code>[HttpPost]
  [ValidateAntiForgeryToken]
  public async Task Login()
  {
      await HttpContext.SignOutAsync("oidc");
      await HttpContext.ChallengeAsync("oidc", 
          new AuthenticationProperties() {
              RedirectUri = Url.Action("LoginCallback")
          });
  }
  </code></pre>