"
 
 
 
ASP.NET (snapshot 2017) Microsoft documentation and samples

OWIN OAuth 2.0 Authorization Server

by Hongye Sun, Praburaj Thiagarajan, Rick Anderson

This tutorial will guide you on how to implement an OAuth 2.0 Authorization Server using OWIN OAuth middleware. This is an advanced tutorial that only outlines the steps to create an OWIN OAuth 2.0 Authorization Server. This is not a step by step tutorial. Download the sample code.

[!NOTE] This outline should not be intended to be used for creating a secure production app. This tutorial is intended to provide only an outline on how to implement an OAuth 2.0 Authorization Server using OWIN OAuth middleware.

Software versions

Shown in the tutorial Also works with
Windows 8.1 Windows 8, Windows 7
Visual Studio 2013 Visual Studio 2013 Express for Desktop. Visual Studio 2012 with the latest update should work, but the tutorial has not been tested with it, and some menu selections and dialog boxes are different.
.NET 4.5

Questions and Comments

If you have questions that are not directly related to the tutorial, you can post them at Katana Project on GitHub. For questions and comments regarding the tutorial itself, see the comments section at the bottom of the page.

The OAuth 2.0 framework enables a third-party app to obtain limited access to an HTTP service. Instead of using the resource owner’s credentials to access a protected resource, the client obtains an access token (which is a string denoting a specific scope, lifetime, and other access attributes). Access tokens are issued to third-party clients by an authorization server with the approval of the resource owner.

This tutorial will cover:

## Prerequisites

Create an Authorization Server

In this tutorial, we will roughly sketch out how to use OWIN and ASP.NET MVC to create an authorization server. We hope to soon provide a download for the completed sample, as this tutorial does not include each step. First, create an empty web app named AuthorizationServer and install the following packages:

Add an OWIN Startup class under the project root folder named Startup.

[!code-csharpMain]

   1:  using Microsoft.Owin;
   2:  using Owin;
   3:   
   4:  [assembly: OwinStartup(typeof(AuthorizationServer.Startup))]
   5:   
   6:  namespace AuthorizationServer
   7:  {
   8:     public partial class Startup
   9:     {
  10:        public void Configuration(IAppBuilder app)
  11:        {
  12:           ConfigureAuth(app);
  13:        }
  14:     }
  15:  }

Create an App_Start folder. Select the App_Start folder and use Shift+Alt+A to add the downloaded version of the AuthorizationServer_Start.Auth.cs file.

[!code-csharpMain]

   1:  public void ConfigureAuth(IAppBuilder app)
   2:   {
   3:       // Enable the Application Sign In Cookie.
   4:       app.UseCookieAuthentication(new CookieAuthenticationOptions
   5:       {
   6:           AuthenticationType = "Application",
   7:           AuthenticationMode = AuthenticationMode.Passive,
   8:           LoginPath = new PathString(Paths.LoginPath),
   9:           LogoutPath = new PathString(Paths.LogoutPath),
  10:       });
  11:   
  12:       // Enable the External Sign In Cookie.
  13:       app.SetDefaultSignInAsAuthenticationType("External");
  14:       app.UseCookieAuthentication(new CookieAuthenticationOptions
  15:       {
  16:           AuthenticationType = "External",
  17:           AuthenticationMode = AuthenticationMode.Passive,
  18:           CookieName = CookieAuthenticationDefaults.CookiePrefix + "External",
  19:           ExpireTimeSpan = TimeSpan.FromMinutes(5),
  20:       });
  21:   
  22:       // Enable Google authentication.
  23:       app.UseGoogleAuthentication();
  24:   
  25:       // Setup Authorization Server
  26:       app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
  27:       {
  28:           AuthorizeEndpointPath = new PathString(Paths.AuthorizePath),
  29:           TokenEndpointPath = new PathString(Paths.TokenPath),
  30:           ApplicationCanDisplayErrors = true,
  31:  #if DEBUG
  32:                  AllowInsecureHttp = true,
  33:  #endif
  34:       // Authorization server provider which controls the lifecycle of Authorization Server
  35:       Provider = new OAuthAuthorizationServerProvider
  36:       {
  37:           OnValidateClientRedirectUri = ValidateClientRedirectUri,
  38:           OnValidateClientAuthentication = ValidateClientAuthentication,
  39:           OnGrantResourceOwnerCredentials = GrantResourceOwnerCredentials,
  40:           OnGrantClientCredentials = GrantClientCredetails
  41:       },
  42:   
  43:       // Authorization code provider which creates and receives the authorization code.
  44:       AuthorizationCodeProvider = new AuthenticationTokenProvider
  45:       {
  46:           OnCreate = CreateAuthenticationCode,
  47:           OnReceive = ReceiveAuthenticationCode,
  48:       },
  49:   
  50:       // Refresh token provider which creates and receives refresh token.
  51:       RefreshTokenProvider = new AuthenticationTokenProvider
  52:       {
  53:           OnCreate = CreateRefreshToken,
  54:           OnReceive = ReceiveRefreshToken,
  55:       }
  56:   });
  57:  }

