Swagger not able to authenticate to Azure AD B2C - swagger

I have a Web API with a Swagger and an Azure AD B2C tenant.
A React app is able to obtain a token from B2C like:
msalInstance.loginRedirect({
scopes: ["openid", "offline_access", process.env.MY_CLIENT_ID],
});
However the Swagger Authorize function returns AADB2C90205, This+application+does+not+have+sufficient+permissions+against+this+web+resource+to+perform+the+operation
The AddSwagger code in Startup.cs is:
private void AddSwagger(IServiceCollection services)
{
var azureAdB2C = new AzureAdB2CSettings();
this.Configuration.Bind("AzureAdB2C", azureAdB2C);
var authUrl = $"https://{azureAdB2C.TenantName}.b2clogin.com/{azureAdB2C.TenantName}.onmicrosoft.com/{azureAdB2C.SignUpSignInPolicyId}/oauth2/v2.0";
services.AddOpenApiDocument(
document =>
{
document.AddSecurity(
"bearer",
Enumerable.Empty<string>(),
new OpenApiSecurityScheme
{
Type = OpenApiSecuritySchemeType.OAuth2,
Description = "Azure AAD Authentication",
Flow = OpenApiOAuth2Flow.Implicit,
Flows = new OpenApiOAuthFlows()
{
Implicit = new OpenApiOAuthFlow()
{
Scopes = new Dictionary<string, string>
{
{
$"{azureAdB2C.Instance}/{azureAdB2C.ClientId}/user_impersonation",
"Access Application"
},
{
$"{azureAdB2C.Instance}/{azureAdB2C.ClientId}/access_as_user",
"Access as User"
},
},
AuthorizationUrl = $"{authUrl}/authorize",
TokenUrl = $"{authUrl}/token",
},
},
});
document.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("bearer"));
});
}
The B2C configuration is as follows:
Am I missing anything obvious here?

