401 Unauthorized with Azure b2c on Xamarin.Forms - c#

I have a Xamarin.Forms application that I'm using to connect to an App Service backend, and I'm attempting to authenticate using Auzre B2C JWT tokens.
Through various tutorials I have managed to get B2C setup using microsoft accounts, and I am able to create users, change passwords, and generate access tokens.
My next step was to add the [Authorize] attribute to my controller and attempt to pass that token to my app service and authorize users, but no matter what I try I get a 401 Unauthorized response from my service.
I'm adding the JWT token to the Authorization header of my HttpClient, and it's getting to the service.
I can paste my token into https://jwt.ms/, and it correctly tells me what's in my token.
I've implemented this code in an attempt to figure out what's wrong.
ConfigureServices in startup.cs looks like this:
public void ConfigureServices(IServiceCollection services) {
services.AddAuthentication(options => {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options => {
options.Audience = Configuration["Authentication:AzureAd:ClientId"];
options.Events = new JwtBearerEvents {
OnAuthenticationFailed = AuthenticationFailed
};
options.Authority = $"https://{tenant name}.b2clogin.com/{tenant id}/{Configuration["Authentication:AzureAd:Policy"]}";
options.Events = new JwtBearerEvents {
OnAuthenticationFailed = ctx =>
{
ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
message += "From OnAuthenticationFailed:\n";
message += FlattenException(ctx.Exception);
return Task.CompletedTask;
},
OnChallenge = ctx =>
{
message += "From OnChallenge:\n";
ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
ctx.Response.ContentType = "text/plain";
return ctx.Response.WriteAsync(message);
},
OnMessageReceived = ctx =>
{
message = "From OnMessageReceived:\n";
ctx.Request.Headers.TryGetValue("Authorization", out var BearerToken);
if (BearerToken.Count == 0)
BearerToken = "no Bearer token sent\n";
message += "Authorization Header sent: " + BearerToken + "\n";
return Task.CompletedTask;
},
OnTokenValidated = ctx =>
{
Debug.WriteLine("token: " + ctx.SecurityToken.ToString());
return Task.CompletedTask;
}
};
});
services.AddMvc();
}
Configure looks like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
IdentityModelEventSource.ShowPII = true;
} else {
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc();
}
And I've also added this call to AuthenticationFailed, so I'll know if my authentication is working or not:
Task AuthenticationFailed(AuthenticationFailedContext arg) {
Console.WriteLine(arg.Exception.Message);
return Task.FromResult(0);
}
With my current setup I'm getting a 401 error from the server, and that's right after it hits the OnChallenge event wired up in Startup.cs. According to the link above, that's what gets called right before it returns a 401 to the user, so it seems like the service is receiving the proper token, and authenticating, but maybe I don't have the correct rights set up?
I'm not sure where to go from here, but any guidance would be appreciated.
Edit:
As mentioned in a comment below, I was able to curl my website using the access token generated after logging in through my app like this:
curl https://mywebsite.azurewebsites.net/api/Values -i --header "Authorization: Bearer [TOKEN]"
And that seems to work with no issue, so it seems like it's something with how I'm making a call to the controller through my app, not the authentication itself.
Edit 2 (solution):
So, as per Edit 1, I was correct in that it was just how I was adding the token to the authorization header. It wasn't my brightest moment, but I wasn't calling .Value on the claim that contained my Access Token. I was only calling .ToString() on the claim itself, so the "token" was actually the entire claim text "Access Token: ". I didn't think much of it at the time when I was debugging my service, because I didn't realize it shouldn't have that text there.
Once I corrected that issue the service started working as expected.
So, in the end, I guess it was all working as expected. I was, in fact, not sending the expected token, so I was ... unauthorized.
As requested the line of code that I had to change was this:
So, this won't be 100% applicable to most because I'm using a business library called CSLA, but the idea is the same regardless.
After my b2c call returns the token I store it in the ApplicationContext.User.Identity that's built into the CSLA library. That allows me to get the access token claim later. The important part to take away from this is that I'm storing the token some place that I can access it later when I want to add it to the authorization header.
Later, when I'm making the call with my httpclient I need to get that token, so originally, I was doing this:
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ((ClaimsIdentity)ApplicationContext.User.Identity).Claims.FirstOrDefault(c => c.Type == "AccessToken").ToString());
This isn't correct. This was sending the "token" as with value "Access Token: [token value]. Essentially, it was adding the words "Access Token" to the token I needed to authenticate, and that was failing, because the words "Access Token" are not actually supposed to be part of the token you use to authenticate.
After I changed my call to this:
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ((ClaimsIdentity)ApplicationContext.User.Identity).Claims.FirstOrDefault(c => c.Type == "AccessToken").Value);
It started getting only the token value, and when that was added to the authorization header, it worked just fine.

