Introduction
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 common mechanism to secure backend APIs.
A common architecture for web applications typically consist of a web client app (e.g. an Angular or React frontend), a backend API (written in .NET Core, Java or NodeJS) and database for persistent.
In token based security, generally web client application send token, representing consent, to API. So, Instead of sending over Username, Password on each call to the API, client app send token. These tokens represent consent, for example, consent, granted by the user, to 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 gat 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
- ….more….
These are tedious tasks and prone to change. Its better to handle at a central location, at IDP level, so, it can be reused across applications.
So, instead of building our own authentication/authorization for different kind 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 type of applications i.e.
a proven protocol that’s safe for authentication and authorization and handle 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 need to communicate with 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 its going to be entirely on our user’s machine (e.g. An angular app). How can we trust the information that it sends, to use? We will see that this can be done by using Open ID Connect (OIDC).
OIDC is an identity layer built on top of OAuth 2.0 framework. It allows applications to verify the identity of the end-user and to obtain basic user profile information. OIDC uses JWTs, which you can obtain using flows conforming to the OAuth 2.0 specifications. But first, lets learn about OAuth 2.0.
OAuth 2.0
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 type 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 achieve authorization.
We can already feel that home grown endpoints are replaced by endpoints from OAuth standard. The standard also defines how to use these endpoints for different type 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-In 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 OAuth 2.0 protocol, so it extends OAuth2.
With OIDC, an application can receive an identity token (next to access token) if it needs one. This identity-token can then be used to sign-in into an application, while the same application uses the access token to access an API.
It also defines an additional endpoint that can used by an application to get additional user information. That’s the UserInfo endpoint.
Like before, same principles apply. It defines how different type of client applications can safely get those token from STS.
OIDC is not just for new apps or API-based apps. You can use it even with apps who doesn’t talk to a API.
Luckily, we do not have to implement most of this. There are some great frameworks available which do the most of the heavy lifting. IdentityServer4 is one of them, which we will be using later for 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:
- Issuer
- Client_id
- Username
- groups
- etc
Let’s see three different JSON web tokens:
ID Token
Contains user identity information.
ACESS Token
Contains scopes and groups for user 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 access token. If a valid access token is present means we are authorize to use resource.
Refresh Token
Used to get new ID-Token and ACESS-Token.
Identity Solution (How to choose)
- Your Own => (No, you shall try not to built your own solution from scratch).
- Framework (It is recommend 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.
OAuth Endpoints
These endpoints are required by standard (when we use IdentityServer4, those are automatically setup for us):
/authorize
- New Access-Token request (certain flows i.e. different ways)
/token
- Can be used in following cases
- New Access-Token request (Certain flows)
- Refresh Access-Token
- Trade Authorization-Code for an Access-Token
/revocation
- Revoke an Access or Refresh-Token
The following end-points are part of OpenId Specifications:
- /UserInfo
- /CheckSession
- /endSession
- /.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 implementation of STS using IdentityServer4.
IdentityServer4 is an OpenID Connect and OAuth 2.0 framework for ASP.NET Core. There is 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, Lets add nuget package for IdentityServer4:
Before configure 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.
Configuring IdentityServer4
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 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 to the end of this post. We still have to cover a lot of implementation details. We will continue our learning in next post. You can clone the source code repo from this github link.
Summary
OIDC extends OAuth 2.0 protocol which deals with Authentication and Authorization. IdentityServer4 is a middleware we can use to build an IDP (STS) which is OAuth 2.0 specs compliant.
In this post, we learn the OIDC basics and setup an ASP .NET Core Web Application with IdentityServer4 package. Let me know, if you have some comments or questions. Till next time, Happy Coding.
My Recent Books
Discover more from Hex Quote
Subscribe to get the latest posts sent to your email.
1 thought on “Token Based Security, OAuth 2.0, OIDC and IdentityServer4”
Comments are closed.