ASP.NET C# MVC Core

Authorizing your .NET Core MVC Core API requests with OpenIddict and Identity

OpenIddict is an excellent open-source library for dealing with OAuth and OpenID in the new MVC Core (previously known as MVC6) for .NET Core. At first, I dreaded having to relearn this process; OAuth Bearer Tokens in MVC5 was dicey and kind of annoying to get the hang of. But, OpenIddict is pretty straight forward.

Note that out-of-the-box, OpenIddict returns opaque/encrypted tokens, not JWT. However, you can enable JWT very simply shown in an example below.

If you want to skip to the end, here is a Gist of my Startup.cs file with CORS and OpenID enabled.

Setup OpenIddict-Core

Install Package

To use OpenIddict, the first thing you need to install is the OpenIddict Core package and the AspNet.Security.OAuth.Validation:

{
  "dependencies": {
    ...
    "OpenIddict": "1.0.0-*",
    "AspNet.Security.OAuth.Validation": "1.0.0-alpha1-final",
    ...
  },
}

Setup Middleware

Then, we need to modify our startup to hook OpenIddict into our middleware pipeline. In your Startup.cs, you should see something like this in the ConfigureServices(IServiceCollection services) method:

services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

This is the first spot we hook into to give OpenIddict Identity resources. Update to the following:

services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders()
    .AddOpenIddict();

Next, we need to add OpenIddict to the HTTP pipeline. Again in Startup.cs, you should see something like this:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseMvc();
    }

After “app.UseMvc()”, we are going to add “app.UseOpenIddict()” to add OpenIddict to the pipeline, and “app.UseOAuthValidation()” to enable validation of the bearer token. Ordering matters! When first trying this, I put UseOpenIddict first and nothing worked. So, your new method should look something like this:

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
        
        app.UseOAuthValidation(); // enabled auth through bearer tokens

        app.UseMvc();

        app.UseOpenIddict(builder =>
        {
            // Lots of configuration options on builder.Options. 
            // For example, you can enable JWT tokens with:
            //    b.Options.UseJwtTokens();
            // We will stick with defaults for this tutorial, however.
        });
    }

Requesting tokens

Now try using Postman or a similar HTTP request tool. Here’s how to get your tokens.

The base URL for getting tokens is:

http://__yourdomain__/connect/token

Keep in mind, your request MUST be with the Content-Type “application/x-www-form-urlencoded”. As such, you will need to send a URL encoded request body if you’re using a JavaScript XHR request – but we’ll get this. For now, let’s just use Postman or your tool of preference.

Getting access token

To get an access token, you need to send the following data to “/connect/token”:

{
    username: "",
    password: "",
    grant_type: "password"
}

The response match this interface:

interface IOpenIdToken {
    access_token: string;
    scope: string;
    refresh_token: string;
    expires_in: number;
    expires_at: number;

    // if bad request
    error: string;
    error_description: string;
}

Here are two example requests in Postman:

goodopeniddict
Successful request
badopeniddict
Unauthorized request

You can now add the access_token to your “Authorization” header, with the value prefixed by “Bearer “. I.E:

Authorization: Bearer CfDJ8E2BjLxchpVOrXVMvbuOceoB-fxQqJeES9kImNIzPKuZ5pHtNmz8sDb_1i-FcitoxX2tp88Z8GBjxbIPXyjI3oVRyCBFh8fTD3SbqEZPWU6O59m8QPGdTbw3OByNkQ2tXG9TIa4coul3uqdHS6RzctRefmc2ZjoKQQhxDdURVxZbkI7L2mKTytqQcezMvZhJviN01M93O723wZkYlKDQVJep_KnEoWrIdeDtXsyA6EJBTOMxEFJYAW6IBMadSjDqHZU5BdIkj24Wy9HsnLTKQtazJ-v8JLQ2hmD_xoR1jUvwTfdw1c3OHxPdtLtVb1SPHTa43V71iyIxXFZe7vBna9d_UgBL4bSvUw8bOPQA80rjAtGqZBtlMX0A9o_BGXBLBcd4raw2xvYPOUnnA6sn85o3p9cnyb4ndCNkDF00z4uGkgaddviUxOWmTANkZ9N8_Yf18SO_zzFT-ijmktQ2XAFjG74q5l_gLrhPXCZsh7n8xRxPf_cxdKeEyF_RHeIa3iH_w23kIA_xC26JDo4ZtZrXlolev2Ft27DRutwb44BYXqivBr6WpVXHjiYeLsvWOapUe-hcACuK9GAUk9AclZjMnQaPiGl9SD6MlYauZFC9Va3wyY3h5blpukVrBCVtPfive5cDBuV8Lcde_5CREmM

Now your API requests will be authorized and your static User will be retrieved using the bearer token.

Getting a new access token using the refresh token

Did you notice the “refresh token”? If you’re not familiar with the idea of a refresh token, it is simply a way for the application to get a new access token after expiration without requiring the username and password. To get a new access token with the refresh token, the request is similar and also to “/connect/token”.

For example:

goodopeniddictrefresh

Now we have a new access token! Note that the refresh token is long-living, so it should be treated securely.