Edit 2 explains the answer to my problem.
I wasn't adding the token correctly to the authorization header, so the service wasn't able to authenticate the token, or rather, it saw the token as invalid.

Related

How to integrate swagger with Azure Active Directory OAuth

I'm trying to setup Swagger in my AspNetCore 2.1 application using Azure Active Directory V2 but I cannot seem to get it right. I am able to configure the setup so that swagger prompts, redirects and successfully authenticates my client/user but when passing the bearer token to the server results in the error Bearer error="invalid_token", error_description="The signature is invalid". I have created a GitHub repository with the project I am trying to get work with all its configuration (https://github.com/alucard112/auth-problem)
I have managed to get the V1 endpoint working, by setting the resource to the Client Id of the AAD app, which results in the JWT token having the 'aud' set to the app client Id. In the V2 endpoint the 'aud' is being set to what I think is the Graph API resource '00000003-0000-0000-c000-000000000000'. I believe this is my problem at the moment, although am not 100 % sure. The V2 endpoints don't seem to have a way to define the audience like the V1 did unless of course there is some oversight from my side.
My Startup file is structured as follows:
The authentication is setup as the following:
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
options.Authority = $"https://login.microsoftonline.com/{tenantId}";
options.TokenValidationParameters = new TokenValidationParameters
{
// In multi-tenant apps you should disable issuer validation:
ValidateIssuer = false,
// In case you want to allow only specific tenants,
// you can set the ValidIssuers property to a list of valid issuer ids
// or specify a delegate for the IssuerValidator property, e.g.
// IssuerValidator = (issuer, token, parameters) => {}
// the validator should return the issuer string
// if it is valid and throw an exception if not
};
});
And the swagger is setup as follows:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info
{
Title = "Protected Api",
});
c.OperationFilter<SecurityRequirementsOperationFilter>();
//IMATE - StevensW
// Define the OAuth2.0 scheme that's in use (i.e. Implicit Flow)
c.AddSecurityDefinition("oauth2", new OAuth2Scheme
{
Type = "oauth2",
Flow = "implicit",
AuthorizationUrl = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize",
TokenUrl = $"https://login.microsoftonline.com/common/{tenantId}/v2.0/token",
Scopes = new Dictionary<string, string>
{
{ "openid", "Unsure" },
{ "profile", "Also Unsure" }
}
});
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.OAuthClientId(Configuration.GetValue<string>("AzureAd:ClientId"));
c.OAuthAppName("Protected API");
// c.OAuthUseBasicAuthenticationWithAccessCodeGrant();
// NEVER set the client secret here. It will ve exposed in the html of the swagger page if you "view source" and its not needed for OpenID Auth
// c.OAuthClientSecret(Configuration.GetValue<string>("AzureAd:ClientId"));
});
I am hoping to configure the swagger UI to use AAD's V2 endpoint and allow for a multi-tenant login that allows successfully authenticated API calls to be executed. Any help or direction would be greatly appreciated.
I ended up fixing the problem I was having. Working through this post helped me understand my mistakes.
The first mistake was my actual AAD app registration. I had not set a scope for the application under "Expose an API". Because they deprecated the resource property in V2, the way you would set the resource was to create a scope with the format api"//{application ID}/{scope_name}. After I made this change my AAD application was now correctly configured.
After that, I needed to add an additional section to my startup file:
return services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
// This is an Azure AD v2.0 Web API
options.Authority += "/v2.0";
// The valid audiences are both the Client ID (options.Audience) and api://{ClientID}
options.TokenValidationParameters.ValidAudiences = new string[] { options.Audience, $"api://{options.Audience}" };
options.TokenValidationParameters.ValidateIssuer = false;
});
Note: the link above provided an alternative solution to turning off the validation of the issuer if anyone is interested.
My AppSettings file was also simplified by only needing to define the Instance, TenantId, and ClientId.
Then from a swagger perspective, I just needed to add an additional scope to the security definition matching the one I created in my AAD application.
c.AddSecurityDefinition("oauth2", new OAuth2Scheme
{
Type = "oauth2",
Flow = "implicit",
AuthorizationUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
TokenUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/token",
Scopes = new Dictionary<string, string>
{
{ "openid", "Sign In Permissions" },
{ "profile", "User Profile Permissions" },
{ $"api://{clientId}/access_as_user", "Application API Permissions" }
}
});
After these changes my application is now working as expected.
for v2 endpoint, update the accessTokenAcceptedVersion in Manifest of AAD from null to 2. It will work.

