Setting up an Idenity Server for your Xamarin app

Image showing a server rack

Have you ever wondered how hard it would be to set up a minimal viable authentication server that uses industry standards and usable from your mobile Xamarin application? Well, I have, and I believe in having found a solution that can be a great starting point and will allow you to expand the answer should you ever need to do so.

One common industry standard is OpenID / OAuth2, which provides a standardized authentication mechanism that allows user identification securely and reliably. You can think of the identity service as a web server that identifies a user and provides the client (website/mobile app, etc.) to authenticate itself with another application server that said client uses.

OAuth Code Flow Diagram

While the OAuth standard is open to anyone with a computer and an internet connection, I generally do not recommend writing your own implementation. My go-to solution for setting up an identity provider is the IdentityServer by Dominick Bayer and Brock Allen.

At the time of writing this post the IdentityServer5 has been released by Duende Software. A company founded by Dominick Bayer and Brock Allen. With that come some changes to licenses for companies. You can still use Duende IdentityServer for free for certain scenarios which you can find here. For this post however we will be sticking with IdentityServer 4.

IdentityServer4 is built based on the OAuth spec. It is built on the trusted ASP.NET Core but requires quite some know-how to get the configurations and other settings ready for use. Luckily my good friend Damien Bowden has created a quickstart template that you can install via the dotnet command line and then make your server. You can find the repository here on GitHub. After following the install instructions, we can create a server with the following command:

dotnet new sts -n XamarinIdentity.Auth

The solution is pretty much ready to go but let's look at the configuration of the IdentityServer in Config.cs and make some adjustments in the GetClients method. Based on the template, let's make some changes that leave us with the following final configuration:

public static IEnumerable<Client> GetClients(IConfigurationSection stsConfig)
{
    return new List<Client>
    {
        // mobile client
        new Client
        {
            ClientName = "mobileclient-name-shown-in-logs",
            ClientId = "the-mobileclient-id-of-your-choice",
            AllowedGrantTypes = GrantTypes.Code,
            AllowOfflineAccess = true, // allow refresh tokens
            RequireClientSecret = false,
            RedirectUris = new List<string>
            {
                "com.mallibone.oidcsample/authorized"

            },
            PostLogoutRedirectUris = new List<string>
            {
                "com.mallibone.oidcsample/unauthorized",
            },
            AllowedScopes = new List<string>
            {
                "openid",
                "role",
                "profile",
                "email"
            }
        }
    };
}

Generally, you can set the ClientName, ClientId, RedirectUris and PostLogoutRedirectUris to values of your choosing. The scopes represent the defaults. Further note that by setting AllowOfflineAccess to true, the user can request refresh tokens which means that as long as the refresh token is valid, the user will not have to log in but can use said refresh token to request a new access token. In mobile apps, this is generally the prefered behaviour since users usually have their personal device and therefore expect the app to "store" their login.

The only thing left before we can deploy this puppy is making sure we store our users.

Storing the login credentials in a database is good because having in-memory storage usually causes quite some frustration when restarting a service. The quickstart solution we have configured comes with a SQLite database per default. While you might outgrow the SQLite database at some point, if you only have a couple of users using it, it works very well. To use SQLite, you will have to set the Copy to output directory to Copy if newer of the userdatabase.sqlite or it will not deploy during a build. And please note that the SQLite database will be created anew on every deploy - so this is purely for development purposes. 😉

Please note that using the SQLite version is a quick and easy way to get your IdentityServer up and running locally and in the cloud. However, I am not saying you should not use MS SQL, Postgresql, MySQL or any other database that you might have already running in production. If you plan to use a different database anyway, feel free to configure the required changes in the ASP.NET Core startup.

Next, we will want to deploy our solution so a client can call it. Since the identity service is an ASP.NET Core web app, we can deploy it to any web server. For example, you could use Azure Web Service for this. Once the server is deployed, you can visit it, register new users and authenticate your clients. Of course, you can further edit the server to your needs and wishes, in which case the official documentation will be of great value.

And that's it - with these few changes, you have a fully running IdentityServer running in the cloud, and you can now start integrating it into your apps, knowing that you are using industry standards to authenticate and identify your users. You can find a sample on GitHub.

HTH

Title photo by panumas nikhomkhai from Pexels

Updated: