Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write OAuth2 Web API Client in Asp.net MVC

We have developed a set of Web APIs (REST) which are protected by an Authorization server. The Authorization server has issued the client id and client secret. These can be used to obtain an access token. A valid token can be used on subsequent calls to resource servers (REST APIs).

I want to write an web based (Asp.net MVC 5) client that will consume the APIs. Is there a nuget package I can download that will help me to implement the client OAuth2 flow? Can anyone direct me to a good example on client implementation of OAuth2 flow (written in asp.net MVC)?

Update I was able to get access token using the code block below, but what I want is a "client credentials" oauth 2 flow where I don't have to enter login and passwords. The code I have now is:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType("ClientCookie");

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            AuthenticationType = "ClientCookie",
            CookieName = CookieAuthenticationDefaults.CookiePrefix + "ClientCookie",
            ExpireTimeSpan = TimeSpan.FromMinutes(5)
        });

        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,                
            SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(),
            ClientId = ConfigurationManager.AppSettings["AuthServer:ClientId"],
            ClientSecret = ConfigurationManager.AppSettings["AuthServer:ClientSecret"],
            RedirectUri = ConfigurationManager.AppSettings["AuthServer:RedirectUrl"],
            Configuration = new OpenIdConnectConfiguration
            {
                AuthorizationEndpoint = "https://identityserver.com/oauth2/authorize",
                TokenEndpoint = "https://identityserver.com/oauth2/token"                                        
            },

            //ResponseType = "client_credentials", // Doesn't work
            ResponseType = "token",

            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthenticationFailed = notification =>
                {
                    if (string.Equals(notification.ProtocolMessage.Error, "access_denied", StringComparison.Ordinal))
                    {
                        notification.HandleResponse();

                        notification.Response.Redirect("/");
                    }

                    return Task.FromResult<object>(null);
                },

                AuthorizationCodeReceived = async notification =>
                {
                    using (var client = new HttpClient())
                    {
                        //var configuration = await notification.Options.ConfigurationManager.GetConfigurationAsync(notification.Request.CallCancelled);
                        String tokenEndPoint = "https://identityserver.com/oauth2/token";

                        //var request = new HttpRequestMessage(HttpMethod.Post, configuration.TokenEndpoint);
                        var request = new HttpRequestMessage(HttpMethod.Post, tokenEndPoint);
                        request.Content = new FormUrlEncodedContent(new Dictionary<string, string> {
                            { OpenIdConnectParameterNames.ClientId, notification.Options.ClientId },
                            { OpenIdConnectParameterNames.ClientSecret, notification.Options.ClientSecret },
                            { OpenIdConnectParameterNames.Code, notification.ProtocolMessage.Code },
                            { OpenIdConnectParameterNames.GrantType, "authorization_code" },
                            { OpenIdConnectParameterNames.RedirectUri, notification.Options.RedirectUri }
                        });

                        var response = await client.SendAsync(request, notification.Request.CallCancelled);
                        response.EnsureSuccessStatusCode();

                        var payload = JObject.Parse(await response.Content.ReadAsStringAsync());

                        // Add the access token to the returned ClaimsIdentity to make it easier to retrieve.
                        notification.AuthenticationTicket.Identity.AddClaim(new Claim(
                            type: OpenIdConnectParameterNames.AccessToken,
                            value: payload.Value<string>(OpenIdConnectParameterNames.AccessToken)));
                    }
                }
            }
        });


    }
}
like image 537
TejSoft Avatar asked Jul 13 '15 06:07

TejSoft


People also ask

How does OAuth2 work in Web API?

For local login, Web API uses the resource owner password flow defined in OAuth2. The user enters a name and password into the client. The client sends these credentials to the authorization server. The authorization server authenticates the credentials and returns an access token.


1 Answers

To support the client credentials grant type, your best option is probably to directly use HttpClient:

var request = new HttpRequestMessage(HttpMethod.Post, "http://server.com/token");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string> {
    { "client_id", "your client_id" },
    { "client_secret", "your client_secret" },
    { "grant_type", "client_credentials" }
});

var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();

var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
var token = payload.Value<string>("access_token");

For interactive flows (like the authorization code flow), there are two better approaches:

  • If your authorization server supports OpenID Connect (which is based on OAuth2), you can simply use the OpenID Connect middleware for OWIN/Katana 3 developed by Microsoft: https://www.nuget.org/packages/Microsoft.Owin.Security.OpenIdConnect/

  • If OpenID Connect is not supported by your authorization server, one option is to create your own OAuth2 client middleware. You can take a look at the last part of this SO answer for more information: Registering Web API 2 external logins from multiple API clients with OWIN Identity

like image 98
Kévin Chalet Avatar answered Sep 30 '22 05:09

Kévin Chalet