Azure Bot project with client and server in same web app

I've made an Azure bot application using the BotFramework v4 and used the WebChat control as an interface. I noticed that the bot server's dotnetcore app had a wwwroot folder with a placeholder HTML page in it, so thought it might be expedient to host the webchat client there. But now seems counter-intuitive that my webchat client is using DirectLine to send activities back to the same back-end that served it.
I had chosen the webchat client because I need to customise the appearance of the client. I also need the MVC app that serves the bot client to include Azure Active Directory B2C authentication (which it does). Users should see the webchat client before and after authentication but the bot back-end (handling the activities) needs to know whether the user is logged in and modify its behaviour accordingly (and I am struggling to achieve that part with DirectLine).
So my first question (ever on StackOverflow) is: With the Bot back-end and the webchat client front-end being hosted in the same, single Azure web app, is it necessary to use DirectLine, or is there a simpler way of doing this?
Relevant code in my Startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
app.UseStaticFiles(); // to allow serving up the JS, CSS, etc., files.
app.UseBotFramework(); // to add middleware to route webchat activity to the bot back-end code
app.UseSession(); // to enable session state
app.UseAuthentication(); // to enable authentication (in this case AAD B2C)
app.UseMvcWithDefaultRoute(); // to add MVC middleware with default route
}
Also in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// standard code to add HttpContextAssessor, BotServices, BotConfigs and memory storage singletons ommitted for brevity ...
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddAzureAdB2C(options => Configuration.Bind("Authentication:AzureAdB2C", options))
.AddCookie();
services.AddMvc();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromHours(1);
options.CookieHttpOnly = true;
});
// Create and add conversation state.
var conversationState = new ConversationState(dataStore);
services.AddSingleton(conversationState);
var userState = new UserState(dataStore);
services.AddSingleton(userState);
services.AddBot<MyBot>(options =>
{
options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);
options.ChannelProvider = new ConfigurationChannelProvider(Configuration);
// Catches any errors that occur during a conversation turn and logs them to currently
// configured ILogger.
ILogger logger = _loggerFactory.CreateLogger<RucheBot>();
options.OnTurnError = async (context, exception) =>
{
logger.LogError($"Exception caught : {exception}");
await context.SendActivityAsync("Sorry, it looks like something went wrong.");
};
});
}
My controller's Index method:
public async Task<ActionResult> Index()
{
string userId;
if (User.Identity.IsAuthenticated)
{
string aadb2cUserId = User.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier").Value;
Users.EnsureAccountExists(aadb2cUserId); // ensure account with given AAD identifier is know locally (by creating it if not)
userId = $"ia_{aadb2cUserId}";
}
else
{
userId = $"na_{Guid.NewGuid()}";
}
HttpClient client = new HttpClient();
string directLineUrl = $"https://directline.botframework.com/v3/directline/tokens/generate";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, directLineUrl);
// TODO: put this in the config somewhere
var secret = "<the secret code from my bot's DirectLine channel config in the Azure portal>";
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", secret);
string jsonUser = JsonConvert.SerializeObject(new { User = new { Id = userId } });
request.Content = new StringContent(jsonUser, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
string token = string.Empty;
if (response.IsSuccessStatusCode)
{
var body = await response.Content.ReadAsStringAsync();
token = JsonConvert.DeserializeObject<DirectLineToken>(body).token;
}
var config = new ChatConfig()
{
Token = token,
UserId = userId,
};
return View(config);
}
And finally the code in the associated view:
<div id="webchat"></div>
<script type="text/javascript">
...
/// Called asynchronously during the page load
function renderWebChat( withSound )
{
var webchatOptions =
{
directLine: window.WebChat.createDirectLine( { secret: '#Model.Token'} ),
userID: '#Model.UserId'
};
if ( withSound )
{
webchatOptions.webSpeechPonyfillFactory = window.WebChat.createBrowserWebSpeechPonyfillFactory();
}
window.WebChat.renderWebChat( webchatOptions, document.getElementById( 'webchat' ) );
document.querySelector( '#webchat > *' ).focus();
}
</script>
I'm going to disagree with Nicolas R a little bit. When it comes to directly accessing your bot, you might like to have a look at this: https://www.npmjs.com/package/offline-directline
There's also the option of hosting a bot in the browser, which I think may facilitate the sort of direct communication you're looking for.
Long question, but the answer will be a lot shorter!
So my first question (ever on StackOverflow) is: With the Bot back-end
and the webchat client front-end being hosted in the same, single
Azure web app, is it necessary to use DirectLine, or is there a
simpler way of doing this?
Yes, it is necessary. In fact, all the channels types are using the Bot Connector to communicate with your backend (your bot code), there is no direct access possible. There are a lot of reasons for that, one is for example the billing!

