Browse to http://localhost:5000/api/Values and you should see a JSON response if everything worked well so far. (The webapi template adds a sample controller in Controllers/ValuesController.cs which is why this works.)

Setup VS Code (Optional)

Type code .. in the terminal to open the solution directory in VS Code. You'll be prompted with a dialog saying: Required assets to build and debug are missing from 'dotnet-identity-example'. Add them?

Answer Yes. This will add a .vscode folder with a build task and two launch configurations. You'll now be able to use F5 to debug the application within VS Code. Just remember to open the solution directory everytime, not the project directory.

Visual Studio (Optional)

Just open the dotnet-identity-example.sln file with Visual Studio. You can now use F5 to debug as usual (Cmd+Return on VS for Mac).

Add the User Model

In this case I've added only a FullName property to keep things simple. In case you need more properties for a user (eg. DateOfBirth), this is where you need to add them. Fields like the Id, UserName, Email, PasswordHash, etc. are defined in IdentityUser, so you don't need to re-define them. Here's the source.

You can also subclass the IdentityRole class if you'd like to customize it with additional fields. IdentityRole.cs source.

Now add an empty ApplicationDbContext with the appropriate constructors as follows:

I've tried and added steps for a few database providers. You should be able to figure your preferred (relational) database out, even if it's not on the list. This post assumes that you already know to configure EF anyway 🙃

For an InMemory database for testing replace UseSqlServer() with UseInMemoryDatabase(). I do not recommend using it for this exercise because you won't be able to query the database and see what's happening.

For MySQL use UseMySQL() instead.

For Postgress use UseNpgsql().

Creating the tables

Add a DotNetCliToolReference to the Web.csproj file for dotnet ef commands to work. The <ItemGroup> with <DotNetCliToolReference> tags should look something like this (with the first child element being the one I manually added):

We now need to include authentication in our application pipeline by adding the following right before app.UseMvc() in the Startup.Configure() method:

app.UseAuthentication();

By default Identity performs a 302 redirect to a login page for unauthenticated or unauthorized requests. While this behaviour is desirable for websites, an SPA might want to handle this locally. We can override the default authentication events by configuring the Application Cookie as follows:

The auth controller

Add the Login request ViewModel

Add a LoginViewModel class preferrably to a ViewModels/Auth folder in the project directory. The viewmodels will have the data required to perform a user login, which in most cases is a username (email address) and a password:

If you now add the [Authorize(Roles = "Role1")] attribute to the ValuesController, those actions will now only be accessible to logged in users that belong to Role1. (Pro tip: use a custom authorize attribute to keep your code clean. Here's how.)

Introduction to claims

Try the following:

Login using the Login API we just created.

Perform GET: /api/values. It should work, if it doesn't make sure that your HTTP client is sending cookies and try again from step 1. (Postman sends cookies out of the box.)

Now disconnect/shutdown/drop the database.

Perform GET: /api/values. It will still work.

Now perform a logout with POST: /api/auth/logout. This will unset the cookie.

Now try GET: /api/values again, and you'll see a 401.

You can't login again until you turn the database on again (or recreate it using dotnet ef database update), so please do whatever it takes to get things working again 😬

Notice how step 4 worked even though the database was disconnected? That route had an [Authorize(Roles="Role1")] which means that the role of the user accessing the API was being verified correctly without using the database. This was done using the claims present in the application cookie in the form of a bearer token.

Update the ValuesController.Get() method's body with the following to return the user's default claims:

The User property used above is populated in the AuthenticationMiddleware we added to the pipeline using .UseAuthentication(). If you're interested in the sources this is a good starting point: AuthenticationMiddleware.cs

GET: /api/values will now give a response similar to the following (you need to login using the login API first, ofcourse):

Notice how the roles of the user are present as claims?
You can also add custom claims and implement claims-based authorization. Claims can be attached to both Users and Roles. (Refer to the database diagram above and it'll make sense.)

On a sidenote ASP.NET Core has a lot more authentication options out of the box compared to ASP.NET MVC 5. And you can use policies to mix and match. Super flexible if you ask me.

Next Steps

There's a lot more I'd love to cover, but this post has already gotten too long. These should help you get going in the right direction:

🚒 For the brave try replacing EF with something else like Dapper. Identity seems to be quite flexible, perhaps try getting it to work with a document based database like MongoDb using a custom implementation?

Also, Microsoft Docs is awesome and has Identity documented very well 🙌.