The code above enables application/external sign in cookies and Google authentication, which are used by authorization server itself to manage accounts.

The UseOAuthAuthorizationServer extension method is to setup the authorization server. The setup options are:

Account Management

OAuth doesn’t care where or how you manage your user account information. It’s ASP.NET Identity which is responsible for it. In this tutorial, we will simplify the account management code and just make sure that user can login using OWIN cookie middleware. Here is the simplified sample code for the AccountController:

[!code-csharpMain]

   1:  public class AccountController : Controller
   2:  {
   3:      public ActionResult Login()
   4:      {
   5:          var authentication =  HttpContext.GetOwinContext().Authentication;
   6:          if (Request.HttpMethod == "POST")
   7:          {
   8:              var isPersistent = !string.IsNullOrEmpty(Request.Form.Get("isPersistent"));
   9:   
  10:              if (!string.IsNullOrEmpty(Request.Form.Get("submit.Signin")))
  11:              {
  12:                  authentication.SignIn(
  13:                      new AuthenticationProperties { IsPersistent = isPersistent },
  14:                      new ClaimsIdentity(new[] { new Claim(
  15:                         ClaimsIdentity.DefaultNameClaimType, Request.Form["username"]) }, 
  16:                         "Application"));
  17:              }
  18:          }
  19:   
  20:          return View();
  21:      }
  22:   
  23:      public ActionResult Logout()
  24:      {
  25:          return View();
  26:      }
  27:   
  28:      public ActionResult External()
  29:      {
  30:          var authentication = HttpContext.GetOwinContext().Authentication;
  31:          if (Request.HttpMethod == "POST")
  32:          {
  33:              foreach (var key in Request.Form.AllKeys)
  34:              {
  35:                  if (key.StartsWith("submit.External.") && !string.IsNullOrEmpty(Request.Form.Get(key)))
  36:                  {
  37:                      var authType = key.Substring("submit.External.".Length);
  38:                      authentication.Challenge(authType);
  39:                      return new HttpUnauthorizedResult();
  40:                  }
  41:              }
  42:          }
  43:          var identity = authentication.AuthenticateAsync("External").Result.Identity;
  44:          if (identity != null)
  45:          {
  46:              authentication.SignOut("External");
  47:              authentication.SignIn(
  48:                  new AuthenticationProperties { IsPersistent = true },
  49:                  new ClaimsIdentity(identity.Claims, "Application", identity.NameClaimType, identity.RoleClaimType));
  50:              return Redirect(Request.QueryString["ReturnUrl"]);
  51:          }
  52:   
  53:          return View();
  54:      }
  55:  }

[!code-csharpMain]

   1:  private Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
   2:  {
   3:      if (context.ClientId == Clients.Client1.Id)
   4:      {
   5:          context.Validated(Clients.Client1.RedirectUrl);
   6:      }
   7:      else if (context.ClientId == Clients.Client2.Id)
   8:      {
   9:          context.Validated(Clients.Client2.RedirectUrl);
  10:      }
  11:      return Task.FromResult(0);
  12:  }
  13:   
  14:  private Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
  15:  {
  16:      string clientId;
  17:      string clientSecret;
  18:      if (context.TryGetBasicCredentials(out clientId, out clientSecret) ||
  19:          context.TryGetFormCredentials(out clientId, out clientSecret))
  20:      {
  21:          if (clientId == Clients.Client1.Id && clientSecret == Clients.Client1.Secret)
  22:          {
  23:              context.Validated();
  24:          }
  25:          else if (clientId == Clients.Client2.Id && clientSecret == Clients.Client2.Secret)
  26:          {
  27:              context.Validated();
  28:          }
  29:      }
  30:      return Task.FromResult(0);
  31:  }

ValidateClientRedirectUri is used to validate the client with its registered redirect URL. ValidateClientAuthentication checks the basic scheme header and form body to get the client’s credentials.

The login page is shown below:

Review the IETF’s OAuth 2 Authorization Code Grant section now.

Provider (in the table below) is OAuthAuthorizationServerOptions.Provider, which is of type OAuthAuthorizationServerProvider, which contains all OAuth server events.