Setup cross-origin requests with the new AspNetCore.CORS

Install package

If you’re trying to make these requests through a different site, you’ll need to enable CORS, or you’ll see the always-fun “no ‘access-control-allow-___’ header is present on the requested resource” error. To do this, we need to install the new CORS package.

{
  "dependencies": {
    ...
    "Microsoft.AspNetCore.Cors": "1.0.0-rc2-final"
    ...
  },
}

Adding CORS middleware

Again in the startup, find the ConfigureServices(IServiceCollection services) method. At the top of the method, add the following:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors();
    ...

Now in Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory), add app.UseCors. For example:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseCors(builder =>
            // This will allow any request from any server. Tweak to fit your needs!
            // The fluent API is pretty pleasant to work with.
            builder.AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowAnyOrigin()
        );

        app.UseOAuthValidation();
        app.UseMvc();
        app.UseOpenIddict();
    }

Keep in mind that ordering matters when setting up the HTTP Request pipeline.

JavaScript requests

Requesting tokens through JavaScript XHR

When requesting for tokens, you must use the content-type header of “application/x-www-form-urlencoded”. OpenIddict will reject the request if you don’t, with a friendly error message (yay for that!). You must also encode your data into a form string. For example:

{
    "grant_type": "password",
    "username": username,
    "password": password,
    "scope": "offline_access profile email"
}

should be sent a string value of:

grant_type=password&username=myusername&password=mypassword&scope=offline_access profile email

I wrote a small, probably not ready for production, method to do this conversion for me (in TypeScript):

private urlEncodeValues(data: any) {
    var str = "";
    for (var key in data) {
        if (data.hasOwnProperty(key)) {
            str += `${key}=${data[key]}&`;
        }
    }
    return str;
}

Requesting API data through JavaScript XHR

When making authorized API requests, you need to make sure to add the authorization header mentioned earlier in the post.

Creating user accounts through Web API

This is not OpenIddict’s responsibility, so you need to create your own controller to handle creating users. After the user is created, you can request tokens immediately. Here’s a quick example of my AccountController WebAPI:

[Route("api/account")]
public class AccountController : Controller
{
    private readonly UserManager<ApplicationUser> _userManager;

    public AccountController(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }

    [HttpPost]
    public async Task<IdentityResult> Register([FromBody]ApplicationUserDto dto)
    {
        var user = new ApplicationUser { UserName = dto.Username, Email = dto.Email };
        var result = await _userManager.CreateAsync(user, dto.Password);
        return result;
    }
}

An example request to this would be to the “/api/account” resource:

{
    "Username": "kerry",
    "Email": "ritter@kerryritter.com",
    "Password": "mygoodpassword"
}

All set!

You should now be able to register users, authorize users, make authorized requests to your web API.

If you have questions, please use OpenIddict-core’s Gitter chat. I unfortunately have not had time to keep up with OpenIddict releases and will not be of too much help.

18 Comments

    1. What is the grant_type in your request? You should only see that message if you use client_credentials… Also, what version of OpenIddict are you using?

  1. Hey Kerry!

    Sorry to be a bother, but I am starting to use OpenIddict for a project I’m working on and have one problem… I’m using EF 6 instead of EF Core. I’ve seen in the OpenIddict readme (as well as in a few issues created on GitHub) that it is possible to use EF6, but I’m just not sure which entities/stores I need to implement/override in order to leverage EF6 with OpenIddict.

    Do you by chance know what needs to be implemented for this?

    Any help would be much appreciated!

    Thanks!

    1. Perhaps, but MVC5’s bearer token provider also provided a bit of configuration – however, there were templates to automatically configure this. What are your errors?

  2. Got a 404 error on POST request to /connect/token. Though when I send it with some missing properties (e.g. username or password) it fails with message about missing properties. So it seems to work, but doesn’t produce token.
    Any ideas? Do I need to implement custom authentication handler?
    OpenIddict version is ‘1.0.0-alpha2-0448’. OAuth.Validation is ‘1.0.0-alpha3-0188’.

  3. Hi

    I am using Version “”1.0.0-*” and when I want to test the endpoint according your sample, I get this error : “The token request validation process was skipped because the client_id parameter was missing or empty”

  4. Great article. I finally got Openiddict installed in my project and it is validating correctly when you don’t provide a required field example:

    “`
    {
    “error”: “invalid_request”,
    “error_description”: “The mandatory ‘grant_type’ parameter was missing.”
    }
    “`

    However, when I pass the username, password and grant_type I am getting a 404 instead of what I would have expected to be a 200. Is this normal? Keeping in mind I haven’t built the authorization controller and/or account controller yet.

  5. Hello
    At the Start , you say look for :
    services.AddIdentity()
    .AddEntityFrameworkStores();
    But this is not anywhere in Startup.cs if you actually have Created the Project with Web API Template not Web Application ! but if we create Web Application Template and Also choose `Individual User Account` for Authentication Type , Everything goes wrong please make your Guide a Step by Step for Absolute Beginners and also send some Http Requests to the built API at the end of the tutorial.

Leave a Reply

Your email address will not be published. Required fields are marked *