title: How to validate JWT token in other project when you have separate project for Identity using asp.net identity
body: <p>I've two projects in solution. One is for Identity management using asp.net identity generating JWT tokens. In Second project there are API's that are secure and validating token that are generated from identity project but token validation not working.</p>
  
  <p>I'm getting this error when calling api store route in postman. I'm passing token in Authorization header.</p>
  
  <blockquote>
    <p>An unhandled exception occurred while processing the request.
    HttpRequestException: Response status code does not indicate success:
    404 (Not Found).
    System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()</p>
    
    <p>IOException: IDX20804: Unable to retrieve document from: '[PII is
    hidden]'.
    Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string
    address, CancellationToken cancel)</p>
    
    <p>InvalidOperationException: IDX20803: Unable to obtain configuration
    from: '[PII is hidden]'.
    Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken
    cancel)</p>
    
    <p>Stack Query Cookies Headers HttpRequestException: Response status code
    does not indicate success: 404 (Not Found).
    System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
    Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string
    address, CancellationToken cancel)</p>
    
    <p>Show raw exception details System.Net.Http.HttpRequestException:
    Response status code does not indicate success: 404 (Not Found).    at
    System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()    at
    Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String
    address, CancellationToken cancel) IOException: IDX20804: Unable to
    retrieve document from: '[PII is hidden]'.
    Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string
    address, CancellationToken cancel)
    Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(string
    address, IDocumentRetriever retriever, CancellationToken cancel)
    Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken
    cancel)</p>
    
    <p>Show raw exception details System.IO.IOException: IDX20804: Unable to
    retrieve document from: '[PII is hidden]'. --->
    System.Net.Http.HttpRequestException: Response status code does not
    indicate success: 404 (Not Found).    at
    System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()    at
    Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String
    address, CancellationToken cancel)    --- End of inner exception stack
    trace ---    at
    Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String
    address, CancellationToken cancel)    at
    Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String
    address, IDocumentRetriever retriever, CancellationToken cancel)    at
    Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken
    cancel) InvalidOperationException: IDX20803: Unable to obtain
    configuration from: '[PII is hidden]'.
    Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken
    cancel)
    Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
    Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
    Microsoft.AspNetCore.Authentication.AuthenticationHandler.AuthenticateAsync()
    Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext
    context, string scheme)
    Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext
    context)
    Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext
    context)</p>
    
    <p>Show raw exception details System.InvalidOperationException: IDX20803:
    Unable to obtain configuration from: '[PII is hidden]'. --->
    System.IO.IOException: IDX20804: Unable to retrieve document from:
    '[PII is hidden]'. ---> System.Net.Http.HttpRequestException: Response
    status code does not indicate success: 404 (Not Found).    at
    System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()    at
    Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String
    address, CancellationToken cancel)    --- End of inner exception stack
    trace ---    at
    Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String
    address, CancellationToken cancel)    at
    Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String
    address, IDocumentRetriever retriever, CancellationToken cancel)    at
    Microsoft.IdentityModel.Protocols.ConfigurationManager<code>1.GetConfigurationAsync(CancellationToken
    cancel)    --- End of inner exception stack trace ---    at
    Microsoft.IdentityModel.Protocols.ConfigurationManager</code>1.GetConfigurationAsync(CancellationToken
    cancel)    at
    Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
    at
    Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
    at
    Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
    at
    Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext
    context, String scheme)    at
    Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext
    context)    at
    Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext
    context)</p>
  </blockquote>
  
  <p>This is my Startup.cs class in Identity project.</p>
  
  <pre><code>using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using Cosmonaut;
  using Cosmonaut.Extensions.Microsoft.DependencyInjection;
  using Microsoft.AspNetCore.Authentication.JwtBearer;
  using Microsoft.AspNetCore.Builder;
  using Microsoft.AspNetCore.Hosting;
  using Microsoft.AspNetCore.Identity;
  using Microsoft.Azure.Documents;
  using Microsoft.Azure.Documents.Client;
  using Microsoft.Extensions.Configuration;
  using Microsoft.Extensions.DependencyInjection;
  using Microsoft.IdentityModel.Tokens;
  using Triverse.Identity.Models;
  using Triverse.Identity.Services;
  using IdentityRole = Microsoft.AspNetCore.Identity.DocumentDB.IdentityRole;
  
  namespace Triverse.Identity
  {
      public class Startup
      {
          public Startup(IConfiguration configuration)
          {
              Configuration = configuration;
          }
  
          public IConfiguration Configuration { get; }
  
          // This method gets called by the runtime. Use this method to add services to the container.
          // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
          public void ConfigureServices(IServiceCollection services)
          {
              services.AddMvc();
  
              var endPointUri = Configuration.GetValue&lt;string&gt;("AppSettings:EndpointUri");
              var primaryKey = Configuration.GetValue&lt;string&gt;("AppSettings:PrimaryKey");
              var databaseId = Configuration.GetValue&lt;string&gt;("AppSettings:DatabaseId");
              var collectionId = Configuration.GetValue&lt;string&gt;("AppSettings:CollectionId");
  
              var client = new DocumentClient(new Uri(endPointUri), primaryKey);
              services.AddSingleton&lt;IDocumentClient&gt;(client);
  
              // make sure the database exists!
              var db = client.CreateDatabaseQuery().Where(d =&gt; d.Id == databaseId).AsEnumerable().FirstOrDefault()
                       ?? client.CreateDatabaseAsync(new Database { Id = databaseId }).Result;
  
              var databaseLink = db.SelfLink;
  
              services.AddIdentityWithDocumentDBStores&lt;ApplicationUser, IdentityRole&gt;(
                  dbOptions =&gt;
                  {
                      dbOptions.DocumentUrl = endPointUri;
                      dbOptions.DocumentKey = primaryKey;
                      dbOptions.DatabaseId = databaseId;
                      dbOptions.CollectionId = collectionId;
                  },
                  identityOptions =&gt;
                  {
                      identityOptions.User.RequireUniqueEmail = true;
                  });
  
              var cosmosSettings = new CosmosStoreSettings(databaseId, endPointUri, primaryKey);
              services.AddCosmosStore&lt;ApplicationUser&gt;(cosmosSettings);
  
              services.AddScoped&lt;IAccountRepository, AccountRepository&gt;();
              services.AddTransient&lt;ITokenService, TokenService&gt;();
  
              services.AddAuthentication(options =&gt;
                  {
                      options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                      options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                      options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
                  })
                  .AddJwtBearer(cfg =&gt;
                  {
                      cfg.TokenValidationParameters = new TokenValidationParameters
                      {
                          ValidIssuer = Configuration["Tokens:Issuer"],
                          ValidAudience = Configuration["Tokens:Audience"],
                          IssuerSigningKey =
                              new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"])),
                          ValidateLifetime = true
                      };
  
                      cfg.Events = new JwtBearerEvents
                      {
                          OnAuthenticationFailed = context =&gt;
                          {
                              if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                              {
                                  context.Response.Headers.Add("Token-Expired", "true");
                                  context.Response.Headers.Add("access-control-expose-headers", "Token-Expired");
                              }
  
                              return Task.CompletedTask;
                          }
                      };
                  });
          }
  
          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
          public void Configure(IApplicationBuilder app, IHostingEnvironment env)
          {
              if (env.IsDevelopment())
              {
                  app.UseDeveloperExceptionPage();
              }
  
              app.UseAuthentication();
  
              app.UseMvc();
          }
      }
  }
  </code></pre>
  
  <p>This is my appsettings.json in Identity project.</p>
  
  <pre><code>"Tokens": {
      "Key": "4343@!#ewewq",
      "Issuer": "http://localhost:44376/",
      "Audience": "http://localhost:44385/",
      "ExpiryMinutes": "55",
      "ValidateLifetime": true
    }
  </code></pre>
  
  <p>This is my Startup.cs class in Store project.</p>
  
  <pre><code>using System;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using Cosmonaut;
  using Cosmonaut.Extensions.Microsoft.DependencyInjection;
  using Microsoft.AspNetCore.Authentication.JwtBearer;
  using Microsoft.AspNetCore.Builder;
  using Microsoft.AspNetCore.Hosting;
  using Microsoft.AspNetCore.Http;
  using Microsoft.Azure.Documents;
  using Microsoft.Azure.Documents.Client;
  using Microsoft.Extensions.Configuration;
  using Microsoft.Extensions.DependencyInjection;
  using Microsoft.IdentityModel.Tokens;
  using Store.API.Services;
  
  namespace Store.API
  {
      public class Startup
      {
          public Startup(IConfiguration configuration)
          {
              Configuration = configuration;
          }
  
          public IConfiguration Configuration { get; }
  
          public void ConfigureServices(IServiceCollection services)
          {
              services.AddMvc();
  
              var endPointUri = Configuration.GetValue&lt;string&gt;("AppSettings:EndpointUri");
              var primaryKey = Configuration.GetValue&lt;string&gt;("AppSettings:PrimaryKey");
              var databaseId = Configuration.GetValue&lt;string&gt;("AppSettings:DatabaseId");
  
              var client = new DocumentClient(new Uri(endPointUri), primaryKey);
              services.AddSingleton&lt;IDocumentClient&gt;(client);
  
              var db = client.CreateDatabaseQuery().Where(d =&gt; d.Id == databaseId).AsEnumerable().FirstOrDefault()
                       ?? client.CreateDatabaseAsync(new Database {Id = databaseId}).Result;
  
              var databaseLink = db.SelfLink;
  
              var cosmosSettings = new CosmosStoreSettings(databaseId, endPointUri, primaryKey);
              services.AddCosmosStore&lt;Models.Store&gt;(cosmosSettings);
  
              services.AddScoped&lt;IStoreRepository, StoreRepository&gt;();
  
              services.AddSingleton&lt;IHttpContextAccessor, HttpContextAccessor&gt;();
  
              services.AddAuthentication(options =&gt;
              {
                  options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                  options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  
              }).AddJwtBearer(options =&gt;
              {
                  options.Authority = "http://localhost:44376/";
                  options.RequireHttpsMetadata = false;
                  options.Audience = "http://localhost:44385/";
              });
          }
  
          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
          public void Configure(IApplicationBuilder app, IHostingEnvironment env)
          {
              if (env.IsDevelopment())
              {
                  app.UseDeveloperExceptionPage();
              }
  
              app.UseAuthentication();
  
              app.UseMvc();
          }
      }
  }
  </code></pre>
  
  <p>This is my controller method in Store project.</p>
  
  <pre><code>[HttpGet]
  [Authorize]
  public async Task&lt;IActionResult&gt; GetStores()
  {
    var stores = new
    {
       Id = 1,
       Name = "T-Shirt",
       Price = "120.00"
    };
  
    return Ok(stores);
  }
  </code></pre>
  
  <p>This is my JWT token generated from Identity project.</p>
  
  <pre><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzaGFAZG9tYWluLmNvbSIsImp0aSI6IjFjYjNkNjA2LWI4MGQtNGNlZC1hMWFjLThlYmUzNzc1ZGViOSIsIlVuaXF1ZUlkIjoiZjU1ZTM2MWQtYjFkYy00MDg4LTlmYjQtMDg3ZTI4OTFjNWI1IiwidW5pcXVlX25hbWUiOiJzaGFAZG9tYWluLmNvbSIsImZpcnN0TmFtZSI6IlNoYXduIiwibmJmIjoxNTY0OTkwMjA1LCJleHAiOjE1NjQ5OTM1MDUsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NDQzNzYvIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo0NDM4NS8ifQ.ZBK8Fi14QUc9ObZx7ojg7LPcl8Qs2vrQyhZi7Dbk4Gg
  </code></pre>