Flow steps from Authorization Code Grant section Sample download performs these steps with:
(A) The client initiates the flow by directing the resource owner’s user-agent to the authorization endpoint. The client includes its client identifier, requested scope, local state, and a redirection URI to which the authorization server will send the user-agent back once access is granted (or denied). Provider.MatchEndpoint Provider.ValidateClientRedirectUri Provider.ValidateAuthorizeRequest Provider.AuthorizeEndpoint
(B) The authorization server authenticates the resource owner (via the user-agent) and establishes whether the resource owner grants or denies the client’s access request. <If user grants access> Provider.MatchEndpoint Provider.ValidateClientRedirectUri Provider.ValidateAuthorizeRequest Provider.AuthorizeEndpoint AuthorizationCodeProvider.CreateAsync
(C) Assuming the resource owner grants access, the authorization server redirects the user-agent back to the client using the redirection URI provided earlier (in the request or during client registration). …
(D) The client requests an access token from the authorization server’s token endpoint by including the authorization code received in the previous step. When making the request, the client authenticates with the authorization server. The client includes the redirection URI used to obtain the authorization code for verification. Provider.MatchEndpoint Provider.ValidateClientAuthentication AuthorizationCodeProvider.ReceiveAsync Provider.ValidateTokenRequest Provider.GrantAuthorizationCode Provider.TokenEndpoint AccessTokenProvider.CreateAsync RefreshTokenProvider.CreateAsync

A sample implementation for AuthorizationCodeProvider.CreateAsync and ReceiveAsync to control the creation and validation of authorization code is shown below.

[!code-csharpMain]

   1:  private readonly ConcurrentDictionary<string, string> _authenticationCodes =
   2:       new ConcurrentDictionary<string, string>(StringComparer.Ordinal);
   3:   
   4:   private void CreateAuthenticationCode(AuthenticationTokenCreateContext context)
   5:   {
   6:       context.SetToken(Guid.NewGuid().ToString("n") + Guid.NewGuid().ToString("n"));
   7:       _authenticationCodes[context.Token] = context.SerializeTicket();
   8:   }
   9:   
  10:   private void ReceiveAuthenticationCode(AuthenticationTokenReceiveContext context)
  11:   {
  12:       string value;
  13:       if (_authenticationCodes.TryRemove(context.Token, out value))
  14:       {
  15:           context.DeserializeTicket(value);
  16:       }
  17:   }

The code above uses an in-memory concurrent dictionary to store the code and identity ticket and restore the identity after receiving the code. In a real application, it would be replaced by a persistent data store. The authorization endpoint is for the resource owner to grant access to the client. Usually, it needs a user interface to allow the user to click a button and confirm the grant. OWIN OAuth middleware allows application code to handle the authorization endpoint. In our sample app, we use an MVC controller called OAuthController to handle it. Here is the sample implementation:

[!code-csharpMain]

   1:  public class OAuthController : Controller
   2:   {
   3:       public ActionResult Authorize()
   4:       {
   5:           if (Response.StatusCode != 200)
   6:           {
   7:               return View("AuthorizeError");
   8:           }
   9:   
  10:           var authentication = HttpContext.GetOwinContext().Authentication;
  11:           var ticket = authentication.AuthenticateAsync("Application").Result;
  12:           var identity = ticket != null ? ticket.Identity : null;
  13:           if (identity == null)
  14:           {
  15:               authentication.Challenge("Application");
  16:               return new HttpUnauthorizedResult();
  17:           }
  18:   
  19:           var scopes = (Request.QueryString.Get("scope") ?? "").Split(' ');
  20:   
  21:           if (Request.HttpMethod == "POST")
  22:           {
  23:               if (!string.IsNullOrEmpty(Request.Form.Get("submit.Grant")))
  24:               {
  25:                   identity = new ClaimsIdentity(identity.Claims, "Bearer", identity.NameClaimType, identity.RoleClaimType);
  26:                   foreach (var scope in scopes)
  27:                   {
  28:                       identity.AddClaim(new Claim("urn:oauth:scope", scope));
  29:                   }
  30:                   authentication.SignIn(identity);
  31:               }
  32:               if (!string.IsNullOrEmpty(Request.Form.Get("submit.Login")))
  33:               {
  34:                   authentication.SignOut("Application");
  35:                   authentication.Challenge("Application");
  36:                   return new HttpUnauthorizedResult();
  37:               }
  38:           }
  39:   
  40:           return View();
  41:       }
  42:  }