Access to user credentials in ASP.NET Core middleware

In ASP.NET core (2.1), running on a windows, I am using HttpSys configured with the following authentication schemes:
builder.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM;
options.Authentication.AllowAnonymous = true;
})
Then in my Startup.Configure() method I am attempting to access the user credentials of the client calling the uri "/sensitiveOperation" as follows:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
app.MapWhen(context => context.Request.Path.Equals("/sensitiveOperation") && context.Request.Method.Equals(HttpMethods.Put), subApp =>
{
subApp.Run(async (context) =>
{
if (context.User.Identity.Name == "admin")
{
await context.Response.WriteAsync("Performing sensitive operation.");
// .. Do Sensitive operation....
}
});
});
The example is slightly vulgarised, but the main point is that context.User.Identity.Name is always empty where I would expect to see the name of the AD account which is making the call. Note that the call is done in powershell as follows:
Invoke-WebRequest -Uri http://localhost:5555/sensitiveOperation -Method Put -UseDefaultCredentials
I could put this code in a controller and use the [Authorize] attribute to get the credentials but I would prefer to do this operation before hitting the Mvc pipeline. Is there any way to get the user at this early stage of the pipeline ?
Change AllowAnonymous
options.Authentication.AllowAnonymous = false;
If you have anonymous on, and you're not prompting for authentication then the browser isn't going to authenticate. Even if you do send creates asp.net isn't going to get them unless there's an Authenticate attribute on the controller/method or, if you're going the function route, you call signin.
If you would not want to set AllowAnonymous as false, you could try context.ChallengeAsync to authenticate the request based on Credential.
Here are the code:
app.MapWhen(context => context.Request.Path.Equals("/sensitiveOperation") && context.Request.Method.Equals(HttpMethods.Put), subApp =>
{
subApp.Run(async (context) =>
{
var authService = context.RequestServices.GetRequiredService<IAuthorizationService>();
if (!context.User.Identity.IsAuthenticated)
{
//await context.ChallengeAsync("Windows"); //Option1
//await context.ChallengeAsync(); //Option2
await context.ChallengeAsync(HttpSysDefaults.AuthenticationScheme); //Option3
}
if (context.User.Identity.Name == "admin")
{
await context.Response.WriteAsync("Performing sensitive operation.");
// .. Do Sensitive operation....
}
});
});
Note, for this way, subApp.Run will run twice, first request is UnAuthenticated, and it will challenge the credentail, second request is Authenticated and context.User.Identity.Name will have value. This process is back-end, this would not be reflected in powershell.
I am using .NET Core 3.0 and in my custom middleware I was able to get the UserId with this code:
httpContext.User.Identity.IsAuthenticated
? new Guid(httpContext.User.Claims.Where(c => c.Type == ClaimTypes.NameIdentifier).First().Value)
: Guid.Empty

