This is my first article of 2023. I think it is the first in a series of articles about migrating an old ASP.net web app to Asp.net core on dotnet 7. Today, we will talk about migrating Old ASP.net authentication to Asp.net core identity with open id connect.

Recently, I’ve had to work on the migration of an ASP.net app that ran on dotnet 4.7, but was built back in 2011 with outdated libraries, but most importantly, an outdated authentication layer. This back end didn’t use ASP.net identity, it used “FormsAuthenticationTicket” which is something more outdated. Today, I will show you how to migrate an old authentication layer to ASP.net core identity with Open Id connect.

If you find this article useful, please follow me on Twitter,  Github, Linkedin, or like my Facebook page to stay updated.
Follow me on social media and stay updated

High-level concept

If you break things down to their basics, you will realize that any Authentication system simply relies on a database that has as primary table a “User” or “Accounts” table containing similar information for example, username, email, password, biography etc.… Taking this into consideration our aim here is to make every user of the outdated web app authenticate seamlessly on the new web app. Meaning that we should abstract the authentication process in such a way that OpenID connect and ASP.net Identity will replace the former authentication system without altering the end users experience.

Taking all the above into consideration, our first step is modifying the database model.

Upgrading the database schema

The former database schema used by the old authentication system must be updated to adapt itself to ASP.net core Identity. There are two ways to do this. This tutorial primarily focuses on migrating to ASP.net core Identity which can be used with open id connect, so open id connect isn’t really covered in this article.

NOTE: First test this in a dummy database before any updates to the production database.

  • Either you do it via SQL commands (You add columns, manually to the already existing users table and create new tables for Roles, Claims etc.)
  • You do a code first migration.

We will use the second approach since it is faster. For this, we will use Entity framework’s migration feature.

  • In case you want to add open Id connect to your project, I recommend you use the server templates provided by Duende checkout this video: https://www.youtube.com/watch?v=eLRGlnGGUQs
  • Choose the “isaspid” template if you want an already setup template with an initial ASP.net Identity configuration. To learn more about open Id connect with identity server, read this documentation: https://docs.duendesoftware.com/identityserver/v6
  • In the new ASP.net core project, create an application user, with the properties required by the old authentication system. This class should inherit from the identity user.

Note: in our case, the former User database used the “integer” type as Id, whereas Asp.net core Identity uses strings by default. So, we create our custom entities as follows.

NOTE: Only follow the steps below If your previous user table had Ids as integers or a numeric type.

Then, we create our identity user.

Then we create the db context to access the database.

  • The next step is to inform entity framework that it should use the old “Users” table to store future users and retrieve previous users for authentication.
    • And, in your old users table, you might have saved properties with names different from those used in Identity user. For example, in my database, the field UserName of my users was saved in the column “UName”, whereas in ASP.net core Identity, the column name is “UserName”. I need to tell entity framework about this difference.  Open your DBcontext we created above and add the following lines.
  • Configure access to your database using its connection string as stated in the documentation: https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-strings
  • Create your migrations using either your terminal or package manager console. Here is the command:   dotnet ef migrations add IdpMigration
  • This will create a “Migrations” folder, with a class named “IdpMigration” or the name you gave to your migration.
  • Inside the “up” method of this migration, if there is a “createTable” with “name:” being set to “users” or the name of your old users table in the database, remove that create statement.
  • Add “update” statements to add to this old table the columns present in the “IdentityUser” but absent in your old users table. Some of these columns include
  • Run the migration with the command “dotnet ef database update SecondMigration5”
  • This will add new columns to your users table, and create new tables in your database for user roles, claims etc.
  • Once you are done, your database should be ready. To test this, create a new user using the UserManager. To do this, at your server’s startup, you could run this demo code to create a new user.
  • If it fails, patiently inspect the errors messages, and correct them. These will most likely be errors related to already existing constraints on the database that are not respected by your models.
  • Once the user can be created without any issue, in case you used the open id connect template I precise earlier, run the project and try authenticating with the user credential you just created. In this step, you might still have errors due to constraints, but they will be minor errors.

Making your old users compatible to ASP.net identity

Our database schema has been updated, we can authenticate newly created users, but what about old users of the former web app?. They will not be able to authenticate using ASP.net Identity even if they are present in the database. This is because the UserManager’s findbyemail or username won’t return these old users no matter how many times you try. To make your old users compatible, follow these steps.

  • Run through every row of the users table in your database (Only rows for old users that where not ceated with ASP.net identity’s usermanager).  
  • For each user, apply the following computations. And add the appropriate claims to your users in the database. You might do this with a background job on your servers, or something similar.

Once you run this, fields required to make users authenticate with ASP.net identity will be set in the database. You will then be able to load users with ASP.net identity.

Password hash and validation

In case your former authentication system used a different method to hash and compare passwords, you need to inform ASP.net identity about this. Else, your old users’ passwords won’t be recognized by the system.

  • To do this, locate your old algorithm to hash passwords and create a new “PasswordHasher” that will combine your old password validation with the new most recent one provided by Microsoft, with all security updates and patches. Here is the password hasher:
  • Then, Tell Asp.net core to use your new password hasher that is compatible with new and old users. Do this by registering the service using DI as follows:

Conclusion

With the above, you should be able to migrate smoothly to ASP.net identity. When I did this at first, the process was easier than expected proving how flexible ASP.net core is. I’ll be posting about Web3 very soon, If your interested in crypto, here is an article I wrote about end-to-end encryption with RSA.

Follow me on social media and stay updated

4 comments

  1. Ashish Khanal

    Reply

    Great article! One question: How do I find the old password hashing algorithm? Any example for that?
    // TODO: Add your old password hashing algorithm here

    • Damien Doumer

      Reply

      I’m glad you liked it. By “old password hashing algorithm” I mean the algorithm that the former authentication system was using, you can find it in the old system and use it. It is specific to the authentication code base you’re trying to upgrade

  2. ayc

    Reply

    very helpful!. how to run through every row of the users table in your database?

    • Damien Doumer

      Reply

      Thanks. I’m glad you liked. In this example, I use EFCore, and a loop for that, but you could use an sql script or something more efficient. Actually depends on you.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.