The Authorize action will first check if the user has logged in to the authorization server. If not, the authentication middleware challenges the caller to authenticate using the “Application” cookie and redirects to the login page. (See highlighted code above.) If user has logged in, it will render the Authorize view, as shown below:

If the Grant button is selected, the Authorize action will create a new “Bearer” identity and sign in with it. It will trigger the authorization server to generate a bearer token and send it back to the client with JSON payload.

Implicit Grant

Refer to the IETF’s OAuth 2 Implicit Grant section now.

The Implicit Grant flow shown in Figure 4 is the flow and mapping which the OWIN OAuth middleware follows.

Flow steps from Implicit Grant section Sample download performs these steps with:
(A) The client initiates the flow by directing the resource owner’s user-agent to the authorization endpoint. The client includes its client identifier, requested scope, local state, and a redirection URI to which the authorization server will send the user-agent back once access is granted (or denied). Provider.MatchEndpoint Provider.ValidateClientRedirectUri Provider.ValidateAuthorizeRequest Provider.AuthorizeEndpoint
(B) The authorization server authenticates the resource owner (via the user-agent) and establishes whether the resource owner grants or denies the client’s access request. <If user grants access> Provider.MatchEndpoint Provider.ValidateClientRedirectUri Provider.ValidateAuthorizeRequest Provider.AuthorizeEndpoint AuthorizationCodeProvider.CreateAsync
(C) Assuming the resource owner grants access, the authorization server redirects the user-agent back to the client using the redirection URI provided earlier (in the request or during client registration). …
(D) The client requests an access token from the authorization server’s token endpoint by including the authorization code received in the previous step. When making the request, the client authenticates with the authorization server. The client includes the redirection URI used to obtain the authorization code for verification.

Since we already implemented the authorization endpoint (OAuthController.Authorize action) for authorization code grant, it automatically enables implicit flow as well. Note: Provider.ValidateClientRedirectUri is used to validate the client ID with its redirection URL, which protects the implicit grant flow from sending the access token to malicious clients (Man-in-the-middle attack).

Resource Owner Password Credentials Grant

Refer to the IETF’s OAuth 2 Resource Owner Password Credentials Grant section now.

The Resource Owner Password Credentials Grant flow shown in Figure 5 is the flow and mapping which the OWIN OAuth middleware follows.

Flow steps from Resource Owner Password Credentials Grant section Sample download performs these steps with:
(A) The resource owner provides the client with its username and password.
(B) The client requests an access token from the authorization server’s token endpoint by including the credentials received from the resource owner. When making the request, the client authenticates with the authorization server. Provider.MatchEndpoint Provider.ValidateClientAuthentication Provider.ValidateTokenRequest Provider.GrantResourceOwnerCredentials Provider.TokenEndpoint AccessToken Provider.CreateAsync RefreshTokenProvider.CreateAsync
(C) The authorization server authenticates the client and validates the resource owner credentials, and if valid, issues an access token.

Here is the sample implementation for Provider.GrantResourceOwnerCredentials:

[!code-csharpMain]

   1:  private Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
   2:   {
   3:       var identity = new ClaimsIdentity(new GenericIdentity(
   4:          context.UserName, OAuthDefaults.AuthenticationType), 
   5:          context.Scope.Select(x => new Claim("urn:oauth:scope", x))
   6:          );
   7:   
   8:       context.Validated(identity);
   9:   
  10:       return Task.FromResult(0);
  11:   }

[!NOTE] The code above is intended to explain this section of the tutorial and should not be used in secure or production apps. It does not check the resource owners credentials. It assumes every credential is valid and creates a new identity for it. The new identity will be used to generate the access token and refresh token. Please replace the code with your own secure account management code.

Client Credentials Grant

Refer to the IETF’s OAuth 2 Client Credentials Grant section now.

The Client Credentials Grant flow shown in Figure 6 is the flow and mapping which the OWIN OAuth middleware follows.

Flow steps from Client Credentials Grant section Sample download performs these steps with:
(A) The client authenticates with the authorization server and requests an access token from the token endpoint. Provider.MatchEndpoint Provider.ValidateClientAuthentication Provider.ValidateTokenRequest Provider.GrantClientCredentials Provider.TokenEndpoint AccessTokenProvider.CreateAsync RefreshTokenProvider.CreateAsync
(B) The authorization server authenticates the client, and if valid, issues an access token.

Here is the sample implementation for Provider.GrantClientCredentials:

[!code-csharpMain]

   1:  private Task GrantClientCredetails(OAuthGrantClientCredentialsContext context)
   2:  {
   3:      var identity = new ClaimsIdentity(new GenericIdentity(
   4:          context.ClientId, OAuthDefaults.AuthenticationType), 
   5:          context.Scope.Select(x => new Claim("urn:oauth:scope", x))
   6:          );
   7:   
   8:      context.Validated(identity);
   9:   
  10:      return Task.FromResult(0);
  11:  }

