One thing I’ve struggled with for the past few years is how to properly do authentication and authorization for web applications – but specifically, ASP.NET Web API (and now, ASP.NET Core Web API). In my professional opinion, building “API first” applications is the future. You build a proper, documented (via HATEOAS and Swagger), secure REST endpoint and you can have any kind of front-end you want: a web app, mobile apps, Windows UWP apps, etc.
That’s great, but how can you properly do the authentication and authorization of those sorts of REST services? I mean, you see people talking about OAuth2, but gadzooks that is super complicated.
The old-fashioned way:
I’ve been approaching this whole prospect from: I have an API, so I’m responsible for managing the user and logging the user in. But wait, that also means I’m responsible for:
- Logging the user in – including account lock-out and potentially “I’m not a robot”. Also needs to be protect against CSRF and other client-side exploits.
- Support for 2FA, ideally a Google Authenticator code – or generating a cryptographically-strong number and using SMS.
- Logging the user out / expiring the session.
- Registering a new user – which includes verifying the e-mail address (or phone, via SMS), and perhaps having a scheme for one-time-passwords (OTP)
- Forgot my password – including a way to send e-mails/SMS to the user, and making sure that isn’t hackable.
- Verifying the user for each call – most API calls will need to know who the user is, and that their session/credentials/token is still valid
So by this time I’m thinking:
This whole identity management part is a full-on application, all by itself! Plus, this MUST be extremely well-written and very secure. If this is to be the security of my application, this needs to be “hack-proof”.
The worst part about this approach is all of this work is just if I wanted to store the username and hashed-password in my database. What if people wanted to use social logins? That would be a fundamentally different approach. I haven’t even gotten to the business of what my website is for – I’m looking at a month of development JUST to handle authentication and authorization, which won’t even give me my ideal setup.
Wouldn’t it be ideal to support BOTH local logins and social logins? Well, this approach above can’t readily support that.
Using JWT and other simple tokens:
Despite this, I did explore several different ways to have a /api/login Web API controller action, and have it issue a “bearer token”. I kept coming back to the same problems. I needed to write a LOT of code to account for many things (resetting password, verifying credentials, refresh tokens, etc.).
Then, looking at the functionality built-in to ASP.NET where you can use social logins, this has always, and continues to be a mess. I’ve invested dozens of hours going through code samples and I’ve not ONCE been able to get this approach working with Web API. It seems to only be for ASP.NET MVC.
Not only did all of this smell like I was barking up the wrong tree, this was going to take a lot of work. There MUST be a better way.
Going back to “school”:
I’m lucky enough to have a subscription to Pluralsight through work and we’re also evaluating enterprise access to Udemy too. So, I searched for ASP.NET Core Web API and went through each of the courses. I specifically was looking to see how they did the authentication and authorization.
Perhaps the most notable was from Pluralsight – check out the API courses from Kevin Dockx, they are just excellent: https://app.pluralsight.com/profile/author/kevin-dockx
I also scoured the net, including Stackoverflow and I was able to finally draw some conclusions.
OAuth2 and OpenID:
It took me a long time to accept it, but the answer truly must be to use OAuth2 (for identity management) and OpenID (to get details/profile about who that user is). I say “long time” and “finally” because the complexity of this has been daunting. “Daunting?”, you ask. Yes – from the IdentityServer website for example:
Where do I even begin? Each box and line of this diagram is a significant piece of functionality with several different possible “flows”. That’s when I finally got it, especially from watching Kevin Dockx’s course on OAuth2 and OpenID. I REALLY shouldn’t be writing any of this, I should be using a pre-built library and stand-up a separate auth site – or just use a 3rd-party provider.
This represents a fundamental change in how we write applications. In the olden days, we used to write T-SQL statements can get “grids of data” back, called recordsets. Then, Entity Framework (and other ORM tools) changed how we access data. Similarly, we used to manage a lot of that authentication and authorization of our users – but in todays world or many different kinds of clients (web, mobile, and desktop), we simply must “trust” this new technology to manage that for us.
Build vs Buy (assemble vs buy):
I was approaching this all wrong. There is no scenario where I should be building something as foundational (and complicated) as authentication and authorization. I need to use a 3rd-party vendor, or use a pre-built system which I can assemble myself.
Build (or assemble):
This is the concept of you building your own OAuth2 and OpenID website using 3rd-party components. Much of the actual overhead is taken care of for you, but there is still quite a bit of configuration you have to do. Presumably, you’d manage this authentication endpoint as a different website – like secure.mycompany.com versus api.mycompany.com.
I say “assemble”, as opposed to “build” because this should really just be about using a 3rd-party library to assemble an OAuth2 and OpenID endpoint. For example: https://identityserver.io/ which comes in the form of Nuget packages, for .NET and .NET Core projects:
They have great documentation starting here: https://identityserver4.readthedocs.io/en/release/ this is as “simple” as creating a new, empty ASP.NET Core website, and they walk you through the different pieces you need. Start in the “Quickstart”.
Buy (but it’s actually “free”):
This is the concept where you register your app with a 3rd party and let them manage/own your user accounts. Your users (invisibly) interact with the vendor, and you trust identities that come from that vendor.
I can’t find the course right now, but I think it was from an author in some Udemy courses who consistently used: https://auth0.com/ in all of his samples.
Before you rule this out, there are a few REALLY significant factors with using Auth0:
- It’s FREE for up to 7,000 users and up to 2 social identity providers: https://auth0.com/pricing
- It’s got a really nice, modern, professional user experience for: register, login, forgot my password, etc.
- Has pre-made functionality for web clients and mobile platforms (in different programming languages)
- Is completely customizable to seamlessly look like part of your application.
- It seems pretty popular and several major companies use them.
If you are already in-bed with Microsoft Azure, you can also leverage AzureAD for this too: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols-oidc
The downside here is that this does cost some money (you must have an active Azure subscription) and with both of these scenarios, you are locked-in with these vendors. Also, if/when someone hacks these vendors, it affects your application too.
I’ve been in a bit of a holding-pattern for quite a while because of this. I want to build ASP.NET Core Web API back-ends, and have web and mobile front-ends over that. However, without a proper, easy, reproducible way to do identity management, I’ve been stuck.
Now that I’ve “accepted” that OAuth2 and OpenID are how we all MUST go, that makes it a lot easier. What approach will I take? I’m not sure yet. I stopped to write this post while I was in the middle of building out an IdentityServer4 endpoint. I also started to build out an Auth0 test site. I’m very hesitant to hand over identity of my users to a vendor, especially if I’m not paying anything. Worse, what if Auth0 goes in a direction I don’t like – can I “export” my user database and bring it into another provider? Probably not very easily. However – it’s basically turn-key and free to use a vendor like Auth0, which is very tempting.
So for me, I don’t know which path I’d take for new, internet-facing applications – but now that I know the direction I need to head, it’s just a matter of fleshing each of the ideas out and see what works best.
Are you already using a 3rd-party library or service for authentication/authorization for your API? If so, please leave a comment below.