If you want to call web api projected by Azure AD B2C, please refer to the folloiwng steps
a. Register web api application in Azure AD B2C
b. Define scope
c. Register SPA application in Azure AD B2C
d. Grant Permissions.
e. application
package
Microsoft.AspNetCore.Authentication.AzureADB2C.UI
NSwag.AspNetCore
appsettings.json
{
"AzureAdB2C": {
"Instance": "https://<>.b2clogin.com/tfp/",
"ClientId": "<web api clinet id>",
"Domain": "<>.onmicrosoft.com",
"SignUpSignInPolicyId": "B2C_1_test"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
public void ConfigureServices(IServiceCollection services)
{
// snip
services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
// Add security definition and scopes to document
services.AddOpenApiDocument(document =>
{
document.AddSecurity("bearer", Enumerable.Empty<string>(), new OpenApiSecurityScheme
{
Type = OpenApiSecuritySchemeType.OAuth2,
Description = "B2C authentication",
Flow = OpenApiOAuth2Flow.Implicit,
Flows = new OpenApiOAuthFlows()
{
Implicit = new OpenApiOAuthFlow()
{
Scopes = new Dictionary<string, string>
{
{ "https://<b2c_tenant_name>.onmicrosoft.com/your-api/user_impersonation", "Access the api as the signed-in user" },
{ "https://<b2c_tenant_name>.onmicrosoft.com/your-api/read", "Read access to the API"},
{ "https://<b2c_tenant_name>.onmicrosoft.com/your-api/mystery_scope", "Let's find out together!"}
},
AuthorizationUrl = "https://<b2c_tenant_name>.b2clogin.com/<b2c_tenant_name>.onmicrosoft.com/oauth2/v2.0/authorize?p=<policy_name>",
TokenUrl = "https://<b2c_tenant_name>.b2clogin.com/<b2c_tenant_name>.onmicrosoft.com/oauth2/v2.0/token?p=<policy_name>"
},
}
});
document.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("bearer"));
});
//snip
// ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseOpenApi();
app.UseSwaggerUi3(settings =>
{
settings.OAuth2Client = new OAuth2ClientSettings
{
ClientId = "<spa client id>",
AppName = "swagger-ui-client"
};
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
f.test
For more details, please refer to the blog.

Related

Issues getting an api with swagger to authenticate with IdentityServer4 using .net5.0

I am currently learning how microservices work for an application i am building for my portfolio and for a small community of people that want this specific application. I have followed a tutorial online and successfully got IdentityServer4 to authenticate an MVC Client, however, I am trying to get swagger to work alongside the API's especially if they require authentication. Each time I try to authorize swagger with IdentityServer4, I am getting invalid_scope error each time I try authenticate. I have been debugging this problem for many hours an am unable to figure out the issue. I have also used the Microsoft eShopOnContainers as an example but still no luck. Any help would be greatly appreciated. Ill try keep the code examples short, please request any code not shown and ill do my best to respond asap. Thank you.
Identiy.API project startup.cs:
public class Startup {
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()
.AddInMemoryClients(Config.GetClients())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryApiScopes(Config.GetApiScopes())
.AddTestUsers(Config.GetTestUsers())
.AddDeveloperSigningCredential(); // #note - demo purposes only. need X509Certificate2 for production)
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseStaticFiles();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
}
}
Config.cs (i removed the test users to keep the code shorter, since it is not relevant).
#note -I created a WeatherSwaggerUI client specifically for use with swagger since this was apart of eShopOnContainers example project provided by microsoft:
public static class Config
{
public static List<TestUser> GetTestUsers()
{
return new List<TestUser>(); // removed test users for this post
}
public static IEnumerable<Client> GetClients()
{
// #note - clients can be defined in appsettings.json
return new List<Client>
{
// m2m client credentials flow client
new Client
{
ClientId = "m2m.client",
ClientName = "Client Credentials Client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets = { new Secret("SuperSecretPassword".ToSha256())},
AllowedScopes = { "weatherapi.read", "weatherapi.write" }
},
// interactive client
new Client
{
ClientId = "interactive",
ClientSecrets = {new Secret("SuperSecretPassword".Sha256())},
AllowedGrantTypes = GrantTypes.Code,
RedirectUris = {"https://localhost:5444/signin-oidc"},
FrontChannelLogoutUri = "https://localhost:5444/signout-oidc",
PostLogoutRedirectUris = {"https://localhost:5444/signout-callback-oidc"},
AllowOfflineAccess = true,
AllowedScopes = {"openid", "profile", "weatherapi.read"},
RequirePkce = true,
RequireConsent = false,
AllowPlainTextPkce = false
},
new Client
{
ClientId = "weatherswaggerui",
ClientName = "Weather Swagger UI",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = {"https://localhost:5445/swagger/oauth2-redirect.html"},
PostLogoutRedirectUris = { "https://localhost:5445/swagger/" },
AllowedScopes = { "weatherswaggerui.read", "weatherswaggerui.write" },
}
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("weatherapi", "Weather Service")
{
Scopes = new List<string> { "weatherapi.read", "weatherapi.write" },
ApiSecrets = new List<Secret> { new Secret("ScopeSecret".Sha256()) },
UserClaims = new List<string> { "role" }
},
new ApiResource("weatherswaggerui", "Weather Swagger UI")
{
Scopes = new List<string> { "weatherswaggerui.read", "weatherswaggerui.write" }
}
};
}
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResource
{
Name = "role",
UserClaims = new List<string> { "role" }
},
};
}
public static IEnumerable<ApiScope> GetApiScopes()
{
return new List<ApiScope>
{
// weather API specific scopes
new ApiScope("weatherapi.read"),
new ApiScope("weatherapi.write"),
// SWAGGER TEST weather API specific scopes
new ApiScope("weatherswaggerui.read"),
new ApiScope("weatherswaggerui.write")
};
}
}
Next project is the just the standard weather api when creating a web api project with vs2019
WeatherAPI Project startup.cs (note i created extension methods as found in eShopOnContainers as i liked that flow):
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.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddCustomAuthentication(Configuration)
.AddSwagger(Configuration);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger()
.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Weather.API V1");
options.OAuthClientId("weatherswaggerui");
options.OAuthAppName("Weather Swagger UI");
});
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
public static class CustomExtensionMethods
{
public static IServiceCollection AddSwagger(this IServiceCollection services, IConfiguration configuration)
{
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "Find Scrims - Weather HTTP API Test",
Version = "v1",
Description = "Randomly generates weather data for API testing"
});
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows()
{
Implicit = new OpenApiOAuthFlow()
{
AuthorizationUrl = new Uri($"{ configuration.GetValue<string>("IdentityUrl")}/connect/authorize"),
TokenUrl = new Uri($"{ configuration.GetValue<string>("IdentityUrl")}/connect/token"),
Scopes = new Dictionary<string, string>()
{
{ "weatherswaggerui", "Weather Swagger UI" }
},
}
}
});
options.OperationFilter<AuthorizeCheckOperationFilter>();
});
return services;
}
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
var identityUrl = configuration.GetValue<string>("IdentityUrl");
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = identityUrl;
options.RequireHttpsMetadata = false;
options.Audience = "weatherapi";
});
return services;
}
}
Lastly is the AuthorizeCheckOperationFilter.cs
public class AuthorizeCheckOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() ||
context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any();
if (!hasAuthorize) return;
operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });
var oAuthScheme = new OpenApiSecurityScheme
{
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme,
Id = "oauth2"
}
};
operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement
{
[oAuthScheme ] = new [] { "weatherswaggerui" }
}
};
}
}
again, any help, or recommendations on a guide would be greatly appreciated as google has not provided me with any results to fixing this issue. Im quite new to IdentityServer4 and am assuming its a small issue due with clients and ApiResources and ApiScopes. Thank you.
The swagger client needs to access the api and to do so it requires api scopes. What you have for swagger scopes are not doing this. Change the scopes for swagger client ‘weatherswaggerui’ to include the api scopes like this:
AllowedScopes = {"weatherapi.read"}