[!NOTE] The code above is intended to explain this section of the tutorial and should not be used in secure or production apps. Please replace the code with your own secure client management code.

Refresh Token

Refer to the IETF’s OAuth 2 Refresh Token section now.

The Refresh Token flow shown in Figure 2 is the flow and mapping which the OWIN OAuth middleware follows.

Flow steps from Client Credentials Grant section Sample download performs these steps with:
(G) The client requests a new access token by authenticating with the authorization server and presenting the refresh token. The client authentication requirements are based on the client type and on the authorization server policies. Provider.MatchEndpoint Provider.ValidateClientAuthentication RefreshTokenProvider.ReceiveAsync Provider.ValidateTokenRequest Provider.GrantRefreshToken Provider.TokenEndpoint AccessTokenProvider.CreateAsync RefreshTokenProvider.CreateAsync
(H) The authorization server authenticates the client and validates the refresh token, and if valid, issues a new access token (and, optionally, a new refresh token).

Here is the sample implementation for Provider.GrantRefreshToken:

[!code-csharpMain]

   1:  public void ConfigureAuth(IAppBuilder app)
   2:   {
   3:      // Code removed for clarity     
   4:   
   5:       // Refresh token provider which creates and receives refresh token.
   6:       RefreshTokenProvider = new AuthenticationTokenProvider
   7:       {
   8:           OnCreate = CreateRefreshToken,
   9:           OnReceive = ReceiveRefreshToken,
  10:       }
  11:   });
  12:  }

[!code-csharpMain]

   1:  private void CreateRefreshToken(AuthenticationTokenCreateContext context)
   2:   {
   3:       context.SetToken(context.SerializeTicket());
   4:   }
   5:   
   6:   private void ReceiveRefreshToken(AuthenticationTokenReceiveContext context)
   7:   {
   8:       context.DeserializeTicket(context.Token);
   9:   }

Create a Resource Server which is protected by Access Token

Create an empty web app project and install following packages in the project:

Create a startup class and configure authentication and Web API. See AuthorizationServer.cs in the sample download.

[!code-csharpMain]

   1:  [assembly: OwinStartup(typeof(ResourceServer.Startup))]
   2:   
   3:  namespace ResourceServer
   4:  {
   5:      public partial class Startup
   6:      {
   7:          public void Configuration(IAppBuilder app)
   8:          {
   9:              ConfigureAuth(app);
  10:              ConfigureWebApi(app);
  11:          }
  12:      }
  13:  }

See AuthorizationServer_Start.Auth.cs in the sample download.

[!code-csharpMain]

   1:  using Microsoft.Owin.Cors;
   2:  using Microsoft.Owin.Security.OAuth;
   3:  using Owin;
   4:   
   5:  namespace ResourceServer
   6:  {
   7:      public partial class Startup
   8:      {
   9:          public void ConfigureAuth(IAppBuilder app)
  10:          {
  11:              app.UseCors(CorsOptions.AllowAll);
  12:   
  13:              app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
  14:              {
  15:              });
  16:          }
  17:      }
  18:  }

See AuthorizationServer_Start.WebApi.cs in the sample download.

[!code-csharpMain]

   1:  using Microsoft.Owin.Security.OAuth;
   2:  using Owin;
   3:  using System.Web.Http;
   4:   
   5:  namespace ResourceServer
   6:  {
   7:      public partial class Startup
   8:      {
   9:          public void ConfigureWebApi(IAppBuilder app)
  10:          {
  11:              var config = new HttpConfiguration();
  12:              // Web API configuration and services
  13:              // Configure Web API to use only bearer token authentication.
  14:              config.SuppressDefaultHostAuthentication();
  15:              config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
  16:   
  17:              // Web API routes
  18:              config.MapHttpAttributeRoutes();
  19:   
  20:              config.Routes.MapHttpRoute(
  21:                  name: "DefaultApi",
  22:                  routeTemplate: "api/{controller}/{id}",
  23:                  defaults: new { id = RouteParameter.Optional }
  24:              );
  25:   
  26:              app.UseWebApi(config);
  27:          }
  28:      }
  29:  }

In order to demonstrate the authenticated identity, we create an ApiController to output current user’s claims.

