19

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


    }
}
TejSoft
  • 3,213
  • 6
  • 34
  • 58

1 Answers1

35

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:

Kévin Chalet
  • 39,509
  • 7
  • 121
  • 131
  • I have made some progress and was able to get tokens back from identity server. But what I want is a "Client Credentials" flow, where I will not need to enter any login and password. Token should be issued based on Client Id and Client Secret. Somehow I was not able to configure that. I have updated the question with my current code. – TejSoft Jul 16 '15 at 06:56
  • 1
    This is now a different question I'm afraid. Your original question, though using imprecise terms, suggested that you were using the authorization code flow: "these can be used to obtain an authorization key, which in turn can be used to get an access token". The OIDC middleware developed for Katana 3 doesn't support non-interactive flows like the resource owner password credentials flow or the client credentials flow. You'll have to directly use `HttpClient` with `grant_type=client_credentials`. Which authorization server are you using? – Kévin Chalet Jul 16 '15 at 09:21
  • Yes, things got clearer when I started implementing it. I am using a Java based Identity Server called WS02. If Katana 3 cannot be used for "Client Credentials" do you recommend any other nuget package? Any examples? – TejSoft Jul 17 '15 at 00:30
  • [IdentityServer3](https://github.com/IdentityServer/IdentityServer3) this is fantastic and enables all the flows you'll ever need – Ian Apr 07 '17 at 08:57
  • Postman has more parameters for ***GET NEW ACCESS TOKEN*** `1) Token Name 2) grant_type = client_credentials , authorization_code, implicit, password credentials 3) Access Token Url 4) Client Id 5) Client Secret 6) Scope: read:org 7) Client Authentication: Send client credentials in body, Send as Basic Auth Header` – Kiquenet Feb 22 '18 at 17:08
  • I would be interested in an up2date OAuth2 Client solution for .Net (core) like a tiny nuget package. Can someone point to it? – Falco Alexander Feb 17 '21 at 07:41