Configure the authorization server endpoint

Question

How do we use a media token with ASP.NET 5 using a username and password stream? For our scenario, we want the user to register and log in using AJAX calls without the need for an external login.

To do this, we need to have an authorization server endpoint. In previous versions of ASP.NET, we would follow these steps and then run with the address ourdomain.com/Token .

 // 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, however, this does not work. We tried to figure out a new approach. the aspnet / identity example on GitHub, for example, configures Facebook, Google and Twitter authentication, but does not display the endpoint of the OAuth external authorization server, unless that means AddDefaultTokenProviders() , in which case we are wondering what the URL will be provider.

Study

We 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, although we are still not sure how to set the token endpoint. It did not help:

 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."); }); } 

When we go to ourdomain.com/meta we just get our worldwide welcome page.

Further studies have shown that we can also use the IAppBuilder.UseOAuthAuthentication extension IAppBuilder.UseOAuthAuthentication and that it accepts the OAuthAuthenticationOptions parameter. This parameter has the TokenEndpoint property. Therefore, although we are not sure what we are doing, we tried it, which, of course, did not 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, there is no mistake when switching to ourdomain.com/Token , we will return our global welcome page again.

+34
c # oauth asp.net-core asp.net-identity
Jun 10 '15 at 21:57
source share
2 answers

Ok, let's recall the other OAuth2 middleware (and their corresponding IAppBuilder extensions) that were proposed by OWIN / Katana 3 , and those that will be ported to ASP.NET Core

  • app.UseOAuthBearerAuthentication / OAuthBearerAuthenticationMiddleware : its name was not obvious, but it was (and still, since it was ported to ASP.NET Core) responsible for checking access tokens issued by the OAuth2 server middleware. This is basically a cookie token copy of the middleware and is used to protect your APIs. In ASP.NET Core, it was supplemented with additional OpenID Connect features (now it can automatically receive a signing certificate from the OpenID Connect server that issued the tokens).

Note. Starting with ASP.NET Core beta8, it is now called app.UseJwtBearerAuthentication / JwtBearerAuthenticationMiddleware .

  • app.UseOAuthAuthorizationServer / OAuthAuthorizationServerMiddleware : as the name suggests, OAuthAuthorizationServerMiddleware was the OAuth2 authorization server middleware and was used to create and issue access tokens. This middleware will not be ported to ASP.NET Core : OAuth Authorization Service in ASP.NET Core .

  • app.UseOAuthBearerTokens : this extension really did not fit with the middleware and was just 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 the OAuth2 authorization server and the OAuth2 middleware used to verify access tokens in a single call. It will not be ported to the ASP.NET kernel .

ASP.NET Core will offer a completely new middleware (and I can proudly say that I developed it):

  • app.UseOAuthAuthentication / OAuthAuthenticationMiddleware : this new middleware is a common OAuth2 interactive client that behaves just like app.UseFacebookAuthentication or app.UseGoogleAuthentication , but supports almost any standard OAuth2 provider, including yours. Google, Facebook and Microsoft vendors have all been updated to inherit this new core middleware.



So, the middleware you are really looking for is the OAuth2 authorization server middleware , aka OAuthAuthorizationServerMiddleware .

Although considered an important component of a large part of the community, it will not be ported to ASP.NET Core .

Fortunately, there is already a direct replacement: AspNet.Security.OpenIdConnect.Server ( https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server )

This middleware is the forefront fork of the OAuth2 authorization server middleware that ships with Katana 3 , but it is for OpenID Connect (which is itself based on OAuth2). It uses the same low-level approach that offers small-scale control (through various notifications) and allows you to use your own infrastructure (Nancy, ASP.NET Core MVC) to serve your authorization pages, as you could, using the OAuth2 server middleware, Configuration 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 is an OWIN / Katana 3 version and an ASP.NET Core version that supports both .NET Desktop and .NET Core.

Feel free to give a Postman sample to understand how this works. I would recommend reading a related blog post that explains how you can implement the password stream of the resource owner.

Feel free to ping me if you still need help. Good luck

+41
Jun 11 '15 at 17:58
source share

Using @Pinpoint help, we linked the rudiments of the answer. It shows how components join 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.

Inquiry

 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 

Answer

 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 carrier token that we can use to access the secure part of the application.

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 works as the authentication server that we configured. Here are the relevant files:

 ResourceOwnerPasswordFlow Providers AuthorizationProvider.cs project.json Startup.cs 

Startup.cs

For readability, I divided the Startup class into two parts.

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 only one application and since it a public client // (ie 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 (eg 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 } 
+26
Jun 16 '15 at 1:35
source share



All Articles