Token-Based Security, OAuth 2.0, OIDC and IdentityServer4: Part 2
We'll learn about some of the details of OAuth2 and OIDC, see different OAuth players and discuss the different types of OAuth flows for different kinds of applications.
Join the DZone community and get the full member experience.
Join For FreeIntroduction
In the previous post, we learned that OAuth is an authorization framework specially built for HTTP APIs. It allows a user to securely delegate scoped API Access to an application.
By scoped access means, that users define exactly what parts of an API they want the application to be allowed to use. This application can then talk to API freely on the user's behalf. In simple words, OAuth is a delegation protocol.
We also learned that OpenID Connect is a standard adding authentication (verifying the user’s identity) on top of OAuth2, which is only for authorization (access control). OpenID connect adds authentication by introducing the notion of an ID token, which is a JWT, providing a signed proof of authentication of the user.
In this post, we will go into a few details of OAuth and OIDC.
OAuth Players
In OAuth, we have the following players:
- Protected Resource: an HTTP API.
- Client (requesting) Application: Application that wants to access to a protected resource on someone’s behalf.
- Resource Owner: The user who owns the protected resource.
- Authorization Server: Responsible for handling authorization requests.
Note that, the protected resource may be an API that your company owns. However, in OAuth, the data on that API belongs to the user and it should be user consent if they want to share their data (Good foundation for GDPR, etc.)
OAuth Scope
We mentioned scoped access earlier. Let's understand it a bit more. An OAuth scope is simply "A permission to do something within the protected resource on behalf of the resource owner."
What those permissions are and how fine-grained those are, entirely up to you. some examples:
- api1: we can have a scope that represents an API in its entirety.
- api1.read: or may be a particular type of access within the API.
- api1.notify: or it can be a particular piece of functionality within the API.
When a client application asks for authorization, it will be these permissions, these scopes that they will be requesting.
I went ahead and added a few ApiScope
in Config.cs file as shown below:
We will define ApiResources
later, for now, note that API-Resources map to scopes which gives access to API. Next wire this up in IdentityServer middleware in Startup.cs file:
Save and run the application. Here is how the discovery document shows this information.
OAuth GrantTypes
If we visit the discover document of our STS, you can see a section name as shown below:
Let’s learn a little bit about these different grant types:
- Authorization Code (Redirect Flow):
- Designed for Confidential Clients (i.e., client applications which can keep a secret).
- The flow is initiated with the response_type parameter set to code and a client secret shared between the client and the Auth server in the login request.
- Best suited for websites with backend servers (e.g., ASP .NET MVC).
- Best of both worlds: Explicit User and Client Authentication.
- Implicit Flow:
- Was Designed for public clients (e.g., Angular SPA).
- Best for clients accessing resources directly from the browser.
- Due to a lack of keeping a secret, no explicit Client authentication in this grant type.
- Not recommended for new apps.
- Client Credentials (No user involved):
- Designed for applications that are the resource owner.
- Best for machine-to-machine communication.
- This flow requires Client authentication.
- Resource Owner Password Credentials (ROPC):
- Instead of Redirect, we talk to the authorization server.
- If you want to use an in-app login screen, e.g., on an angular application, then this flow can be used. But it is advised not to use this flow if possible.
- Designed as a temporary solution for legacy applications (transition period).
- Should no longer be used.
Refresh Tokens
In the previous post, we talked briefly about Access-Tokens and that they contain claims or access information about users. We will talk about Id Token later as well.
Regardless of the mechanism, we get the access-token, but what about when those tokens expire? Here a different type of token comes into play, a Refresh Token.
A refresh token is a long-lived token that can be used by the client applications to swapped for new access-token or even refresh-token. This allowed us to perform long-running background tasks without the user being present.
Refresh tokens are highly confidential. The user should be informed that a refresh token is being requested (consent screen). This is because we will be acting on a user's behalf when they are no longer present.
For refresh tokens, we usually use a scope called "offline access."
OAuth 2.1 Changes
Based on security changes and simplify best practices following are the changes:
- No more ROPC.
- No more Implicit Flow.
- Refresh tokens must be single-use only.
- PKCE is now mandated across all application types.
Recommended Flows from OAuth 2.0 to OAuth 2.1
OAuth 2.0 Flows
App Type | Recommended Flow |
Server-Side | Authorization Code |
Single Page Apps | Implicit Flow |
Native app (mobile, desktop) | Authorization Code + PKCE |
Machine to Machine | Client Credentials |
OAuth 2.1 Flows
App Type | Recommended Flow |
Server-Side | Authorization Code + PKCE |
Single Page Apps | Authorization Code + PKCE |
Native app (mobile, desktop) | Authorization Code + PKCE |
Machine to Machine | Client Credentials |
OAuth + Identity With OIDC
As we already know that in OAuth, there is no authentication. It does not give any indication to the client application about who the user is and how they authenticated. OIDC is an identity layer on top of OAuth and it formalizes some of the OAuth ambiguity.
By using OIDC, your authorization server also acts as an identity provider.
OIDC also gives us a discovery document. A well-known document, which describes the identity provider including the URLs of its various endpoints. What scopes and claim types it supports and the public keys for verifying tokens. The very same document which we are referring to in this post is coming from the OIDC part of IdentityServer. This document allows client applications to automatically configure themselves to use the identity provider.
Identity Access
When using OIDC, we bring a new protected resource into our system, which is an API typically hosted in our identity provider called the UserInfo endpoint.
When we call the UserInfo endpoints with an access-token attained using OIDC, we are returned claims about the delegating user. Access to this API is again scoped, however, this time by identity-specific scopes that give the client application access to a subset of claims about the user.
Example:
- profile: give access to claims about the user, e.g., name, website, gender, username, etc.
Configuring IdentityServer with IdentityResources
I have updated the Config.cs file with the identity resources as shown below:
Next, Update the Startup.cs file with this information:
Now, if we run the application and check the discovery document, we will see that it is now populated with more information:
Identity Resources map to scopes that gives access to identity-related information.
Identity Token
The other major feature of OIDC is identity tokens. This is a new type of token, however, instead of allowing us access to a protected resource, this token describes the authentication event itself. This token is intended for client applications (in contrast to a protected resource).
When the client receives this token, it is going to verify both the data in it and whether or not the token has been tampered with. This is done using public-key cryptography (digitally verifiable). The identity provider signs the token with private-key and the client application verifies the token with public-key.
An identity-token is always a JSON Web Token (JWT). The payload contains information, which client information further act upon as needed.
The ID token is never sent to the resource API and is only used by the client to validate if the user is properly authenticated before requesting authorized resources.
Hybrid Flow
OIDC also adds a new authorization flow called the Hybrid flow. It offers us an interesting alternative for authorizing confidential clients.
Hybrid flow allows every combination of code, token, and id token.
So, by requesting a code and id-token together, we can not only verify that the response was intended for us but also verify that the authorization code was also intended for us.
Summary
In this post, we learned about some of the details of OAuth2 and OIDC. Learned about different OAuth players. We also discussed what are different types of OAuth flows for different kinds of applications and OAuth2.1 recommendations.
We also talked about the OIDC extension to OAuth and also configured our identity server with some of the identity-related scopes. We learned that an id token is a type of JWT and it is digitally verifiable and intended for client applications. We will resume our journey on Token-Based security using IdentityServer in the next post. Let me know if you have any comments or questions. You can clone the source code repo from this GitHub link. 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.
Comments