Swagger error - Unable to render this definition.The provided definition does not specify a valid version field

I deployed my .NET Core application to a Windows server and I have now an issue about opening the Swagger-UI in browser with the public ip-address.
I have no issue when I run Swagger-UI on localhost. However the UI doesn't load when I try to access through server's ip-address.
The error is:
Unable to render this definition The provided definition does not
specify a valid version field.
Please indicate a valid Swagger or OpenAPI version field. Supported
version fields are swagger: "2.0" and those that match openapi: 3.0.n
(for example, openapi: 3.0.0).
As it can be seen in the beginning of the Swagger.json file (The one that is running on the server), then the OpenAPI version field is set to 3.0.1. What I don't get is then why there's still an issue, when the version is clearly set and fulfilled.
I can even copy-paste the json-file into Editor Swagger and see the endpoints through that site.
My code:
namespace ParkShare
{
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.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContextPool<ParkShareDbContext>(options => options.UseSqlServer(Configuration
.GetValue<string>("ConnectionStrings:ParkShareDB")).UseLazyLoadingProxies());
services.AddSwaggerGen(c => {
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "ParkShare API",
Description = "BackEnd GET/POST/PATCH/DELETE"
});
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "JWT Authorization header using the Bearer scheme."
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] {}
}
});
});
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = false,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["JwtToken:Issuer"],
ValidAudience = Configuration["JwtToken:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtToken:SecretKey"])) //Configuration["JwtToken:SecretKey"]
};
});
//For identity, options changes the default password requirements
services.AddIdentity<AppUser, IdentityRole>(options =>
{
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = false;
})
.AddEntityFrameworkStores<ParkShareDbContext>()
.AddDefaultTokenProviders();
//Adding Authentication
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "JwtBearer";
options.DefaultChallengeScheme = "JwtBearer";
})
//Adding JWT Bearer
.AddJwtBearer("JwtBearer", JwtBearerOptions =>
{
JwtBearerOptions.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("AuthSettings:Key"))),
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5)
};
});
services.AddScoped<IUserModelingService, UserModeling>();
services.AddScoped<IUserPasswordService, UserPasswordService>();
services.AddScoped<IUserService, UserService>();
services.AddScoped<IContactService, ContactService>();
services.AddTransient<IMailService, SendMailService>();
// Email configurations
var emailConfig = Configuration.GetSection("EmailConfiguration").Get<EmailConfigurationModel>();
services.AddSingleton(emailConfig);
services
.AddCors()
.AddControllersWithViews()
.AddNewtonsoftJson();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
app.UseHttpsRedirection();
app.UseRouting();
// global cors policy
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Many thanks.

How to get OAuth2 OpenId token from Identity Server 4 for client that uses OWIN