Do not receive refresh token with OpenIddict

I have a web api project based on .net core 2.0.
I followed pretty much the very good example on http://kevinchalet.com/2017/01/30/implementing-simple-token-authentication-in-aspnet-core-with-openiddict/.
The code that returns the SignIn() result for the auth. method looks like so:
if (request.IsPasswordGrantType())
{
// (...)
if (useraccount != null && useraccount.Failcount <= AppConstants.AuthMaxAllowedFailedLogin)
{
var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme, OpenIdConnectConstants.Claims.Name, OpenIdConnectConstants.Claims.Role);
identity.AddClaim(OpenIdConnectConstants.Claims.Subject, AppConstants.AuthSubjectClaim, OpenIdConnectConstants.Destinations.AccessToken);
identity.AddClaim(OpenIdConnectConstants.Claims.Name, useraccount.Username, OpenIdConnectConstants.Destinations.AccessToken);
return SignIn(new ClaimsPrincipal(identity), OpenIdConnectServerDefaults.AuthenticationScheme);
}
// (...)
}
My startup code looks like so:
services.AddDbContext<DbContext>(options =>
{
options.UseInMemoryDatabase(nameof(DbContext));
options.UseOpenIddict();
});
services.AddOpenIddict(options =>
{
options.AddEntityFrameworkCoreStores<DbContext>();
options.AddMvcBinders();
options.EnableTokenEndpoint(DcpConstants.ApiTokenRoute);
options.AllowPasswordFlow();
options.AllowRefreshTokenFlow();
options.SetAccessTokenLifetime(TimeSpan.FromHours(1));
options.SetRefreshTokenLifetime(TimeSpan.FromDays(1));
options.DisableHttpsRequirement();
});
services.AddAuthentication(options =>
{
options.DefaultScheme = OAuthValidationDefaults.AuthenticationScheme;
}).AddOAuthValidation();
Now, when I send the post request with the following params:
username: foo#bar.com
password: myPassword
grant_type: password
scope: openid profile offline_access
I only receive scope, token_type, access_token, expires_in and id_token and no refresh_token.
What am I missing?
Returning a refresh token with the password is definitely allowed by the OAuth2 specification and thus, fully supported by OpenIddict.
For a refresh token to be returned by OpenIddict, you have to grant the special offline_access scope when calling SignIn. E.g:
if (request.IsPasswordGrantType())
{
// (...)
if (useraccount != null && useraccount.Failcount <= AppConstants.AuthMaxAllowedFailedLogin)
{
var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme, OpenIdConnectConstants.Claims.Name, OpenIdConnectConstants.Claims.Role);
identity.AddClaim(OpenIdConnectConstants.Claims.Subject, AppConstants.AuthSubjectClaim, OpenIdConnectConstants.Destinations.AccessToken);
identity.AddClaim(OpenIdConnectConstants.Claims.Name, useraccount.Username, OpenIdConnectConstants.Destinations.AccessToken);
var ticket = new AuthenticationTicket(
new ClaimsPrincipal(identity),
new AuthenticationProperties(),
OpenIdConnectServerDefaults.AuthenticationScheme);
// You have to grant the 'offline_access' scope to allow
// OpenIddict to return a refresh token to the caller.
ticket.SetScopes(OpenIdConnectConstants.Scopes.OfflineAccess);
return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
}
// (...)
}
Note that you'll also have to handle the grant_type=refresh_token requests in your controller. Here's an example using Identity: https://github.com/openiddict/openiddict-samples/blob/dev/samples/RefreshFlow/AuthorizationServer/Controllers/AuthorizationController.cs#L75-L109
options.AllowPasswordFlow();
Refresh Token cannot be used with Password flow, as the user is never redirected to login at Auth Server in this flow and so can’t directly authorize the application:
If the application uses the username-password OAuth authentication flow, no refresh token is issued, as the user cannot authorize the application in this flow. If the access token expires, the application using username-password OAuth flow must re-authenticate the user.

