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!
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!
Write a service that returns information back to the UI. Based on the identity of the user, probably based on more context – but most importantly in a format is most useful to the UI.
In a sense this is completely in-line with my other advice – if you treat the UI as a “resource”…
Would this service be part of the Identity Server App or application/api? I an make arguments that go either way, but currently leaning towards a new endpoint in the Identity Server App.
Doesn’t really matter IMO – it’s a service. I do not see a benefit of putting it into the identity server app tbh.
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!
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…
I agree – it is a hard problem to solve.
You would think this would be obvious? Your suggestion is the correct suggestion and fails inline with the SRP (Single Responsibility Principle).
It is obvious when you know what you are doing, but easy to get confused when you are learning.
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 :)
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?
see my other reply.
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?
I’ll write more about it once we are closer, sorry ;)
2017 almost finished…any news to share on the topic? Don’t want to put any sort of pressure, just felt and still feel very excited on finally seeing something on this subject, which has been a problem for any system forever. Congratulations for all your work around identity / authentication in the past years, which helped thousands of people, me included :-)
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: https://identityserver.github.io/Documentation/docsv2/overview/bigPicture.html 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.
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.
Is the “AspNetRoleClaims” table (part of the Asp.net 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 Asp.net 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: http://benjamincollins.com/blog/practical-permission-based-authorization-in-asp-net-core/
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 !
(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 :-)
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: https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims.
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.
So let’s make it clear:
A claim “date of birth” with value “1/1/1970” is absolutely fine. Because it models “identity”.
A claim “night_club_access” with value “true” is wrong. Because it models “permissions”.
If your ecosystem with 150 different clients want to decide whether a user has access to a nightclub or not, they should decide on their own, based on user’s identity, and specifically using the “date of birth” claim.
A client that operates in a country where legal age to enter nightclub is 18 may produce a different result from another client that operates in a country where legal age is 21. If we had modeled permissions, a single “night_club_access” would be problematic all the way.
Yes – similar to your passport – it contains a date of birth claim – and you can use it in many countries. The exact policy when you are allowed to drink alcohol or enter a bar, is handled locally.
Hello Dominick, thank you for the response in my previous comment. I am a bit confused as this post seems to me that contradicts with an example from the official documentation. The following code from official documentation seems to me that models *permissions* rather than *identity*:
// this API defines two scopes
Name = “api2.full_access”,
DisplayName = “Full access to API 2”,
Name = “api2.read_only”,
DisplayName = “Read only access to API 2”
These two scopes seem to me like “permissions”. If Api2 wants to PERMIT full access or not it’s Api2’s internal business, and should not be a part of the IDENTITY. In other words, in this example IdentityServer seems to carry (and control!) information about Api2’s PERMISSIONS. At least that’s how i interpret it. Can you please elaborate on this?
By reading and (i think) understanding your post, i would expect just a simple “api2” scope on the identity, and do not care about “full_access” or “read_only” as this is api2’s business and this has nothing to do with identity per se.
And also, a BIG thanks to you, Brock and the rest of the contributors for a great project ***AND*** a great documentation!
Scopes are not about user permissions – they are about what access a user grants to a client.
I know it is a bit confusing – but makes total sense once you understand it ;)
Maybe read this: https://www.amazon.com/OAuth-2-Action-Justin-Richer/dp/161729327X/ref=sr_1_1?ie=UTF8&qid=1496135709&sr=8-1&keywords=oauth2+in+action
I’m a bit confused. I use roles to control permissions all over my api using the authorize attribute. I am also using reference tokens. If the access token doesn’t have the claims for roles, how would the api know if the user is authorized to access a controller? Hit the DB again to check roles for the user? And what if the api doesnt have access to the user database?
Well – I think I already said everything in my post.
Your API should def have access to the data store where it can find its authorization information.
If you system is that simple that a couple of roles is all you need, maybe you then can ignore my advice – you will regret that later then when complexity rises.
I enjoyed the post. I’m trying to come to terms with how I should structure permissions in my app and there’s lots of conflicting advice out there.
I have a question related to the above though.
Right now I can have 100 actions/permissions assigned to a role, and a user assigned to the role. It’s fairly easy to check if the action I’m trying to do (“CreateUser”) is available on any of my roles, therefore allowing me access. What makes this approach inferior to a completely separate implementation not using roles?
Also what kind of implementation would you suggest? The only thing I can think of is almost identical do the above, just kept away from the Identity DB.
e.g. These tables: Permissions, UserGroups, UserGroupPermissions, UserUserGroups.
Custom Authorize attribute would then see if the permissionid with the action you’re executing is contained on any of the groups you are associated with – Pretty much exactly the same as roles, except without the claims.
Technically you can implement that in many ways. I think my main message was “don’t mix identity with permissions – especially not in security tokens”
The part about identity makes perfect sense, but what really confuses me is the existence of roles in IdentityServer. And I don’t mean in the sense that it is authorization information, but I can’t see how users can be labeled ‘customer’ or ’employee’ for the ‘entire’ system.
The same counts for claims. How can ‘Customer Id’ or ‘Employee Id’ be a claim of the user for the ‘entire’ system?
If I want to use IdentityServer for multiple, unknown future apps (not limited to one organization), then at some point the user is both ‘customer’ and ’employee’ and may have multiple ’employee id’ claims. And, unless I am mistaken, there is no link to the client app. Shouldn’t there be a discriminator in the roles (and claims) table in order to maintain the roles and add the claims to the specific app only? Or shouldn’t IdentityServer be used like that?
But while adding a discriminator may work, it doesn’t seem to be the right solution for the ‘roles’ problem. So it occured to me that it may be better to not use roles at all. As there are no real benefits gained from using them.
So, after reading your post (over and over again) and reading about protecting user data by authorization, I came today to the conclusion that the better approach is to use ‘rules’ instead. As I think that authorization is in fact a set of rules and not something you read from an ‘authorization context’.
With policies and authorization handlers I can implement advanced authorization, close to the source. The business defines the rules (or at least for an important part) and has the information that could be used for authorization, like department, function and perhaps even roles. While aditional information can be read from the identity claims. I wonder how hard it is to implement this.
We’ll have an announcement at NDC in January. Will also blog about it shortly after…stay tuned ;)
Hi! Excited to hear you will announce something at NDC London, I’ve been eagerly awaiting news on the authorization stuff since NDC Oslo.
I have one question that I’d like to hear your thoughts on. You say that roles is a grey area between identity and authorization. I have a similar kind of grey area: service subscriptions in a multi-tenant SaaS portfolio. Pretty much all our services will need to know if the given user is a member of the tenant requested per URL, and whether or not those tenants are actually subscribing to the requested service. Would you say it’s OK to let our IdSrv issue a claim with a list of tenants the user is a member of, as well as the service identifiers each of these tenants subscribe to?
If yes, would you also say it is OK to include information on which of 3 generic access levels the user has been given: admin, read/write and read? If a service needs anything more specific or fine-grained than that, it needs to handle it itself, but for maybe 80% of the services, this basic set would cover the authorization requirements, and then there would be no need for them to query another service.
My gut feeling is: list of tenants is OK – service identifiers is app logic.
Do you know where I can find a framework that uses OAuth as an authorization/permission management system? Is it possible to extend IdentityServer for this – and if so, did someone do this? I need an API permission management tool, where users can grant access to specific scopes and also review and revoke permissions for third-party applications. (like a Facebook consent screen, where you can change the permissions afterwards in https://www.facebook.com/settings?tab=applications)
> where users can grant access to specific scopes and also review and revoke permissions for third-party applications
That’s exactly the purpose of OAuth – and IdentityServer is built for that.
Hi Dominic, thanks for this article. I refer back to it often.
I’m clear on the distinction between scopes and user permissions (the former representing what a client/token is authorized to do, and the latter representing what a user is authorized to do).
I am hung up on one practical implication, however. Let’s say I have admins and consumers using the same identity system, and I have a scope called “reports” that represent access to some reporting endpoints/APIs. An admin could grant access to a client with the “reports” scope, and the client could call those APIs. Good so far.
What if a consumer tries to grant access to that same client with the “reports” scope, i.e. a scope/capability the consumer would fundamentally never have access to? It seems wrong to allow the user to authorize that scope to the client. That the allowed scopes for that user should minimally be constrained to what he/she is authorized for. But, at a high-level, this would be a user authorization concern (that’s now in the IdP).
I suspect this isn’t a unique problem, for IdPs with heterogenous user populations. Would much appreciate your input.
Yes you are right – and I don’t have a good answer for you tbh. It is definitely not covered by the protocol.
Ah, okay, I appreciate your candor. The best I can come up with is to implement some coarse-grained authorization rules in the IdP based on a simple “group membership”-to-scope mapping, and then keep all finer-grained user permissions (based on assigned roles) contained within the application. Just enough to make the IdP work sensibly, but not enough to compromise the principles you’ve outlihed above.
Thanks for your participation with all of us in the community, your expertise is highly-valued!
Thanks for the article and all the work done on Identity Server to date.
Are there any example of a basic implementation of the non claims based authorisation method? at the minute I’ve got everything I need store in the claims but it hasn’t taken long to encounter the 431 (Request header Field to Large) as a result of the claims getting too big.
I’ve trawled through the sample on github but can’t seem to find anything that covers this scenario.
First of all thank you for the article and all you articles on identity and authorization.
I think I do understand the difference between identity and permission.
Do you think linking permission with resource is a good idea ? The goal will be to grant permission to a user on a specific resource (business entity: client, merchant) in a specific scope (Api defined in the access token).
I saw your video introducing policyServer but I could’nt figure out how policyServer might be used for this case or I crossed the line between authorization and business requirement ?
Linking access control to resource is a common practice – compare to what NTFS does. You probably need some sort of inheritance rules there. And also think about orphaned entries.
PolicyServer could do this for you.
Quote in OAUTH2 In Action
” OAuth isn’t an authentication protocol, even though it can be used to build one. As we’ll
cover in greater depth in chapter 13, an OAuth transaction on its own tells you nothing
about who the user is, or even if they’re there. ”
If we put PolicyIO as an authorization server than it makes IdentityServer only to use for authentication doesn’t it
IdentityServer is both an OAuth 2.0 and OpenID Connect implementation. Yes – we recommend to use IdentityServer for end-user authentication, federation and API access control.
PolicyServer is our recommendation for user authorization.
Hi I am coming from a MS Dynamics CRM xRM framework background and I am trying to figure out how fine grain authorization can be implemented as implemented by MS in CRM https://docs.microsoft.com/en-us/power-platform/admin/security-roles-privileges. To me it seems some fundamentals are missing like entity ownership, teams, business units as well as extra permissions on entities or am I missing something totally?
> To me it seems some fundamentals are missing
Missing from what?
Well either from IdentityServer or PolicyServer depending on how you would like to classify each functionality.
Well – IdentityServer is an authentication system – so nothing is missing there.
PolicyServer is a generic multi-tenanted app roles/permission management system. I don’t know how this compares to MS CRM though. Many of our customers are using it to implement other features on top of it.
IdentityServer is an authentication framework. but how can I handle the local user-role permissions in each apps (clients)?
the user want to login to the client.
the client redirect him/she to the idp login page.
after successful login, the idp redirects him/her to the client homepage.
the client, verifying the received token.
[**and this is my question**]: in this step, the client, handle the user authorizations (e.g show/hide the menus) and etc..
it means that I have to create a “User”, “Role” and “UserRole” Tables in each app and handle the authorization tasks in each of them separately (like before)?
it that corret?
Yes. either a local data store – or a central one.