Reputation: 969
I'm all of a sudden getting 401 errors from my web API project after trying to migrate to the latest version of IdentityServer4 and .NET Core 2. Over the last week, I've made so many changes, I don't know what's right or wrong anymore.
I have a small 3 project solution:
Here is my Code to configure IDSV which is stored in my database:
public class Config
{
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(){
Name = "api.oc.com",
Description = "OC Api",
Scopes = new[] {new Scope("api.oc.com")}
}
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "oc.com",
ClientName = "OC Website",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
AlwaysIncludeUserClaimsInIdToken = true,
ClientSecrets =
{
new Secret("SomeReallyStrongPassword1!".Sha256())
},
RedirectUris = { "https://localhost:44301/signin-oidc" },
PostLogoutRedirectUris = { "https://localhost:44301/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api.oc.com",
"offline_access"
},
AllowOfflineAccess = true
}
};
}
}
In my WEB API Startup.cs. I have this in ConfigureServices. I believe my Configure method is ok.
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.Authority = "https://localhost:44300";
o.RequireHttpsMetadata = false;
o.Audience = "api.oc.com";
});
services.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters();
This brings me to the WEB Front End trying to authenticate to the WEB API. I've tried it both with Access Tokens & ID Tokens, but none seem to work.
With Access Token:
var accessToken = await HttpContext.GetTokenAsync("access_token");
var client = new HttpClient();
client.SetBearerToken(accessToken);
var result = await client.GetStringAsync("https://localhost:44302/api/text/welcome");
Or with the client credentials flow:
var disco = await DiscoveryClient.GetAsync("https://localhost:44300");
var tokenClient = new TokenClient(disco.TokenEndpoint, "oc.com", "SomeReallyStrongPassword1!");
var tokenResponse = await tokenClient.RequestClientCredentialsAsync();
var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);
var result = await client.GetStringAsync("https://localhost:44302/api/text/welcome");
I'm sincerely thankful if anyone has any incite on this. It's been so long looking at security code that my eyeballs are going explode! LOL.
Thanks, Mike Kushner
Upvotes: 3
Views: 3403
Reputation: 969
After some meddling.. And adding a real certificate, this seems to be working after I created some policies instead of just using the [Authorize] attribute only. Note, that I'm also using IdentityServer4.AccessTokenValidation again.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthorization((options) => {
options.AddPolicy("MustBeValidUser", policybuilder =>
{
policybuilder.RequireAuthenticatedUser();
policybuilder.Requirements = new[] { new MustBeValidUserRequirement() };
});
});
services.AddSingleton<IAuthorizationHandler, MustBeValidUserHandler>();
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = "https://localhost:44300";
options.RequireHttpsMetadata = true;
options.ApiName = "api.oc.com";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
app.UseDeveloperExceptionPage();
app.UseAuthentication();
app.UseMvc();
}
}
Upvotes: 1