[!code-csharpMain]

   1:  namespace ResourceServer.Controllers
   2:  {
   3:      [Authorize]
   4:      public class MeController : ApiController
   5:      {
   6:          // GET api/<controller>
   7:          public IEnumerable<object> Get()
   8:          {
   9:              var identity = User.Identity as ClaimsIdentity;
  10:              return identity.Claims.Select(c => new
  11:              {
  12:                  Type = c.Type,
  13:                  Value = c.Value
  14:              });
  15:          }
  16:      }
  17:  }

If the authorization server and the resource server are not on the same computer, the OAuth middleware will use the different machine keys to encrypt and decrypt bearer access token. In order to share the same private key between both projects, we add the same machinekey setting in both web.config files.

[!code-xmlMain]

   1:  <configuration>
   2:    <appSettings>    
   3:       <!-- Keys removed for clarity. -->
   4:    </appSettings>
   5:    <system.web>
   6:      <compilation debug="true" targetFramework="4.5" />
   7:      <httpRuntime targetFramework="4.5" />
   8:      <machineKey decryptionKey="Enter decryption Key here" 
   9:                  validation="SHA1" 
  10:                  validationKey="Enter validation Key here" />
  11:    </system.web>  
  12:    <runtime>
  13:       <!-- Keys removed for clarity. -->    
  14:    </runtime>
  15:  </configuration>

Create OAuth 2.0 Clients

We use the DotNetOpenAuth.OAuth2.Client NuGet package to simplify the client code.

Authorization Code Grant Client

This client is an MVC application. It will trigger an authorization code grant flow to get the access token from backend. It has a single page as shown below:

Here is the sample code of the HomeController of the client.

[!code-csharpMain]

   1:  using Constants;
   2:  using DotNetOpenAuth.OAuth2;
   3:  using System;
   4:  using System.Net.Http;
   5:  using System.Web.Mvc;
   6:   
   7:  namespace AuthorizationCodeGrant.Controllers
   8:  {
   9:     public class HomeController : Controller
  10:     {
  11:        private WebServerClient _webServerClient;
  12:   
  13:        public ActionResult Index()
  14:        {
  15:           ViewBag.AccessToken = Request.Form["AccessToken"] ?? "";
  16:           ViewBag.RefreshToken = Request.Form["RefreshToken"] ?? "";
  17:           ViewBag.Action = "";
  18:           ViewBag.ApiResponse = "";
  19:   
  20:           InitializeWebServerClient();
  21:           var accessToken = Request.Form["AccessToken"];
  22:           if (string.IsNullOrEmpty(accessToken))
  23:           {
  24:              var authorizationState = _webServerClient.ProcessUserAuthorization(Request);
  25:              if (authorizationState != null)
  26:              {
  27:                 ViewBag.AccessToken = authorizationState.AccessToken;
  28:                 ViewBag.RefreshToken = authorizationState.RefreshToken;
  29:                 ViewBag.Action = Request.Path;
  30:              }
  31:           }
  32:   
  33:           if (!string.IsNullOrEmpty(Request.Form.Get("submit.Authorize")))
  34:           {
  35:              var userAuthorization = _webServerClient.PrepareRequestUserAuthorization(new[] { "bio", "notes" });
  36:              userAuthorization.Send(HttpContext);
  37:              Response.End();
  38:           }
  39:           else if (!string.IsNullOrEmpty(Request.Form.Get("submit.Refresh")))
  40:           {
  41:              var state = new AuthorizationState
  42:              {
  43:                 AccessToken = Request.Form["AccessToken"],
  44:                 RefreshToken = Request.Form["RefreshToken"]
  45:              };
  46:              if (_webServerClient.RefreshAuthorization(state))
  47:              {
  48:                 ViewBag.AccessToken = state.AccessToken;
  49:                 ViewBag.RefreshToken = state.RefreshToken;
  50:              }
  51:           }
  52:           else if (!string.IsNullOrEmpty(Request.Form.Get("submit.CallApi")))
  53:           {
  54:              var resourceServerUri = new Uri(Paths.ResourceServerBaseAddress);
  55:              var client = new HttpClient(_webServerClient.CreateAuthorizingHandler(accessToken));
  56:              var body = client.GetStringAsync(new Uri(resourceServerUri, Paths.MePath)).Result;
  57:              ViewBag.ApiResponse = body;
  58:           }
  59:   
  60:           return View();
  61:        }
  62:   
  63:        private void InitializeWebServerClient()
  64:        {
  65:           var authorizationServerUri = new Uri(Paths.AuthorizationServerBaseAddress);
  66:           var authorizationServer = new AuthorizationServerDescription
  67:           {
  68:              AuthorizationEndpoint = new Uri(authorizationServerUri, Paths.AuthorizePath),
  69:              TokenEndpoint = new Uri(authorizationServerUri, Paths.TokenPath)
  70:           };
  71:           _webServerClient = new WebServerClient(authorizationServer, Clients.Client1.Id, Clients.Client1.Secret);
  72:        }
  73:     }
  74:  }