I am using IdentityServer4 to get my OpenId tokens for my web app.
But my web app uses Owin for security. I cannot find any example samples of where this is done.
So this code works;
In my client;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using SIR.API.Caller.Helpers;
namespace SIR.API.Caller
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = Settings.SignInAsAuthenticationType // "Cookies";
});
app.UseOpenIdConnectAuthentication(openIdConnectOptions: new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "oidc",
Authority = Settings.AuthorityUrl1, //ID Server, "https://localhost:44314/"; https://localhost:44307/
ClientId = Settings.ClientId, // "SIR"
Scope = Settings.Scope, // "openid profile";
ResponseType = Settings.ResponseType, // "id_token code";
SignInAsAuthenticationType = Settings.SignInAsAuthenticationType,
//--------------------------------------// "Cookies";
RedirectUri = Settings.RedirectUri, // URL of website, http://localhost:50000/signin-oidc;
//RedirectUri = Settings.RedirectUri1, // URL of website, http://localhost:53200/signin-oidc;
RequireHttpsMetadata = Settings.RequireHttpsMetadata,
//--------------------------------------// true
ClientSecret = "secret"
});
app.Use(async (ctx, next) =>
{
var message = ctx.Authentication.User.Identity.IsAuthenticated
? $"User: {ctx.Authentication.User.Identity.Name}"
: "User Not Authenticated";
await next();
});
}
}
}
In my ID 4 server the startup is;
using System.Security.Cryptography.X509Certificates;
using IdentityServer4;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Mulalley.IdentityServer4.Helpers;
using QuickstartIdentityServer;
namespace Mulalley.IdentityServer4
{
public class Startup
{
// 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();
// configure identity server with in-memory stores, keys, clients and scopes
services.AddIdentityServer()
//.AddDeveloperSigningCredential()
.AddSigningCredential(new X509Certificate2(Settings.CertPath, Settings.Password))
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetUsers());
services.AddAuthentication()
.AddGoogle("Google", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
// register your IdentityServer with Google at https://console.developers.google.com
// enable the Google+ API
// set the redirect URI to http://localhost:port/signin-google
options.ClientId = "copy client ID from Google here";
options.ClientSecret = "copy client secret from Google here";
})
.AddOpenIdConnect("oidc", "OpenID Connect", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.Authority = "https://demo.identityserver.io/";
options.ClientId = "implicit";
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
});
}
// 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.UseIdentityServer();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
}
}
and the Config.cs is;
using IdentityServer4;
using IdentityServer4.Models;
using IdentityServer4.Test;
using System.Collections.Generic;
using System.Security.Claims;
namespace QuickstartIdentityServer
{
public class Config
{
// scopes define the resources in your system
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("SIR", "Service Inspection Report")
};
}
// clients want to access resources (aka scopes)
public static IEnumerable<Client> GetClients()
{
var baseUri = "http://localhost:53200/";
// client credentials client
return new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = { "SIR" },
AlwaysIncludeUserClaimsInIdToken = true
},
// resource owner password grant client
new Client
{
ClientId = "ro.client",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = { "SIR" },
AlwaysIncludeUserClaimsInIdToken = true
},
// OpenID Connect hybrid flow and client credentials client (MVC)
new Client
{
ClientId = "SIR",
ClientName = "SIR",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { baseUri + "signin-oidc" },
PostLogoutRedirectUris = { baseUri + "signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"SIR"
},
AllowOfflineAccess = true,
AlwaysIncludeUserClaimsInIdToken = true
}
};
}
public static List<TestUser> GetUsers()
{
return new List<TestUser>
{
new TestUser
{
SubjectId = "1",
Username = "alice",
Password = "password",
Claims = new List<Claim>
{
new Claim("name", "Alice"),
new Claim("website", "https://alice.com")
}
},
new TestUser
{
SubjectId = "2",
Username = "bob",
Password = "password",
Claims = new List<Claim>
{
new Claim("name", "Bob"),
new Claim("website", "https://bob.com")
}
}
};
}
}
}
And the question is how do I get the token in C# so I can have a look at it? And how do I set the GetClaimsFromUserInfoEndpoint = true which is not available in OWIN?
Are there any code samples I can look at with OWIN access to ID4?
EDIT: This code appears to be what I need: https://identitymodel.readthedocs.io/en/latest/client/token.html
However I put the code in and I get an access token which when I put it in jwt.io I get a message "Invalid Signature".
private static async Task<TokenResponse> GetClientCredentialsTokenResponse()
{
var client = new HttpClient();
var tokenRequest = new ClientCredentialsTokenRequest
{
Address = Settings.AuthorityUrl1 + "connect/token",
ClientId = Settings.ClientId,
ClientSecret = "secret",
Scope = "SIR"
};
return await client.RequestClientCredentialsTokenAsync(tokenRequest);
}
private static async Task<TokenResponse> GetTokenResponse()
{
var client = new HttpClient();
var tokenRequest = new TokenRequest
{
Address = Settings.AuthorityUrl1 + "connect/token",
GrantType = GrantType.ClientCredentials,
ClientId = Settings.ClientId,
ClientSecret = "secret",
Parameters =
{
{"scope", "SIR"}
}
};
return await client.RequestTokenAsync(tokenRequest);
}
private static void ThrowResponseException(TokenResponse response)
{
const string message = "Problem accessing the UserInfo endpoint";
if (response.Exception == null)
{
throw new Exception($"{message}: {response.Error}. {response.ErrorDescription}.");
}
throw new Exception(message, response.Exception);
}
}
}

