Token-Based Security, OAuth 2.0, OIDC and IdentityServer4
We'll learn the basics of token-based security, OAuth, OIDC basics, and set up an ASP .NET Core Web Application with IdentityServer4 package.
Join the DZone community and get the full member experience.Join For Free
We all know the username/password mechanism of login to a web application. We also might have heard, used, or implemented authentication/authorization systems, with or without frameworks.
Token-based security is one of the common mechanisms to secure backend APIs.
A common architecture for web applications typically consists of a web client app (e.g. an Angular or React frontend), a backend API (written in .NET Core, Java, or NodeJS), and a database for persistent.
In token-based security, generally, web client applications send tokens, representing consent, to an API. So, Instead of sending over Username, Password on each call to the API, the client app sends a token. These tokens represent consent, for example, consent, granted by the user to the client application to access an API on behalf of that user. A token can then be used on the client or can be passed to the API.
Home-grown token services e.g. self-created login endpoints that accept username, password and return a JSON Web Token are one of the options. This is already an improvement because we are no longer sending username/password on each request. We are sending it once to get a token and afterward, we can send this token to APIs.
Central Identity Provider
Let’s think about identity and access management related tasks:
- Users Registration and Management,
- Locking out users,
- Password policies, strength, resets,
These are tedious tasks and prone to change. It's better to handle at a central location, at the IDP level, so, it can be reused across applications.
So, instead of building our own authentication/authorization for different kinds of applications. If we can use an IDP (Identity Provider) to simplify these tasks for us and follow a standard, a way to ensure these tokens are safe enough to use for both authentication and authorization purposes for different types of applications, i.e., a proven protocol that’s safe for authentication and authorization and handles these common concerns.
And that’s what we will cover in this and upcoming posts.
Scenario 1: Web Application
In our basic scenario, a Web app client needs to communicate with the API tier. So, how do we create trust in this environment? How can we make sure that when we have an app client that’s not running on any machine that we control, but it's going to be entirely on our user’s machine (e.g., an Angular app). How can we trust the information that it sends to us? We will see that this can be done by using Open ID Connect (OIDC).
OAuth 2.0 is an open protocol to allow secure authorization in a simple and standard method from web, mobile, and desktop apps.
OAuth 2.0 is about authorization, i.e., a client application can request an access-token and pass this access-token to an API to gain access to an API.
But, we also know there are different types of applications. A server-side ASP .NET MVC App has different means of storing things like secrets than, e.g., an Angular application, which completely runs in the client and it’s just not to be trusted by default.
So, OAuth 2.0 also defines how an application can securely get such token from STS (security token service), or in other words, how a client application securely achieves authorization.
We can already feel that homegrown endpoints are replaced by endpoints from the OAuth standard. The standard also defines how to use these endpoints for different types of client applications.
One thing to note: These access-token should only be used to access resources, an API. They shouldn’t be used to sign into client applications. That’s authentication, not authorization.
Authorization gives you access, Authentication is what identifies you, who you are.
So if OAuth is only authorization, then how about the identity, where it comes from?
OpenID Connect (OIDC)
This is the other half of the puzzle. OpenID connect complements OAuth 2.0 with authentication (identity).
As mentioned before, OIDC is a simple identity layer on top of the OAuth 2.0 protocol, so it extends OAuth2.
With OIDC, an application can receive an identity token (next to the access token) if it needs one. This identity token can then be used to sign in to an application, while the same application uses the access token to access an API.
It also defines an additional endpoint that can be used by an application to get additional user information. That’s the UserInfo endpoint.
Like before, the same principles apply. It defines how different types of client applications can safely get those tokens from STS.
OIDC is not just for new apps or API-based apps. You can use it even with apps that don’t talk to an API.
Luckily, we do not have to implement most of this. There are some great frameworks available that do most of the heavy lifting. IdentityServer4 is one of them, which we will be using later for the demo.
JSON Web Tokens (JWTs)
OIDC uses JWTs, which you can obtain using flows conforming to the OAuth 2.0 Specs. STS will actually issue JWTs and sign them. JWTs payload contains user-specific information:
Let’s see 3 different JSON web tokens:
1. ID Token
Contains user identity information.
2. ACCESS Token
Contains scopes and groups for users and this is what you will send along with the request to API. When we are talking to API, the API knows where to look for the access token. If a valid access token is present means we are authorized to use resources.
3. Refresh Token
Used to get new ID-Token and ACESS-Token.
Identity Solution (How to Choose)
- Your Own => (No, you shall try not to build your own solution from scratch).
- Framework (It is recommended to use a framework/middleware, e.g., Identity Server).
- SASS/PASS on cloud (e.g., AWS Cognito, etc.).
We will be using IdentityServer4 for the demos.
These endpoints are required by the standard (when we use IdentityServer4, those are automatically setup for us):
- New Access-Token request (certain flows, i.e., different ways).
Can be used in the following cases:
- New Access-Token request (Certain flows).
- Refresh Access-Token.
- Trade Authorization-Code for an Access-Token.
- Revoke an Access or Refresh-Token.
The following end-points are part of OpenId Specifications:
- /.well-known/openid-configuration (list endpoints and configs)
- /.well-know/jwks (list info about JWT signing keys. used for token validation)
Getting Started With IdentityServer4
Ok, after covering some of the basic theory, we will now start with the implementation of STS using IdentityServer4.
IdentityServer4 is an OpenID Connect and OAuth 2.0 framework for ASP.NET Core. There is a good amount of information available on its official website on this link. Setting it up in a .ASP .NET Core Web Application is very simple. There are multiple options to get started:
I created a net .NET Core Web Application using AWS Serverless Template. You can use the typical .NET Core Web API Template as well if you like:
Next, let's add the NuGet package for IdentityServer4:
Before configuring ASP.NET Core with IdentityServer4 middleware, let’s talk about few basic concepts:
Defining an API Scope
An API is a resource in your system that you want to protect.
Defining the Client
The next step is to define a client application that we will use to access our new API.
For this initial scenario, the client will not have an interactive user and will authenticate using the so-called client secret with IdentityServer.
You can think of the ClientId and the ClientSecret as the login and password for your application itself. It identifies your application to the identity server so that it knows which application is trying to connect to it.
Loading the resource and client definitions happens in Startup.cs. Let’s update the file:
Let’s put it to a test, run the application and visit the /.well-known/openid-configuration endpoint (notice a few of the endpoints we mentioned earlier in this post):
Don’t worry if this information is overwhelming for you. We will learn about these more later. For now, think that by adding identityserver4 middleware we get all this functionality, which follows security best practices standard, ready for use.
This discovery document is a standard endpoint in identity servers and this will be used by your client apps and APIs to download the necessary configuration data.
Now, we’ve reached the end of this post. We still have to cover a lot of implementation details. We will continue our learning in the next post. You can clone the source code repo from this GitHub link.
OIDC extends OAuth 2.0 protocol which deals with Authentication and Authorization. IdentityServer4 is a middleware we can use to build an IDP (STS) that is OAuth 2.0 specs compliant.
In this post, we learn the OIDC basics and set up an ASP .NET Core Web Application with the IdentityServer4 package. Let me know if you have any comments or questions. Till next time, Happy Coding!
Published at DZone with permission of Jawad Hasan Shani. See the original article here.
Opinions expressed by DZone contributors are their own.