DotNetOpenAuth requires SSL by default. Since our demo is using HTTP, you need to add following setting in the config file:

[!code-xmlMain]

   1:  <configuration>
   2:     <!-- Markup removed for clarity. -->
   3:    
   4:    <dotNetOpenAuth>
   5:      <messaging relaxSslRequirements="true"/>
   6:    </dotNetOpenAuth>
   7:  </configuration>

[!WARNING] Security - Never disable SSL in a production app. Your login credentials are now being sent in clear-text across the wire. The code above is just for local sample debugging and exploration.

Implicit Grant Client

This client is using JavaScript to:

  1. Open a new window and redirect to the authorize endpoint of the Authorization Server.
  2. Get the access token from URL fragments when it redirects back.

The following image shows this process:

The client should have two pages: one for home page and the other for callback.Here is the sample JavaScript code found in the Index.cshtml file:

[!code-cshtmlMain]

   1:  <script type="text/javascript">
   2:      (function ($) {
   3:          var authorizeUri = '@(Paths.AuthorizationServerBaseAddress + Paths.AuthorizePath)';
   4:          var tokenUri = '@(Paths.AuthorizationServerBaseAddress + Paths.TokenPath)';
   5:          var apiUri = '@(Paths.ResourceServerBaseAddress + Paths.MePath)';
   6:          var returnUri = '@Paths.ImplicitGrantCallBackPath';
   7:   
   8:          $('#Authorize').click(function () {
   9:              var nonce = 'my-nonce';
  10:   
  11:              var uri = addQueryString(authorizeUri, {
  12:                  'client_id': '7890ab',
  13:                  'redirect_uri': returnUri,
  14:                  'state': nonce,
  15:                  'scope': 'bio notes',
  16:                  'response_type': 'token',
  17:              });
  18:   
  19:              window.oauth = {};
  20:              window.oauth.signin = function (data) {
  21:                  if (data.state !== nonce) {
  22:                      return;
  23:                  }
  24:   
  25:                  $('#AccessToken').val(data.access_token);
  26:              }
  27:   
  28:              window.open(uri, 'Authorize', 'width=640,height=480');
  29:          });
  30:   
  31:          $('#CallApi').click(function () {
  32:              $.ajax(apiUri, {
  33:                  beforeSend: function (xhr) {
  34:                      xhr.setRequestHeader('Authorization', 'Bearer ' + $('#AccessToken').val());
  35:                  },
  36:                  dataType: 'text',
  37:                  cache: false,
  38:                  success: function (data) {
  39:                      console.log(data);
  40:                      $('#output').text(data);
  41:                  }
  42:              });
  43:          });
  44:   
  45:          function addQueryString(uri, parameters) {
  46:              var delimiter = (uri.indexOf('?') == -1) ? '?' : '&';
  47:              for (var parameterName in parameters) {
  48:                  var parameterValue = parameters[parameterName];
  49:                  uri += delimiter + encodeURIComponent(parameterName) + '=' + encodeURIComponent(parameterValue);
  50:                  delimiter = '&';
  51:              }
  52:              return uri;
  53:          }
  54:      })(jQuery);
  55:  </script>

Here is the callback handling code in SignIn.cshtml file:

[!code-cshtmlMain]

   1:  <script type="text/javascript">
   2:      (function ($) {
   3:          function getFragment() {
   4:              if (window.location.hash.indexOf("#") === 0) {
   5:                  return parseQueryString(window.location.hash.substr(1));
   6:              } else {
   7:                  return {};
   8:              }
   9:          }
  10:   
  11:          function parseQueryString(queryString) {
  12:              var data = {},
  13:                  pairs, pair, separatorIndex, escapedKey, escapedValue, key, value;
  14:   
  15:              if (queryString === null) {
  16:                  return data;
  17:              }
  18:   
  19:              pairs = queryString.split("&");
  20:   
  21:              for (var i = 0; i < pairs.length; i++) {
  22:                  pair = pairs[i];
  23:                  separatorIndex = pair.indexOf("=");
  24:   
  25:                  if (separatorIndex === -1) {
  26:                      escapedKey = pair;
  27:                      escapedValue = null;
  28:                  } else {
  29:                      escapedKey = pair.substr(0, separatorIndex);
  30:                      escapedValue = pair.substr(separatorIndex + 1);
  31:                  }
  32:   
  33:                  key = decodeURIComponent(escapedKey);
  34:                  value = decodeURIComponent(escapedValue);
  35:   
  36:                  data[key] = value;
  37:              }
  38:   
  39:              return data;
  40:          }
  41:   
  42:          var fragments = getFragment();
  43:          if (window.opener && window.opener.oauth && window.opener.oauth.signin) {
  44:              window.opener.oauth.signin(fragments);
  45:          }
  46:          window.close();
  47:      })(jQuery);
  48:  </script>