How do I fix a 403 using JwtBearerAuthentication?

I'm trying to understand how to delve into the automagic I get when I configure the hell out of asp.net. I'm currently translating a small api from asp.net web-api 2 to asp.net core. I'm not sure where the 403 is coming from in this configuration or how to fix it. Right now the majority of the api endpoint just need a valid token and do not need to check for any specific claim in the token. So for all my authenticated controllers I get a 403 response that should be a 200, when using a valid bearer token. Also right now I use asymmetric keys with Auth0 as the provider.
Startup.cs configure method I'm using to validate the JWT bearer tokens.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
//Middleware added here order matters
//TODO formatter settings https://docs.asp.net/en/latest/mvc/models/formatting.html
//samples to check
//https://auth0.com/docs/server-apis/webapi-owin
//https://github.com/auth0-samples/auth0-aspnetcore-webapi-rs256
var options = new JwtBearerOptions
{
Audience = Configuration["auth0:clientId"]
,Authority = $"https://{Configuration["auth0:domain"]}/"
,Events = new JwtBearerEvents() // just a pass through to log events
};
app.UseJwtBearerAuthentication(options);
// Very hacky to catch invaild tokens https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/issues/191
// issue says the need for the required hack is fixed but it's been still happening. Issue about the fix https://github.com/aspnet/Security/issues/411
app.Use(next => async context => {
try
{
await next(context);
}
catch
{
// If the headers have already been sent, you can't replace the status code.
// In this case, throw an exception to close the connection.
if (context.Response.HasStarted)
{
throw;
}
context.Response.StatusCode = 401;
}
});
app.UseMvc();
// TODO global exception handling https://github.com/dotnet/corefx/issues/6398
app.UseSwaggerGen();
app.UseSwaggerUi();
}
}
It seems your token middleware is not executed to validate incoming requests.
Try setting the token middleware to run automaticly.
var options = new JwtBearerOptions
{
//other configurations..
AutomaticAuthenticate = true;
};
You can also use attributes to specify the authentication scheme in the controllers.
[Authorize(AuthenticationSchemes = "MyAuthenticationScheme")]
Read more about it here: Limiting identity by scheme
The problem was with the policy in the ConfigureServices section. The simplest policy is all I need at the moment.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc(c =>
{
// TODO implement this abstract class c.Filters.Add(typeof(ExceptionFilterAttribute));
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
c.Filters.Add(new AuthorizeFilter(policy));
c.Filters.Add(typeof(ValidateModelFilter));
});

Categories