Securing a .NET 4.6.x API with OpenID Connect

Introduction

OpenID Connect is powerful… and confusing. If you have ever experienced the frustration of adding authentication/authorization to an API built on .NET 4.6.x where the token comes from an OpenID Server, then you have come to th…


This content originally appeared on DEV Community and was authored by Isaac Adams

Introduction

OpenID Connect is powerful... and confusing. If you have ever experienced the frustration of adding authentication/authorization to an API built on .NET 4.6.x where the token comes from an OpenID Server, then you have come to the right place. I have accomplished this and can help you implement it in this guide.

Here are the requirements of the system we will be implementing.

  • protect legacy API from unauthorized access
  • only requests that include a valid bearer token (access_token from identity server) will be allowed
  • identity server should issue a valid access_token to our configured client

Protecting the API

In this particular instance, I want to protect a legacy application from unauthorized access. That kind of requirement calls for an API resource to be made. API resources are configured on the identity server and are used to protect API(s) from unauthorized access. Does it sound like I am repeating myself? Good. So, I added the following code to my self hosted identity server which sits on a .NET core application.

new ApiResource()
{
    Name = "legacy",
    Description = "protects the legacy API from unauthorized access",
    ApiSecrets = new List<Secret> { new Secret("secret".Sha256()) },
    Scopes = new List<Scope>
    {
        // only interested in a single scope for this purpose
        new Scope("legacy.access", "grants access to use the legacy API")
    }
}

Now I need to add authorization to the legacy application. First, add the IdentityServer3.AccessTokenValidation nuget package to your .NET 4.6.x web app.

Next, in Startup.cs, add the following code.

using Owin;
using Microsoft.Owin;
using IdentityServer3.AccessTokenValidation;

[assembly: OwinStartup(typeof(ema.Web.Startup))]
namespace ema.Web
{
    public class Startuptemp
    {
        public void Configuration(IAppBuilder appBuilder)
        {
            appBuilder.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
            {
                Authority = "https://localhost/identityserver", // this will ultimately change per environment and therefore come from configuration
                ClientId = "legacy",
                ClientSecret = "secret", // this should be populated through configuration
                RequiredScopes = new[] { "legacy.access" },
                ValidationMode = ValidationMode.ValidationEndpoint,
                EnableValidationResultCache = true
            });
        }
    }
}

This will enable the use of the [Authorize] attribute and respond to any request with 401 Unauthorized unless it has the Bearer Authorization header with a valid access_token issued to it from the identity server with the legacy.access scope.

Yes, the ClientId and ClientSecret should match the Name and ApiSecret you configured in the ApiResource.

Fetching the access_token

The last piece is getting the access_token which will be added to the Authorization header for making authorized requests to the legacy app.

In order to see this in action, we will need a client that can make an authenticated request to the identity server for the token.

Add the following configuration to your identity server.

new Client()
{
    ClientId = "client",
    ClientSecrets = new[] { new Secret("client-secret".Sha256()) }, // the secret should be populated through configuration
    AllowedGrantTypes = GrantTypes.ClientCredentials,
    AllowedScopes = new[] { "legacy.access" },
    AccessTokenType = AccessTokenType.Jwt,
    Enabled = true,
}

By adding legacy.access, we are saying that this client can generate an access_token that will include the legacy.access scope.

Using postman (or whatever tool you use), construct the following request given that your identity server is hosted @ localhost/identityserver

!! NOTE: make sure your request parameters are formed as application/x-www-form-urlencoded content type

POST /identityserver/connect/token HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 89

client_id=client&client_secret=client-secret&grant_type=client_credentials&scope=legacy.access

the expected response should look like the following

{
  "access_token": "xxx.xxx.xxx",
  "expires_in": 3600,
  "token_type": "Bearer"
}

Using the access_token

Lets setup a controller in our legacy app

using System;
using System.Web;
using System.Web.Http;

namespace Legacy
{
    [RoutePrefix("api/test")]
    public class TestController : ApiController
    {
        [HttpGet]
        public IHttpActionResult Test()
        {
            return Ok("Hello World");
        }

        [Authorize]
        [HttpGet, Route("auth")]
        public IHttpActionResult AuthTest()
        {
            return Ok("Authorized: Hello World");
        }
    }
}

Make sure your controller is properly registered in your app by hitting the endpoint that doesn't have the [Authorize] attribute.

Now, take the access_token you generated and place it inside the Authorization header (prefixed with "Bearer") and make a request to the AuthTest() endpoint

GET /legacy/api/test/auth HTTP/1.1
Host: localhost
Authorization: Bearer xxx.xxx.xxx
  • If the response is 401 Unauthorized ❌, something is not configured properly ?
  • If the response is 200 OK ? and the content is Authorized: Hello World, you are in business ✅


This content originally appeared on DEV Community and was authored by Isaac Adams


Print Share Comment Cite Upload Translate Updates
APA

Isaac Adams | Sciencx (2021-09-08T21:16:51+00:00) Securing a .NET 4.6.x API with OpenID Connect. Retrieved from https://www.scien.cx/2021/09/08/securing-a-net-4-6-x-api-with-openid-connect/

MLA
" » Securing a .NET 4.6.x API with OpenID Connect." Isaac Adams | Sciencx - Wednesday September 8, 2021, https://www.scien.cx/2021/09/08/securing-a-net-4-6-x-api-with-openid-connect/
HARVARD
Isaac Adams | Sciencx Wednesday September 8, 2021 » Securing a .NET 4.6.x API with OpenID Connect., viewed ,<https://www.scien.cx/2021/09/08/securing-a-net-4-6-x-api-with-openid-connect/>
VANCOUVER
Isaac Adams | Sciencx - » Securing a .NET 4.6.x API with OpenID Connect. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/09/08/securing-a-net-4-6-x-api-with-openid-connect/
CHICAGO
" » Securing a .NET 4.6.x API with OpenID Connect." Isaac Adams | Sciencx - Accessed . https://www.scien.cx/2021/09/08/securing-a-net-4-6-x-api-with-openid-connect/
IEEE
" » Securing a .NET 4.6.x API with OpenID Connect." Isaac Adams | Sciencx [Online]. Available: https://www.scien.cx/2021/09/08/securing-a-net-4-6-x-api-with-openid-connect/. [Accessed: ]
rf:citation
» Securing a .NET 4.6.x API with OpenID Connect | Isaac Adams | Sciencx | https://www.scien.cx/2021/09/08/securing-a-net-4-6-x-api-with-openid-connect/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.