[!NOTE] A best practice is to move the JavaScript to an external file and not embed it with the Razor markup. To keep this sample simple, they have been combined.

Resource Owner Password Credentials Grant Client

We uses a console app to demo this client. Here is the code:

[!code-csharpMain]

   1:  class Program
   2:  {
   3:      private static WebServerClient _webServerClient;
   4:      private static string _accessToken;
   5:   
   6:      static void Main(string[] args)
   7:      {
   8:          InitializeWebServerClient();
   9:   
  10:          Console.WriteLine("Requesting Token...");
  11:          RequestToken();
  12:   
  13:          Console.WriteLine("Access Token: {0}", _accessToken);
  14:   
  15:          Console.WriteLine("Access Protected Resource");
  16:          AccessProtectedResource();            
  17:      }
  18:   
  19:      private static void InitializeWebServerClient()
  20:      {
  21:          var authorizationServerUri = new Uri(Paths.AuthorizationServerBaseAddress);
  22:          var authorizationServer = new AuthorizationServerDescription
  23:          {
  24:              AuthorizationEndpoint = new Uri(authorizationServerUri, Paths.AuthorizePath),
  25:              TokenEndpoint = new Uri(authorizationServerUri, Paths.TokenPath)
  26:          };
  27:          _webServerClient = new WebServerClient(authorizationServer, Clients.Client1.Id, Clients.Client1.Secret);
  28:      }
  29:   
  30:      private static void RequestToken()
  31:      {
  32:          var state = _webServerClient.GetClientAccessToken(new[] { "bio", "notes" });
  33:          _accessToken = state.AccessToken;
  34:      }
  35:   
  36:      private static void AccessProtectedResource()
  37:      {
  38:          var resourceServerUri = new Uri(Paths.ResourceServerBaseAddress);
  39:          var client = new HttpClient(_webServerClient.CreateAuthorizingHandler(_accessToken));
  40:          var body = client.GetStringAsync(new Uri(resourceServerUri, Paths.MePath)).Result;
  41:          Console.WriteLine(body);
  42:      }
  43:  }

Client Credentials Grant Client

Similar to the Resource Owner Password Credentials Grant, here is console app code:

[!code-csharpMain]

   1:  class Program
   2:  {
   3:      private static WebServerClient _webServerClient;
   4:      private static string _accessToken;
   5:   
   6:      static void Main(string[] args)
   7:      {
   8:          InitializeWebServerClient();
   9:   
  10:          Console.WriteLine("Requesting Token...");
  11:          RequestToken();
  12:   
  13:          Console.WriteLine("Access Token: {0}", _accessToken);
  14:   
  15:          Console.WriteLine("Access Protected Resource");
  16:          AccessProtectedResource();
  17:      }
  18:   
  19:      private static void InitializeWebServerClient()
  20:      {
  21:          var authorizationServerUri = new Uri(Paths.AuthorizationServerBaseAddress);
  22:          var authorizationServer = new AuthorizationServerDescription
  23:          {
  24:              AuthorizationEndpoint = new Uri(authorizationServerUri, Paths.AuthorizePath),
  25:              TokenEndpoint = new Uri(authorizationServerUri, Paths.TokenPath)
  26:          };
  27:          _webServerClient = new WebServerClient(authorizationServer, Clients.Client1.Id, Clients.Client1.Secret);
  28:      }
  29:   
  30:      private static void RequestToken()
  31:      {
  32:          var state = _webServerClient.ExchangeUserCredentialForToken("test", "test", new[] { "bio", "notes" });
  33:          _accessToken = state.AccessToken;
  34:      }
  35:   
  36:      private static void AccessProtectedResource()
  37:      {
  38:          var resourceServerUri = new Uri(Paths.ResourceServerBaseAddress);
  39:          var client = new HttpClient(_webServerClient.CreateAuthorizingHandler(_accessToken));
  40:          var body = client.GetStringAsync(new Uri(resourceServerUri, Paths.MePath)).Result;
  41:          Console.WriteLine(body);
  42:      }
  43:  }





Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/AspNet-DocAndSamples-2017/aspnet/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>