I am working on an Web API application that will be secured used Identity Server 4. The user is authenticated using implicit flow using a JavaScript client.
I am having problems reading the IdentityResource scopes in my Web API client. I think I might be missing something in the configuration when I invoke app.UseIdentityServerAuthentication( ) in my Startup.cs. I am not seeing the JSON data in any of these IdentityResource scopes when I examine the User.Claims collection.
In the JavaScript client, I am able to view the scope data using the oidc-client.js library. But, I cannot read the scope data in my Web API application.
In the javascript client, I can see the scope data stored as json blob by doing this in TypeScript:
class MyService {
private _userManager: Oidc.UserManager;
private _createUserManager(authority: string, origin: string) {
// https://github.com/IdentityModel/oidc-client-js/wiki#configuration
var config : Oidc.UserManagerSettings = {
authority: authority,
client_id: "myapi",
redirect_uri: `${origin}/callback.html`,
response_type: "id_token token",
scope: "openid profile user.profile user.organization ...",
post_logout_redirect_uri: `${origin}/index.html`
};
this._userManager = new Oidc.UserManager(config);
}
// snip
user() {
this._userManager.getUser().then(user => {
const userProfile = JSON.parse(user.profile["user.profile"]);
console.log(userProfile);
const userOrganization = JSON.parse(user.profile["user.organization"]);
console.log(userOrganization);
});
}
}
In my Web API Project, I have:
public class Startup
{
public IConfigurationRoot Configuration { get; set; }
public IContainer Container { get; set; }
public Startup(IHostingEnvironment env)
{
var configurationBuilder = new ConfigurationBuilder();
if (env.IsDevelopment())
{
configurationBuilder
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json");
env.ConfigureNLog("nlog.development.config");
}
else
{
configurationBuilder.AddEnvironmentVariables();
env.ConfigureNLog("nlog.config");
}
Configuration = configurationBuilder.Build();
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services
.AddMvcCore()
.AddJsonFormatters()
.AddAuthorization();
services.AddCors();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IRestService, RestService>();
var builder = AutoFacConfig.Create(Configuration);
builder.Populate(services);
Container = builder.Build();
return new AutofacServiceProvider(Container);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors(policy =>
{
policy
.WithOrigins(
"http://app.local:5000"
)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
ConfigureExceptionHandling(app, env);
ConfigureOidc(app);
app.UseMvc();
}
private void ConfigureExceptionHandling(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
}
private void ConfigureOidc(IApplicationBuilder app)
{
app.UseCors("default");
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = Configuration["IdentityServerUrl"],
AllowedScopes = { "api1", "openid", "profile", "user.profile", "user.organization" ... },
ApiName = "myapi",
RequireHttpsMetadata = false
});
}
}
The problem is when I try to access the claims to read its scopes. When the user is authenticated, I pass the token in the header of the request to the Web API endpoint. I have a BaseController in which I would like to read the scopes from, but cannot.
public class BaseController : Controller
{
private ApplicationUser _user;
public string UserId => CurrentUser?.UserInfo.Id;
public string OrganizationId => CurrentUser?.Organization.Id;
[CanBeNull]
public ApplicationUser CurrentUser
{
get
{
var claims = Request.HttpContext.User.Claims.ToList();
_user = new ApplicationUser
{
UserInfo = claims.Where(f => f.Type == "user.profile").Select(s => s.Value).FirstOrDefault(),
OrganizationInfo = claims.Where(f => f.Type == "user.organization").Select(s => s.Value).FirstOrDefault()
};
return _user;
}
}
}
If, I look at the claims collection, I see the following for Types and values:
nbf: 1499441027
exp: 1499444627
iss: https://identity-service....
aud: https://identity-service..../resources
aud: myapi
client_id: myapi
sub: the_user
auth_time: 1499441027
idp: local
scope: openid
scope: profile
scope: user.profile
scope: user.organization
...
scope: myapi
amr: pwd
How do I read scope data from C#?
For user.organization scope, I am expecting to read a data structure like:
{
"Id":"some id",
"BusinessCategory":"some category",
"Name":"some name"
}