I am building an application where Web API and IdentityServer4 are inside the same .Net Core 2.0 project. This API is consumed by Aurelia SPA web app. IdentityServer4 set to use JWT and ImplicitFlow. Everything works good (Client app gets redirected to login, gets token, sends it back on header, etc.) up to the point where user needs to be authorized in the API controller, then it just cannot authorize user, because it's null.
There are many similar questions exists, but I tried all proposed solutions and none of them worked for me. I already spent 2 days on this issue and starting to loose hope and patience. I probably missing something obvious, but just can't find it. I posting my configs here - what is wrong with them? Will appreciate any help.
My Startup class (I have omitted some extra things like logging, localization, etc.):
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddCors(options =>
{
options.AddPolicy("default", policy =>
{
policy.WithOrigins(Config.APP1_URL)
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddMvc();
services.Configure<IdentityOptions>(options =>
{
// Password settings
options.Password.RequireDigit = false;
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
options.Password.RequiredUniqueChars = 4;
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
options.Lockout.AllowedForNewUsers = true;
// User settings
options.User.RequireUniqueEmail = true;
});
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryPersistedGrants()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddAspNetIdentity<ApplicationUser>();
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = Config.HOST_URL + "/";
options.RequireHttpsMetadata = false;
options.ApiName = "api1";
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentityServer();
app.UseAuthentication();
app.UseCors("default");
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
This is my Config class:
public class Config
{
public static string HOST_URL = "http://dev.example.com:5000";
public static string APP1_URL = "http://dev.example.com:9000";
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API")
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "reporter",
ClientName = "ReporterApp Client",
AccessTokenType = AccessTokenType.Jwt,
AllowedGrantTypes = GrantTypes.Implicit,
RequireConsent = false,
AllowAccessTokensViaBrowser = true,
RedirectUris =
{
$"{APP1_URL}/signin-oidc"
},
PostLogoutRedirectUris = {
$"{APP1_URL}/signout-oidc"
},
AllowedCorsOrigins = {
APP1_URL
},
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
}
}
};
}
}
And the token Aurelia app gets from IdentityServer:
{
"alg": "RS256",
"kid": "52155e28d23ddbab6154ce0c34511c9a",
"typ": "JWT"
},
{
"nbf": 1521195164,
"exp": 1521198764,
"iss": "http://dev.example.com:5000",
"aud": ["http://dev.example.com:5000/resources", "api1"],
"client_id": "reporter",
"sub": "767381df-446a-4c34-af27-7bdf9e4563f3",
"auth_time": 1521195163,
"idp": "local",
"scope": ["openid", "profile", "api1"],
"amr": ["pwd"]
}