Identity vs Permissions

We often see people misusing IdentityServer as an authorization/permission management system. This is troublesome – here’s why.

IdentityServer (hence the name) is really good at providing a stable identity for your users across all applications in your system. And with identity I mean immutable identity (at least for the lifetime of the session) – typical examples would be a user id (aka the subject id), a name, department, email address, customer id etc…

IdentityServer is not so well suited for for letting clients or APIs know what this user is allowed to do – e.g. create a customer record, delete a table, read a certain document etc…

And this is not inherently a weakness of IdentityServer – but IdentityServer is a token service, and it’s a fact that claims and especially tokens are not a particularly good medium for transporting such information. Here are a couple of reasons:

  • Claims are supposed to model the identity of a user, not permissions
  • Claims are typically simple strings – you often want something more sophisticated to model authorization information or permissions
  • Permissions of a user are often different depending which client or API it is using – putting them all into a single identity or access token is confusing and leads to problems. The same permission might even have a different meaning depending on who is consuming it
  • Permissions can change over the life time of a session, but the only way to get a new token is to make a roundtrip to the token service. This often requires some UI interaction which is not preferable
  • Permissions and business logic often overlap – where do you want to draw the line?
  • The only party that knows exactly about the authorization requirements of the current operation is the actual code where it happens – the token service can only provide coarse grained information
  • You want to keep your tokens small. Browser URL length restrictions and bandwidth are often limiting factors
  • And last but not least – it is easy to add a claim to a token. It is very hard to remove one. You never know if somebody already took a hard dependency on it. Every single claim you add to a token should be scrutinized.

In other words – keep permissions and authorization data out of your tokens. Add the authorization information to your context once you get closer to the resource that actually needs the information. And even then, it is tempting to model permissions using claims (the Microsoft services and frameworks kind of push you into that direction) – keep in mind that a simple string is a very limiting data structure. Modern programming languages have much better constructs than that.

What about roles?
That’s a very common question. Roles are a bit of a grey area between identity and authorization. My rule of thumb is that if a role is a fundamental part of the user identity that is of interest to every part of your system – and role membership does not or not frequently change – it is a candidate for a claim in a token. Examples could be Customer vs Employee – or Patient vs Doctor vs Nurse.

Every other usage of roles – especially if the role membership would be different based on the client or API being used, it’s pure authorization data and should be avoided. If you realize that the number of roles of a user is high – or growing – avoid putting them into the token.

Design for a clean separation of identity and permissions (which is just a re-iteration of authentication vs authorization). Acquire authorization data as close as possible to the code that needs it – only there you can make an informed decision what you really need.

I also often get the question if we have a similar flexible solution to authorization as we have with IdentityServer for authentication – and the answer is – right now – no. But I have the feeling that 2017 will be our year to finally tackle the authorization problem. Stay tuned!

This entry was posted in .NET Security, IdentityServer, OAuth, OpenID Connect, WebAPI. Bookmark the permalink.

