User Authentication in ASP.NET WEB API 2 with RSA-signed JWT Tokens (part 2)

published in Android Development, iOS Development, Tutorials
by Michał Zawadzki

In the second part on JWT Tokens we will implement a basic user authentication in a REST app based on ASP.NET WEB API 2.

In the first part we’ve learnt about JWT structure and found out how Tokens are working. In the following examples we will use RSA for signing (an asymmetric coding algorithm) and Unity as a dependency injection container.

JWT Token example

To create, sign and validate tokens you can use an existing library provided by Microsoft: System.IdentityModel.Tokens.Jwt. You can download it right through NuGet. JWT Token example

User Authentication

The architecture of our app

MembershipProvider

In the beginning we create a new class (MembershipProvider), which is responsible for downloading claims and validating the user.


using System.Collections.Generic;
using System.Security.Claims;
using Zaven.Practices.Auth.JWT.Providers.Interfaces;
...
public class MembershipProvider : IMembershipProvider
    {
        public List GetUserClaims(string username)
        {
            List claims = new List();
            claims.Add(new Claim(ClaimTypes.Role, "Admin"));
            claims.Add(new Claim(ClaimTypes.Email, "admin93@gmail.com"));
            return claims; 
        }

        public bool VerifyUserPassword(string username, string password)
        {
            if (username == "admin93" && password == "password")
                return true;
            return false;
        }
    }

RSAKeyProvider

RSAKeyProvider is responsible for providing the RSA key to encrypt/decrypt the JWT Token. In our example the RSA key is downloaded from a file in our repository, but in a real case scenario it should be kept in a safe place somewhere else.

using System;
using System.IO;
using System.Threading.Tasks;
using System.Security.Cryptography;
using Zaven.Practices.Auth.JWT.Providers.Interfaces;
...
public class RSAKeyProvider : IRSAKeyProvider
    {

        private string rsaKeyPath;

        public RSAKeyProvider()
        {
            rsaKeyPath = AppDomain.CurrentDomain.BaseDirectory + @"RsaKeys\RsaUserKey.txt";
        }

        public async Task GetPrivateAndPublicKeyAsync()
        {
            string result = await ReadPrivateAndPublicKeyAsync();
            if (string.IsNullOrEmpty(result))
            {
                string key = CreatePrivateAndPublicKey();
                Boolean isInserted = await InsertPrivateAndPublicKeyAsync(key);
                if (isInserted)
                    result = key;
            }
            return result;
        }

        private string CreatePrivateAndPublicKey()
        {
            RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider(2048);
            RSAParameters publicKey = myRSA.ExportParameters(true);
            string publicAndPrivateKey = myRSA.ToXmlString(true);
            return publicAndPrivateKey;
        }       

        private async Task InsertPrivateAndPublicKeyAsync(string key)
        {
            Boolean result = false;
            try
            {
                using (StreamWriter fileStream = new StreamWriter(rsaKeyPath))
                {
                    await fileStream.WriteLineAsync(key);
                    result = true;
                }
            }
            catch(Exception ex)
            {
                Debug.WriteLine(ex.Message);
                result = false;
            }
            return result;            
        }

        private async Task ReadPrivateAndPublicKeyAsync()
        {
            String result = null;
            try
            {
                using (StreamReader fileStream = new StreamReader(rsaKeyPath))
                {
                    result = await fileStream.ReadToEndAsync();
                }
            }
            catch(Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }          
            return result;
        }
}


The RSA key is generated in the CreatePrivateAndPublicKey() method using the existing RSACryptoServiceProvider class. The ToXmlString(true) method generates both public and private, while ToXmlString(false) only the public one.

In the next part we’ll move on to AuthService. This is the most important element of the application because it’s responsible for creating, signing and verifying the incoming JWT token.

Sources:

Michał Zawadzki Back-end Developer

Michał is at the Back-end site of our software team, specializing in .NET web apps. Apart from being an excellent table tennis player, he’s very much into sci-fi literature and computer games.

Popular posts

Effortless deployment of Azure CosmosDB JS functions with GitLab-CI

Effortless deployment of Azure CosmosDB JS functions with GitLab-CI

Working with CosmosDB JavaScript triggers and stored procedures can be problematic, especially when your application consists of three or four separate development environments. The solution we need is found in the effortless deployment of Azure CosmosDB JS functions with GitLab-CI.

Read more
Interviews with startup founders: Fonn Byggemappen

Interviews with startup founders: Fonn Byggemappen

Fonn Byggemappen is an iOS, Android and web application for construction industry projects. The tool’s co-founder Jan Tore Grindheim told us about the beginnings and crucial moments of the app.

Read more
Core ML: Machine Learning for iOS

Core ML: Machine Learning for iOS

You have probably heard phrases like “Machine Learning” or “Artificial Intelligence” without knowing exactly what they mean. In this article, I will shed some light on “What Machine Learning is” by showing you a Core ML iOS sample.

Read more
Mobile Apps

Get your mobile app in 3 easy steps!

1

Spec out

with the help of our
business analyst

2

Develop

design, implement
and test, repeat!

3

Publish

get your app out
to the stores

Contact us

Hire us now!

back to top