Implement token authorization using Swagger UI in asp.net core 2.0

I want to use JWT bearer token authorization using Swagger in my application.
when I use Postman tool the authorization works fine. But when I try authorize using Swagger the controller method always return unauthorized even after passing the token.
Am I missing some line of code for accepting token? Code implemented is as follows.
public void ConfigureServices(IServiceCollection services)
{
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "XYZ API", Version = "v1", Description = "This is a API for XYZ client applications.", });
c.IncludeXmlComments(GetXmlCommentsPath());
c.AddSecurityDefinition("Bearer", new ApiKeyScheme { In = "header", Description = "Please paste JWT Token with Bearer + White Space + Token into field", Name = "Authorization", Type = "apiKey" });
//c.AddSecurityDefinition("basic", new BasicAuthScheme { Type = "basic" });
});
services.AddCors(config =>
{
var policy = new CorsPolicy();
policy.Headers.Add("*");
policy.Methods.Add("*");
policy.Origins.Add("*");
policy.SupportsCredentials = true;
config.AddPolicy("policy", policy);
});
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌​)
.RequireAuthenticatedUser().Build());
});
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
ValidAudience = "Audience",
ValidIssuer = "Issuer",
// ClockSkew = TimeSpan.FromMinutes(0)
ClockSkew = TimeSpan.Zero
};
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("policy");
app.UseAuthentication();
app.UseMvc();
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "XYZ API V1");
});
}
Controller
[Authorize("Bearer")]
[Route("api/[controller]")]
public class ValuesController : Controller
{
}
You also need to add the AddSecurityRequirement in swagger schema definition to indicate that the scheme is applicable to all operations in your API.
like below:
c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
{
{ "Bearer", new string[] { } }
});
So, the complete definition will be:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "XYZ API", Version = "v1", Description = "This is a API for XYZ client applications."});
c.IncludeXmlComments(GetXmlCommentsPath());
c.AddSecurityDefinition("Bearer", new ApiKeyScheme
{
In = "header",
Description = "Please paste JWT Token with Bearer + White Space + Token into field",
Name = "Authorization",
Type = "apiKey"
});
c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
{
{ "Bearer", new string[] { } }
});
});

IdentityServer4 Implicit GrantType throws Unauthorized_Client Error

When I run my project and try to login to get an access token, I get an Unauthorized_Client error on the browser or when testing with Postman. I'm fairly new to IdentityServer. This is my Configuration:
Config.cs
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Email(),
// custom identity resource with some consolidated claims
new IdentityResource("custom.profile", new[] { JwtClaimTypes.Name, JwtClaimTypes.Email, "location" })
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
//new ApiResource("NuB.hAPI", "Hospital API")
new ApiResource
{
Name = "NuB.HospitalSearch",
ApiSecrets = { new Secret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256()) },
UserClaims =
{
JwtClaimTypes.Name,
JwtClaimTypes.Email,
JwtClaimTypes.PhoneNumber,
JwtClaimTypes.Gender,
"NuB.HospitalSearch"
},
Scopes =
{
new Scope
{
Name = "NuB.HospitalSearch",
DisplayName = "Full access to Hospital Search App"
},
new Scope
{
Name = "openid",
DisplayName = "Read only access to Hospital Search App"
}
}
}
};
}
// clients want to access resources (aka scopes)
public static IEnumerable<Client> GetClients()
{
// client credentials client
return new List<Client>
{
new Client
{
ClientId = "mvcWeb",
ClientName = "MVC Web Client",
AllowedGrantTypes = GrantTypes.Implicit,
AccessTokenType = AccessTokenType.Jwt,
RequireConsent = true,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { "http://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"NuB.HospitalSearch"
},
AllowOfflineAccess = true
}
};
}
I am using ASP.NET Identity with EntityFrameworkCore with IdentityServer4 to do this. It may by a simple problem but kindly point me to the right direction.
Unauthorized_Client means that your client is trying to authencate to the Ids with a client that does not exist. You apear to have created a client called mvcWeb
That means that your client will need to use a client id of mvcWeb your client code should probably look something like this. Note options.ClientId = "mvcWeb";
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = settingsSetup.Authority;
options.RequireHttpsMetadata = false;
options.ClientId = "mvcWeb";
options.ClientSecret = "secret";
options.ResponseType = oidcConstants.ResponseTypes.CodeIdTokenToken;
options.Scope.Add("openid");
options.Scope.Add("profile");
});

Resources