23 Responses to Identity vs Permissions

  1. gep13 says:

    I understand the suggestion to acquire authorization data as close to the operation as possible, i.e. the user clicks the “Add” button, and in the API for the Add action, before doing any work, you check to see if the current user is authorized to take that action, and if not, return the appropriate HTTP Code.

    What happens though when you want to show/hide UI elements in the application based on the permissions associated with the user? i.e. you may want to disable the Add button, or hide it completely, if the current user isn’t allowed to take that action. Historically, we have used claims added into the token to control showing/hiding elements on the screen once the user has been authenticated. What are your thoughts on this area? Thanks!

  2. applicita says:

    I wish I had this knowledge back in 2012, it took me a while to come to the same conclusion, I was Claims mad back then!

  3. Felix says:

    Do you expect that authorization solution will treat “Roles” in ASP.Identity store similar to Groups? In broader sense, Group may have claims, similar to users – and users will have some easy way to aggregate the claims of the groups they belong to. Then protected securable may match required claim to the claims that users have by virtue of belonging to Groups. Right now for me this is the hardest problem to solve…
    Thank you

  4. You would think this would be obvious? Your suggestion is the correct suggestion and fails inline with the SRP (Single Responsibility Principle).

  5. Diego says:

    We have had similar dilemmas and I although I agree with what you say about separating clearly those concerns here’s what we did (and for our scenario it has some benefits and the downside is not that relevant).

    Our Identity Server keeps identity details such as name, email, dob, etc. But we decided to also include “authorization” details disguised as “department” identities (call it “role”?).
    For example as part of the identity we have something like:
    “departments”: [“read-only”, “editors”, “admins”]

    That seems like mixing authorization with identity, but we thought that it’s actually not much different to saying:
    “departments”: [“departmentA”, “departmentB”, “departmentC”]
    because the fact that a user has the department “read-only” doesn’t say anything until you put it in context with the http verb and resource trying to access, and that still happens only at the resource’s API end.

    The big benefit we found by including those roles is that at the client side we can also have authorization based on those token’s “identities” in order to display or hide certain UI elements without the need to make an additional call to the API to determine whether that identity is authorized to view some UI elements. For example the UI will display the administration section in browser if the id_token has the “admins” department because it “trusts” the token it just requested, or hide EDIT button on some areas if no “editors” department found.

    Then at the API level we have our rules to say that for example a POST on some resource if the access_token has no “admins” department will be unauthorized.

    The downside is what you mention about those “identities-permision-ish” changing and the possibility that third party clients could have an old “identity”. We decided to violate this separation of concerns because the client application is also our application and we silently renew tokens every 5 minutes (we can live with those 5 minutes of incorrect identities). I understand that could become a problem if we ever decided to expose our resources to third party companies.

    Another downside is the size of the token. So I agree with all your points but it’s a bit of a grey line :)

    • Tamas Føldesi says:

      Where did you get the access token from? The one I have been getting from Identity Server 3 has the audience set to IS self, so it doesn’t seem right to use it for accessing another API. Or are you sending the id token as access token?

  6. Mark says:

    The sentence “But I have the feeling that 2017 will be our year to finally tackle the authorization problem” has really peaked my interest. It can be a really complex problem to solve when moving beyond RBAC. Most complex projects I’ve encountered required some attributes of both user and resource (ABAC) to determine authorized access but this can mean hard-coded rules, which may or may not be a problem.

    Are you thinking along the lines of ABAC, XACML or something else entirely?

  7. Tamas Føldesi says:

    I have been trying to set up an architecture that involves a purely browser based client, an API, and security token service. Reading the docs here: suggests that Identity Server is a good candidate for doing authentication and authorization in one round trip – but in this article you seem to say the opposite…?
    The linked doc made me try using the IS accces token to secure my API, though it doesn’t seem right, the audience on that is IS, just to name one problem.

    • IdentityServer supports both id_tokens (authentication) and access tokens (access to APIs) – some people also call that (coarse grained) authorization for clients.
      This article talks about (finer grained) authorization for users.

      The audience is “issuer name + /resources” – or IOW “all resources guarded by this issuer” – for more fine grained audience – the scope claims are used.

      • Tamas Føldesi says:

        Okay, thanks for clarifying – to me the article sounded like I should not be using IS to do authorization at all, but then I guess using it to grant access to a certain web API as a whole is fine.

        Also, I was not aware of what /resources means, but with that I have one questionmark less :)

    • “just to name one problem” – what other problems do you have.

      For issues with identityserver, the best place is the github issue tracker.

  8. Anthony says:

    Is the “AspNetRoleClaims” table (part of the core Identity EntityFramework implementation) what you are describing permissions using claims should NOT be modeled using or just “AspNetUserClaims” ? (i.e. a rich claims-based models).

    The organisation I work in, typically delegates all management of permissions to one service desk. The ideal being that the Service desk user would open up a single management application to manage users, roles and permissions (roles are effectively templated groups of permissions in this organisation). They wouldn’t want to open up one application for users and roles and then individual applications to manage permissions. So, the description and association of the permission to a user could be managed at a higher level (in the core Identity EntityFramework implementation for example) but the implementation should be at the lower level (within the application requiring authorization). This would then lean towards creating a Permissions & RolePermissions table to avoid using the Claims based tables. This blog post talks about a similar scenario:

    MS does seem to push you down the claims based route. It feels like the easy option but isn’t a good fit as you say. Looking forward to you solving Authori(z/s)ation in 2017, but I may have implemented something already !

  9. Mohamed says:

    (Just started working with IdServer)

    My confusion came from the fact that a client has scopes (“Add”, “Remove”, ect…) so I expected I could do similar work with a user. The final scope would be an intersection of the Client + User.

    Not sure if this makes sensse :-)

  10. Matt says:

    Re. the point about modelling permissions with claims – Microsoft certainly do more than push you towards this, they explicitly say claims can/should be used for authorisation:

    I find it hard to disagree with what they’re saying in the above, it isn’t breaking separation of concerns – the idp is only returning identity info and the API is using that as it sees fit. Issues around size of cookies and token expiration are kind of separate to my mind, we can’t avoid them but they’re practical issues that shouldn’t affect the concepts.

    Obviously it has to be the API that’s making the authorisation decisions specific to its own requirements. And I agree that in many cases individual APIs may well have more info about a user that makes no sense to be stored in the idp but in a simple case I don’t see any issue with an API authorising access based only on what claims the idp has reasonably supplied.

    • I didn’t say “don’t use claims for authorization” – if your authorization is based on identity data, that’s totally fine.

      I am saying that claims should be used to model identity – not permissions.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s