On my current webapi project I have set a swagger oauth security definition with implicit flow and authorize url https://login.microsoftonline.com/ + tenant Id. The scopes are the same as in the github exapmle for the Swashbuckle.AspNetCore nuget , this is the link https://github.com/domaindrivendev/Swashbuckle.AspNetCore. But when i try to authenticate on swagger online editor, this one https://editor.swagger.io/, I can't get the token back and get a 404 exception. What do I need to set in my azure portal registered app to return a token back to the online swagger editor ?
According to your description, I created my .Net Core 2.0 Web API application and created the AAD app on Azure Portal. The configuration under ConfigureServices would look like this:
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
// Configure the app to use Jwt Bearer Authentication
.AddJwtBearer(jwtOptions =>
{
jwtOptions.Authority = string.Format(CultureInfo.InvariantCulture, "https://sts.windows.net/{0}/", Configuration["AzureAd:TenantId"]);
jwtOptions.Audience = Configuration["AzureAd:WebApiApp:ClientId"];
});
For Swagger UI, I also created a new AAD app on Azure Portal and add permissions to access the Web API app as follows:
Then, I added the following code snippet for defining the OAuth2.0 scheme as follows:
// Define the OAuth2.0 scheme that's in use (i.e. Implicit Flow)
c.AddSecurityDefinition("oauth2", new OAuth2Scheme
{
Type = "oauth2",
Flow = "implicit",
AuthorizationUrl = string.Format(CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}/oauth2/authorize", Configuration["AzureAd:TenantId"]),
Scopes = new Dictionary<string, string>
{
{ "user_impersonation", "Access Bruce-WebAPI-NetCore" }
}
});
// Enable operation filter based on AuthorizeAttribute
c.OperationFilter<SecurityRequirementsOperationFilter>();
And use the following code for initializing the middleware to serve swagger-ui.
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.ConfigureOAuth2(
Configuration["AzureAd:SwaggerApp:ClientId"],
Configuration["AzureAd:SwaggerApp:ClientSecret"],
Configuration["AzureAd:SwaggerApp:RedirectUri"], //http://localhost:30504/swagger/o2c.html
"Bruce-WebAPI-NetCore-Swagger",
additionalQueryStringParameters: new Dictionary<string, string>(){
{ "resource",Configuration["AzureAd:WebApiApp:ClientId"]}
});
});
Test:
but it still returns AADSTS50001 Resource identifier is not provided
During my processing, I encountered the similar issue. At last, I found that the resource parameter is not specified. Then, I set the additionalQueryStringParameters parameter for ConfigureOAuth2. Here is my code sample WebAPI-Swagger-NetCore, you could refer to it.
Moreover, for adding access scopes to your resource application (Web API), you could follow the Adding access scopes to your resource application section under here. Also, my SecurityRequirementsOperationFilter did not assign the scope requirements to operations based on AuthorizeAttribute provided here. You could specific the supported scopes under AddSecurityDefinition, then for your controller or action you could mark it as [Authorize(AuthenticationSchemes = "Bearer", Policy = "{scope}")]. Details, you could follow this sample.
Related
Porting from .NET Core 3 to .NET Core 5 Authentication, I am required to replace services.AddSignIn (deprecated) by services.AddMicrosoftIdentityWebAppAuthentication or other related MicrosoftIdentity extensions. I need to support both OpenId user login and Bearer token policies for API access. These both worked with services.AddSignIn but I can't get this combination working with the new MicrosftIdentity extensions.
I have a .Net Core Blazor Server with OpenId login to Azure AD B2C. This works fine as:
services.AddMicrosoftIdentityWebAppAuthentication(
configuration,
aadB2CConfigName,
OpenIdConnectDefaults.AuthenticationScheme,
CookieAuthenticationDefaults.AuthenticationScheme,
true);
But when I add the Bearer Token handling directly after it, as follows, then it overrides the OpenId, so only the Bearer API works (and vice versa):
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(
options =>
{
configuration.Bind("AzureAd", options);
options.ForwardDefaultSelector = ctx =>
ctx.Request.Path.StartsWithSegments("/api", System.StringComparison.InvariantCulture)
? JwtBearerDefaults.AuthenticationScheme
: null;
options.Authority = configuration["AzureAd:Authority"];
options.TokenValidationParameters.NameClaimType = "name";
options.TokenValidationParameters.RoleClaimType = "roles";
}, options =>
{
configuration.Bind(aadB2CConfigName, options);
});
For completeness, followed by (worked fine in .net core 3)
services.AddControllersWithViews()
.AddMicrosoftIdentityUI();
services.AddAuthorization(options =>
{
options.AddPolicy("Tst1AuthPolicy", policy => policy.RequireRole("Tst1AppRole"));
options.AddPolicy("Tst2AuthPolicy", policy => policy.RequireRole("Tst2AppRole"));
});
The chaining of extension methods does not seem to work as it did with AddSignIn. How do I make both of these work again in parallel in the new .net core 5 context? i.e. OpenId as default, and Bearer Tokens when the WebApi (/api) is hit.
Got it working as follows. I don't feel totally confident that this is the intended/best usage here, but it works:
Replace the above "null" as follows with the alternate login scheme, which is the oreo cookie scheme in our case:
options.ForwardDefaultSelector = ctx =>
ctx.Request.Path.StartsWithSegments("/api", System.StringComparison.InvariantCulture)
? JwtBearerDefaults.AuthenticationScheme
: CookieAuthenticationDefaults.AuthenticationScheme;
This will probably mean that, instead of a HTTP-Status error, I get a HTML login page if the Bearer Token fails, so there must be a better way ... if anybody cares to chime in.
Have you tried explicitly calling out the authentication scheme on the controllers?
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Microsoft.AspNetCore.Components.Route("api/[Controller]")]
[ApiController]
public class LoginController :ControllerBase
{
}
So, to give you a general overview of what I am trying to achieve, I have a web application which
uses AAD authentication, and so users need to be signed in to a Microsoft organizational account in
order to use most of the controllers implemented in the web app (which targets .NET Core).
Visual Studio offers a template for this kind of web app setup. This
template project seems to obtain the user’s identity as a "ClaimsIdentity" (System.Security.Claims.ClaimsIdentity), which is ok so far, as long
as the user is AAD authenticated.
I also have a .NET Core Web API solution which the web app needs to make calls to on behalf of the
logged in user. So, I have a web app which signs in the user to AAD and then a web API (which the
web app calls) which has controller end points that expect an AAD authenticated request.
For this to work, my understanding is that the web app needs to include the signed in identity that
Microsoft, (which in this case is the security provider) provided it with, inside the header of the
request that it makes to the API. The API would then be able to view user claims and act accordingly.
The problem is here. As a header, I believe I need to provide the access token that Microsoft sends
to the web app.. however I cannot locate this token. All I can extract from User or User.Identity, are the claims. How
can I call a separate API on behalf of these claims? Do I need to completely disregard the template
that Microsoft provided and just make a call to the /token endpoint? I would just like to do this the right way :)
This is the ConfigureServices method in the web app Startup class:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
This is where I would like to call the external web API on behalf of the logged in AAD to get the
required data:
public IActionResult Index()
{
var user = User.Identity as ClaimsIdentity;
var request = (HttpWebRequest)WebRequest.Create("http://localhost:4110/data");
request.Headers["Authorization"] = "bearer " + getAccessToken_using_user;
var response = (HttpWebResponse)request.GetResponse();
var dataString = new StreamReader(response.GetResponseStream()).ReadToEnd();
return View();
}
Of course, my intention is to replace "getAccessToken_using_user" with the access token that Microsoft supposedly provides the web app with, as illustrated in their diagram.
You can use MSAL to get the access token for the downstream API.
https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/on-behalf-of#practical-usage-of-obo-in-an-aspnet--aspnet-core-application
This is a full example with on behalf flow:
https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2/tree/master/2.%20Web%20API%20now%20calls%20Microsoft%20Graph
public static IServiceCollection AddProtectedApiCallsWebApis(this IServiceCollection services, IConfiguration configuration, IEnumerable<string> scopes)
{
...
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
options.Events.OnTokenValidated = async context =>
{
var tokenAcquisition = context.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>();
context.Success();
// Adds the token to the cache, and also handles the incremental consent and claim challenges
tokenAcquisition.AddAccountToCacheFromJwt(context, scopes);
await Task.FromResult(0);
};
});
return services;
}
private async Task GetTodoList(bool isAppStarting)
{
...
//
// Get an access token to call the To Do service.
//
AuthenticationResult result = null;
try
{
result = await _app.AcquireTokenSilent(Scopes, accounts.FirstOrDefault())
.ExecuteAsync()
.ConfigureAwait(false);
}
...
// Once the token has been returned by MSAL, add it to the http authorization header, before making the call to access the To Do list service.
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
// Call the To Do list service.
HttpResponseMessage response = await _httpClient.GetAsync(TodoListBaseAddress + "/api/todolist");
...
}
I can't seem to make my .net core web API work with swashbuckle, OAuth2 with an application flow. When I click the Authorize button, Fiddler shows that the call is OK and my local IdentityServer(4) replies with an access_token. That's all great and all but I don't think Swagger picks this up, there's nothing happening and I can't trigger my controller methods without getting a 401. I see no cookies, nothing. I'm sure I'm missing something super trivial. Can someone help me out?
Relevant code :
ConfigureServices in Startup.cs
c.AddSecurityDefinition("oauth2", new OAuth2Scheme
{
Type = "oauth2",
Flow = "application",
TokenUrl = "http://localhost:61798/connect/token",
Scopes = new Dictionary<string, string>
{
{ "readAccess", "Access read operations" },
{ "writeAccess", "Access write operations" }
}
});
Configure in Startup.cs
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = "http://localhost:61798",
RequireHttpsMetadata = false,
ApiName = "api1",
AutomaticAuthenticate = true, //Doesn't change anything...
});
....
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "V1 Docs");
c.ConfigureOAuth2("Swagger", "swaggersecret", "swaggerrealm", "Swagger UI");
});
My IdentityServer is configured OK. I can call this API in Postman and a simple client without any problem. My only problem is Swagger (Swashbuckle.AspNetCore 1.0.0).
We have a very similar setup for a current project. Our rest api is secured with jwt bearer authentication and azure ad b2c. In this case there is no way swagger to pick up automatically the token.
This solution works perfect for us: https://stackoverflow.com/a/39759152/536196
services.AddSwaggerGen(c =>
{
c.OperationFilter<AuthorizationHeaderParameterOperationFilter>();
});
After that when you run your swagger UI, you should see an additional field for the token.
I have Auth Service hosted on some url. All my microservices requested validation to auth on each requests. In StartUp.cs of each services I have
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = WebConfigurationManager.AppSettings["IdentityServerURL"],
ValidationMode = ValidationMode.ValidationEndpoint,
//ValidationMode = ValidationMode.Local,
RequiredScopes = new[] { "user-api" },
});
It works fine! And in my controller's method in this case I have as you can see
{role: consumer}
But if I change
ValidationMode = ValidationMode.Local,
My request doesn't pass Authorization because values of roles has prefixes
And according to this my request doesn't pass autorization. What should I do in case
ValidationMode = ValidationMode.Local
to have normal value of claims role?
Microsoft apply a claims mapping when the token is received. To remove this default mapping, add this to your Configuration method at startup:
JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();
For more information:
How to use InboundClaimTypeMap for claim mapping?
Update of System.IdentityModel.Tokens.Jwt causing breaking change in IdentityServer3 Client
Question
How do we use a bearer token with ASP.NET 5 using a username and password flow? For our scenario, we want to let a user register and login using AJAX calls without needing to use an external login.
To do this, we need to have an authorization server endpoint. In the previous versions of ASP.NET we would do the following and then login at the ourdomain.com/Token URL.
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14)
};
In the current version of ASP.NET, though, the above doesn't work. We've been trying to figure out the new approach. aspnet/identity example on GitHub, for instance, configures Facebook, Google, and Twitter authentication but does not appear to configure a non-external OAuth authorization server endpoint, unless that's what AddDefaultTokenProviders() does, in which case we're wondering what the URL to the provider would be.
Research
We've learned from reading the source here that we can add "bearer authentication middleware" to the HTTP pipeline by calling IAppBuilder.UseOAuthBearerAuthentication in our Startup class. This is a good start though we're still not sure of how to set its token endpoint. This didn't work:
public void Configure(IApplicationBuilder app)
{
app.UseOAuthBearerAuthentication(options =>
{
options.MetadataAddress = "meta";
});
// if this isn't here, we just get a 404
app.Run(async context =>
{
await context.Response.WriteAsync("Hello World.");
});
}
On going to ourdomain.com/meta we just receive our hello world page.
Further research showed that we can also use the IAppBuilder.UseOAuthAuthentication extension method, and that it takes a OAuthAuthenticationOptions parameter. That parameter has a TokenEndpoint property. So though we're not sure what we're doing, we tried this, which of course didn't work.
public void Configure(IApplicationBuilder app)
{
app.UseOAuthAuthentication("What is this?", options =>
{
options.TokenEndpoint = "/token";
options.AuthorizationEndpoint = "/oauth";
options.ClientId = "What is this?";
options.ClientSecret = "What is this?";
options.SignInScheme = "What is this?";
options.AutomaticAuthentication = true;
});
// if this isn't here, we just get a 404
app.Run(async context =>
{
await context.Response.WriteAsync("Hello World.");
});
}
In other words, in going to ourdomain.com/token, there is no error there is just again our hello world page.
EDIT (01/28/2021): AspNet.Security.OpenIdConnect.Server has been merged into OpenIddict as part of the 3.0 update. To get started with OpenIddict, visit documentation.openiddict.com.
Okay, let's recap the different OAuth2 middleware (and their respective IAppBuilder extensions) that were offered by OWIN/Katana 3 and the ones that will be ported to ASP.NET Core:
app.UseOAuthBearerAuthentication/OAuthBearerAuthenticationMiddleware: its name was not terribly obvious, but it was (and still is, as it has been ported to ASP.NET Core) responsible for validating access tokens issued by the OAuth2 server middleware. It's basically the token counterpart of the cookies middleware and is used to protect your APIs. In ASP.NET Core, it has been enriched with optional OpenID Connect features (it is now able to automatically retrieve the signing certificate from the OpenID Connect server that issued the tokens).
Note: starting with ASP.NET Core beta8, it is now namedapp.UseJwtBearerAuthentication/JwtBearerAuthenticationMiddleware.
app.UseOAuthAuthorizationServer/OAuthAuthorizationServerMiddleware: as the name suggests, OAuthAuthorizationServerMiddleware was an OAuth2 authorization server middleware and was used to create and issue access tokens. This middleware won't be ported to ASP.NET Core: OAuth Authorization Service in ASP.NET Core.
app.UseOAuthBearerTokens: this extension didn't really correspond to a middleware and was simply a wrapper around app.UseOAuthAuthorizationServer and app.UseOAuthBearerAuthentication. It was part of the ASP.NET Identity package and was just a convenient way to configure both the OAuth2 authorization server and the OAuth2 bearer middleware used to validate access tokens in a single call. It won't be ported to ASP.NET Core.
ASP.NET Core will offer a whole new middleware (and I'm proud to say I designed it):
app.UseOAuthAuthentication/OAuthAuthenticationMiddleware: this new middleware is a generic OAuth2 interactive client that behaves exactly like app.UseFacebookAuthentication or app.UseGoogleAuthentication but that supports virtually any standard OAuth2 provider, including yours. Google, Facebook and Microsoft providers have all been updated to inherit from this new base middleware.
So, the middleware you're actually looking for is the OAuth2 authorization server middleware, aka OAuthAuthorizationServerMiddleware.
Though it is considered as an essential component by a large part of the community, it won't be ported to ASP.NET Core.
Luckily, there's already a direct replacement: AspNet.Security.OpenIdConnect.Server (https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server)
This middleware is an advanced fork of the OAuth2 authorization server middleware that comes with Katana 3 but that targets OpenID Connect (which is itself based on OAuth2). It uses the same low-level approach that offers a fine-grained control (via various notifications) and allows you to use your own framework (Nancy, ASP.NET Core MVC) to serve your authorization pages like you could with the OAuth2 server middleware. Configuring it is easy:
ASP.NET Core 1.x:
// Add a new middleware validating access tokens issued by the server.
app.UseOAuthValidation();
// Add a new middleware issuing tokens.
app.UseOpenIdConnectServer(options =>
{
options.TokenEndpointPath = "/connect/token";
// Create your own `OpenIdConnectServerProvider` and override
// ValidateTokenRequest/HandleTokenRequest to support the resource
// owner password flow exactly like you did with the OAuth2 middleware.
options.Provider = new AuthorizationProvider();
});
ASP.NET Core 2.x:
// Add a new middleware validating access tokens issued by the server.
services.AddAuthentication()
.AddOAuthValidation()
// Add a new middleware issuing tokens.
.AddOpenIdConnectServer(options =>
{
options.TokenEndpointPath = "/connect/token";
// Create your own `OpenIdConnectServerProvider` and override
// ValidateTokenRequest/HandleTokenRequest to support the resource
// owner password flow exactly like you did with the OAuth2 middleware.
options.Provider = new AuthorizationProvider();
});
There's an OWIN/Katana 3 version, and an ASP.NET Core version that supports both .NET Desktop and .NET Core.
Don't hesitate to give the Postman sample a try to understand how it works. I'd recommend reading the associated blog post, that explains how you can implement the resource owner password flow.
Feel free to ping me if you still need help.
Good luck!
With #Pinpoint's help, we've wired together the rudiments of an answer. It shows how the components wire together without being a complete solution.
Fiddler Demo
With our rudimentary project setup, we were able to make the following request and response in Fiddler.
Request
POST http://localhost:50000/connect/token HTTP/1.1
User-Agent: Fiddler
Host: localhost:50000
Content-Length: 61
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=my_username&password=my_password
Response
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 1687
Content-Type: application/json;charset=UTF-8
Expires: -1
X-Powered-By: ASP.NET
Date: Tue, 16 Jun 2015 01:24:42 GMT
{
"access_token" : "eyJ0eXAiOi ... 5UVACg",
"expires_in" : 3600,
"token_type" : "bearer"
}
The response provides a bearer token that we can use to gain access to the secure part of the app.
Project Structure
This is the structure of our project in Visual Studio. We had to set its Properties > Debug > Port to 50000 so that it acts as the identity server that we configured. Here are the relevant files:
ResourceOwnerPasswordFlow
Providers
AuthorizationProvider.cs
project.json
Startup.cs
Startup.cs
For readability, I've split the Startup class into two partials.
Startup.ConfigureServices
For the very basics, we only need AddAuthentication().
public partial class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication();
}
}
Startup.Configure
public partial class Startup
{
public void Configure(IApplicationBuilder app)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();
// Add a new middleware validating access tokens issued by the server.
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Audience = "resource_server_1",
Authority = "http://localhost:50000/",
RequireHttpsMetadata = false
});
// Add a new middleware issuing tokens.
app.UseOpenIdConnectServer(options =>
{
// Disable the HTTPS requirement.
options.AllowInsecureHttp = true;
// Enable the token endpoint.
options.TokenEndpointPath = "/connect/token";
options.Provider = new AuthorizationProvider();
// Force the OpenID Connect server middleware to use JWT
// instead of the default opaque/encrypted format.
options.AccessTokenHandler = new JwtSecurityTokenHandler
{
InboundClaimTypeMap = new Dictionary<string, string>(),
OutboundClaimTypeMap = new Dictionary<string, string>()
};
// Register an ephemeral signing key, used to protect the JWT tokens.
// On production, you'd likely prefer using a signing certificate.
options.SigningCredentials.AddEphemeralKey();
});
app.UseMvc();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
AuthorizationProvider.cs
public sealed class AuthorizationProvider : OpenIdConnectServerProvider
{
public override Task ValidateTokenRequest(ValidateTokenRequestContext context)
{
// Reject the token requests that don't use
// grant_type=password or grant_type=refresh_token.
if (!context.Request.IsPasswordGrantType() &&
!context.Request.IsRefreshTokenGrantType())
{
context.Reject(
error: OpenIdConnectConstants.Errors.UnsupportedGrantType,
description: "Only grant_type=password and refresh_token " +
"requests are accepted by this server.");
return Task.FromResult(0);
}
// Since there's only one application and since it's a public client
// (i.e a client that cannot keep its credentials private), call Skip()
// to inform the server that the request should be accepted without
// enforcing client authentication.
context.Skip();
return Task.FromResult(0);
}
public override Task HandleTokenRequest(HandleTokenRequestContext context)
{
// Only handle grant_type=password token requests and let the
// OpenID Connect server middleware handle the other grant types.
if (context.Request.IsPasswordGrantType())
{
// Validate the credentials here (e.g using ASP.NET Core Identity).
// You can call Reject() with an error code/description to reject
// the request and return a message to the caller.
var identity = new ClaimsIdentity(context.Options.AuthenticationScheme);
identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "[unique identifier]");
// By default, claims are not serialized in the access and identity tokens.
// Use the overload taking a "destinations" parameter to make sure
// your claims are correctly serialized in the appropriate tokens.
identity.AddClaim("urn:customclaim", "value",
OpenIdConnectConstants.Destinations.AccessToken,
OpenIdConnectConstants.Destinations.IdentityToken);
var ticket = new AuthenticationTicket(
new ClaimsPrincipal(identity),
new AuthenticationProperties(),
context.Options.AuthenticationScheme);
// Call SetResources with the list of resource servers
// the access token should be issued for.
ticket.SetResources("resource_server_1");
// Call SetScopes with the list of scopes you want to grant
// (specify offline_access to issue a refresh token).
ticket.SetScopes("profile", "offline_access");
context.Validate(ticket);
}
return Task.FromResult(0);
}
}
project.json
{
"dependencies": {
"AspNet.Security.OpenIdConnect.Server": "1.0.0",
"Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0",
}
// other code omitted
}