Authentication and Authorization
When discussing security, we often divide it into two parts: authentication and authorization. So, what's the difference between the two?
Authentication identifies who a user is. A user typically authenticates by entering a username and a password. So long as these match the values the authentication system expects, the user is authenticated. Of course, the mechanism might not be a username and password, for example, it could be biometric-based, or the user may need to use extra steps such as two-factor authentication. But, regardless of the steps, if the user can log in, they are now authenticated. Once authenticated, we know who the user is, so where does authorization come in?
A typical application will have many pieces of functionality. For example, in a blogging application, all users may be able to read any blog entry, but only the blog owner will be able to create entries, in other words, any user will be authorized to 'read', but only blog owners are authorized to 'write'. So, in this case even though a user is authenticated, they are not authorized to do certain things. Notice that you don't have to be authenticated to perform specific tasks; you could be an anonymous user and still be able to read and maybe comment on, a blog post .
So, how do we authorize users in our applications?
Imagine that you are completely in charge of authentication. In that case, you'd gather the login details and decide if the user is authenticated or not. If they are authenticated, you would typically have either their email address or their username, and you’d probably have a database table from which you could get other user information, such as their name and address.
However, when using OpenID Connect (OIDC ), you do not handle the authentication. Instead, you hand it off to a 3rd party, the OIDC Provider or OP. This provider takes care of the mechanism of authentication’ and holds all the information that the user has registered with it, such as their email address, home address, etc. If you want to use this personal information, and you will, then how do you get that data from the OP to your application? That’s where claims come in.
The user data Is stored in the OP, IdentityServer, say, in the form of‘'claim’' where a claim is a name/value pair that contains user data such as the email address.
You can get the claims from the OP in two ways, when your user authenticates an identity token is created. This token can be configured to hold a set of claims as asked for by your application and approved by the user. The format of this identity token is a JSON Web Token (JWT), and part of the body of the JWT is the user’s claims. However, getting the claims this way is not encouraged, instead the client application should call the ‘userinfo’ endpoint to get information about the authenticated user, this information will contain the claims.
What are claims used for? They are typically used either on the user interface, such as a welcome message that says, 'Hello Sarah Smith', or maybe to communicate with the User by using the 'email' claim to send them a secure message .
Why not use claims for authorization?
The primary reason is that we don’t use claims for authorization is because claims were never designed for this purpose. They are meant to be used to model the identity of the user.
A claim itself has no structure; sure, you can store numbers or dates in a claim, but essentially a claim is a piece of text. Imagine an authorization rule such as "a user within who is an administrator can access the server called 'alice' but only between the hours of 17:30 to 07:00"… how would you encode that in a claim?
If you came up with a claim language and embedded those rules in the claim then you hit other issues. Firstly you end up making the token very large and tokens are, by design, meant to be compact. Secondly, if you want to change the rule while the user is logged in and the token is still valid, you now have to get a new token which may involve some UI and will involve a roundtrip to the token server, neither of which are ideal (and in fact may not be possible).
You could also end up with a plethora of claims within the token depending on the API being used, which puts you on the hook for getting the correct claim for the correct API (this may be even more to store inside the claim).
Authorization rules are business logic, but claims are part of the user’s identity, nothing to do with business logic. Why would you put business logic in your token?
So, if you don’t use claims to perform authorization, what do you use? You have a few options.
- Remembering that authorization rules are business logic, you could hard code the rules into your application. At the point the authorization is required you’d have code to decide whether this user should be allowed to call this API. This is obviously not ideal as these authorization rules change (and you’d have to redeploy your application).
- You could encode the rules into a database. This is better as it means that the rules can be changed easily, however again there are issues. You need to have an authorization ‘language’ for the rules and be able to parse this language in your code. Ideally, you’d also need to be able to debug these rules… you can imagine they’d get complex and maybe difficult to manage. As soon as you introduce such a feature, people will take advantage of it so you’ll need a release cycle for the authorization rules, including testing. Better than hard-coding, but much more work
- There is already a standard for this, eXtensible Access Control Markup Language (XACML), “an XML-based standard markup language for specifying access control policies” (quote from Wikipedia). This XML-based language is defined by OASIS and allows you to write fine grained policies to manage access control for your application. Unfortunately, this is not an easy language to master or to apply to your code
- You can use Abbreviated Language For Authorization (ALFA), whichmaps directly into XACML but is much more human-friendly and readable, looking a little like YAML. This means you can write your authorization policies in ALFA, which is human readable, and have them translated into XACML and then processed to be turned into a set of rules for your application
- Finally there is Enforcer. Enforcer allows you to write human-readable access control policies for your .NET applications. It lets you write and debug ALFA, and then turn that ALFA into code that your .NET application can use
In summary, do not use claims for authorization, that is not what they are meant for, claims are used to model the identity of the user, they were never designed for authorization. Instead, for authorization, choose a standard approach such as XACML or ALFA and use a tool such as Enforcer to help create and apply the rules.