Background: There are plenty of oauth response payloads that include a sub or a uid field. Both seem to loosely be used to send a user id.
https://www.oauth.com/oauth2-servers/signing-in-with-google/verifying-the-user-info/
https://developer.okta.com/docs/reference/api/oidc/#response-properties-3
What, if anything is the difference between these two?
As far as I know, there is no practical difference, other than that the subject claim is in the official ietf spec, and the uid claim is not
https://www.rfc-editor.org/rfc/rfc7519#section-4.1.2
I suspect that the uid claim is added to by some oauth providers to help identify a user more explicitly, because the subject claim in the spec is fairly general to support a broad set of scenarios. The entire oauth spec itself is quite general, so any differences between uid and the subject claim will probably be different for each oauth provider.
To add to Anton's response: the user id should be immutable, so that if the user changes name their access to resources are not affected. Some vendors will set uid to a guid and sub to an email. So in some vendor scenarios can use the uid as a stable identifier for the user.
Related
My application is composed of an API layer which is accessable by presenting a Bearer Token, obtained from our Identity Server. Each of our API has a level of scopes that the token must contain in order to be invoked: this means, for example, that if you want to make the API call which "creates a product" you need a write access to products (i.e. the scope "products") while you may just need the scope "products_read" if you only want to retrieve them.
Scopes are bound into the token when you authenticate onto the ID server.
Now, I need this user to be able to perform different operations on different "workspaces". Each workspace administrator can set which permissions each user have. This is, in fact, linked to the scopes that each user will have when operating on that particular workspace.
Right now we have implemented that, if you are trying to access a different workspace, the API layer will check:
if your bearer token is valid (by validating it on the ID server)
if you are authorized to access that workspace
changing associated claims by removing the original "scopes" (set into the token by the ID server) and overwriting with those assigned by the administrator of that workspace
This somehow works, but it stinks because I don't want my application layer (API) to have this kind of responsability and the opportunity to tamper with the token. I want the ID server to handle it and, after the user tries to enter into a different workspace, it generates a new crafted bearer token with correct claims (so the API will just need to trust it).
What's the best approach in doing that? I'm digging into the "custom grant type": may this be the right approach?
Scopes are fixed at design time and the same for all users. I like your use of products and products_read - that is very standard.
When you need dynamic behaviour, implement claims, which depend on who the user is. In your case I would use a workspaces array claim. Since this is a key vaue for authorization, it should be added to access tokens at the time of token issuance. Think in terms of your products scope being composed of claims.
It feels like workspaces and other permissions are part of your business data rather than your identity data. At the time of token issuance, IdentityServer should send identity attributes (eg subject claim) to an API endpoint you provide. which returns business attributes (workspaces). I believe in IdentityServer this is done via a custom profile service.
I'd try to avoid different tokens for different workspaces, since that will be awkward in terms of usability and code complexity. The standard way to do it would be to redirect the user each time.
Context
We use Identity Server for identity and access control in our solution. Our scope names have the form of URLs so they are 40-60 characters long.
Some time ago we received a request to increase the max length for scopes in the request. The default value is set to 300 in InputLengthRestrictions class and it can be changed very easily. However, after some discussions, it turned out that for now it may be enough to increase the max value to 500 or 1000 but in the future, an even bigger limit may be needed in order to be able to request 10, 20 or more scopes.
Here comes the question. Is it a good practice to request an access token with such a large number of scopes? What are the pros and cons?
My thoughts
From my perspective, the main benefit of having one "super" access token has one main advantage i.e. it is convenient because it allows you to call all APIs.
On the other hand, I see some drawbacks and/or code smells:
The fact that a large number of scopes must be requested may mean
that scopes are too granular.
The fact that a large number of scopes must be requested may also suggest that scopes are used more as permissions. It is especially a problem in the case of long-lived tokens as they cannot be revoked easily.
Requesting a large number of scopes may suggest that you request
more than you actually need. However, it is recommended to "choose the most restrictive scopes possible".
Having a super access tokens expose a higher security risk if such a token is intercepted.
In implicit flow, a token is passed in URL so the large super token can exceed the maximum length of the URL.
Super tokens might be too big to store them in cookies (it is a
different topic if tokens should be stored in cookies).
Super tokens can be quite large so the network performance can be affected.
What do you think? Do you see any other pros/cons of super tokens? I'm not sure but maybe large super tokens can affect Identiy Server performance.
I don't have pros or cons for you, but perhaps this answer can help you.
Looking at IdentityServer you'll see three parts, the resource, the client and the user. IdentityServer has two main responsibilities, authorize the client and authenticate the user. User authorization is actually not the responsibility of IdentityServer. That's why they created PolicyServer.
Consider the following resource:
resource = CalendarApi
scope = Calendar.Read
scope = Calendar.Write
scope = Calendar.Event.Create
The resource is just a logical name. It can consist of one or seperate api's (as in projects), where an api can implement a single or multiple scopes. In the api a scope is an implementation of certain functionality.
Only a client can request a scope, because the client knows how to use the functionality.
Suppose I have two clients: Mvc1 and Mvc2. Mvc1 has a calender view and an admin page, while Mvc2 only shows the calendar.
My configuration:
Mvc1: scope = Calendar.Read Calendar.Write Calendar.Event.Create
Mvc2: scope = Calendar.Read
It has no use for Mvc2 to request all scopes, because it doesn't use the other functionality. It wouldn't make sense to request all scopes. And in case Mvc2 is a third party app, you shouldn't, because they could use it even when this was not the purpose.
Best practice here would be that a client only requests scopes that are allowed (as configured in IdentityServer) and may be implemented by the client.
So far the user was not involved, because there is no relation between scopes and users. However, the client needs the user (as resource owner) to actually access the resource.
It then comes to user authorization to determine whether the user can create events on the calendar. This 'permission' is not the scope.
The scope Calendar.Event.Create doesn't allow the user to create an event. It only allows the client to connect to the resource.
When combining the clients and users, then there is only one situation where a user can create an event: when a user with create permission uses the admin page in Mvc1.
Mvc2 can't access the resource, not even when the user has create permission.
Now getting to your question:
Is it a good practice to request an access token with such a large
number of scopes?
The access token should only contain the scopes that are needed, as described above. Only necessary scopes should be requested by the client.
Agree. The number of scopes should not be too detailed. Don't treat scopes as permissions, e.g. create, edit, read. Though I did as example, a better scope would be Calendar, where the user permissions define what the user is allowed to do (CRUD permissions).
Agree, should be investigated.
I would say yes, as argumented above.
It is still the user that has to be authorized. But you should limit the possibility for clients to use functionality that was not meant for that client.
/ 6. / 7. Hitting limits is a good indication that the architecture may need some redesign. In general you should not expose more than necessary and you should avoid hitting limits.
I suspect the problem is that scopes are used as permissions. Remove the 'CRUD' from the scopes and redesign user authorization. Don't set permissions in claims.
In my design there is no need for a super token, nor will I ever hit a limit. There are only few scopes, the access token only contains the sub claim and policy server tells me what the user is allowed to do.
I hope this helps you in any way. Please let me know if something is not clear.
You can implement Service Account flow for same. Using it you can get token of respective client with all allowed scopes to client.
By this way your token does not have included all scope but has scope allowed to client.
I don't have sample code right now but you can check how service account can be implemented
We use OAuth 2.0 to obtain JWT tokens from an Azure AD. In our application, we have used the value of the 'upn' claim to identify an associated internal username.
The Azure AD Token Reference documents the upn claim as a "User Principal Name", which as far as I understand is a username following the addr-spec format (i.e. user#domain). This works well for users created within the Azure AD Tenant. To my surprise, however, the upn claim seems to be gone if the authenticated user is sync'ed from a different AD. This behavior does not seem to be documented anywhere.
Where can I find documentation on when the upn is guaranteed to be in a token?
What are reliable alternative claims that I can use instead? Preferably claims guaranteed to be of the form "user/domain", as that matches our model best. I have considered the following:
unique_name: I have only observed this to be equal to upn, but I am not sure where it comes from. Confusingly, the token reference says: This value is not guaranteed to be unique within a tenant and is designed to be used only for display purposes. (emphasis mine)
email: This too seems to be equal to upn, but again, where is it sourced from? In the management portal, I have tried putting a different value in every email related field associated with the user, but none of them seem to be propagated to this claim. It therefore appears that this field is not actually an email.
I want to be absolutely sure that our application will be able to handle all tokens issued by Azure AD, so I am hesitant to use any of the above claims unless I have some documentation that explains their actual semantics.
Where can I find documentation on when the upn is guaranteed to be in a token?
There is no such document about how this claim is guaranteed. Based on the test, it is as you mentioned that only be issued when the users is not a external user.
What are reliable alternative claims that I can use instead? Preferably claims guaranteed to be of the form "user/domain", as that matches our model best. I have considered the following:
We can use the oid claim to map the users. This claim is contains a unique identifier of an object in Azure AD. This value is immutable and cannot be reassigned or reused. Use the object ID to identify an object in queries to Azure AD.
And if you have any feedback about the Azure document, you can try to submit the feedback from Is this page is helpful? at the right bottom page to help improving the document.
While it is fairly common for a User’s UPN and primary email address to be the same thing, that isn’t guaranteed (nor is the existence of UPN as you’ve noticed). So you should operate under the assumption that UPN != email address. If you need to know the email address, you should make a Graph call and search using the oid.
I'm trying to get up to speed with OpenId Connect, OAuth2.0, Security Token Service and Claims. Imagine a scenario with a large website with many areas and different functionality e.g. Customer, Order, Supplier, Delivery, Returns etc. My question is this – would I create Claims on the Token Server such as CanCreateCustomer, CanReadCustomer, CanUpdateCustomer, CanDeleteCustomer etc, i.e. effectively CRUD Claims for each main area/Business Object? This would lead to many tens but more likely hundreds of Claims. Or is my understanding coming up short?
So fixing terminology, you mean "scopes", not "claims". Scopes are identifiers used to specify what access privileges are being requested. Claims are name/value pairs that contain information about a user.
So an example of a good scope would be "read_only". Whilst an example of a claim would be "email": "john.smith#example.com".
You can send claims in the id token (or JWT), or/and have them available via the userinfo endpoint (if using the "openid" scope).
You can break scopes down per service, and have them as granule as you would like. Or have them as high level (read / write / admin). I would recommend having enough scopes to actively achieve the security principle of least privilege (basically: giving people what they need to do their job). You can use namespaces if you have a lot of scopes.
Your understanding is right, but you have a lot more flexibility in OAuth2.0 scopes (claims)
These scopes can be configured in any way for eg, in your case instead of creating individual scopes for each CRUD operation for each main area, you could create group scopes like
customer.read_write
order.read_write
Etc, you can even go one level higher , by creating functionality level scopes, like
webportal.full_access
adminportal.full_access
Then in your application, after authentication, the authorisation can be done like,
ValidScopesIn({Scopes.WEBPORTAL_FULL_ACCESS, Scopes.CUSTOMER_READ_WRITE})
public void createCustomer(Customer customer) {
// your creation logic
}
I think your understanding is largely correct. However, if I understand what you describe correctly it seems more of an authorization (OAuth) rather than an authentication (OIDC) problem, and as such you might have a look at how other OAuth resource providers define their scopes (not claims btw), for instance GitHub or Slack.
I would recommended that "scopes" be configured as URIs so that collisions do not occur.
As an example.
-jim
I am following railscasts 235-devise-and-omniauth-revised. The first step is setting up a twitter app credential. I found that there is
Consumer key/Consumer secret
and also
Access token/Access token secret
My question is simple, Why there are two pairs of credential, What's the right scenario to use them.
I noticed here is another same question, which is not help much.
Okay, Then, As far as I know, consumer_key pair is for server. access_key pair is for client. check below comment. Add your answer if you have other understanding.
The consumer key is for your application and client tokens are for end users in your application's context.
If you want to call in just the application context, then consumer key is adequate. You'd be rate limited per application and won't be able to access user data that is not public.
With the user token context, you'll be rate limited per token/user, this is desirable if you have several users and need to make more calls than application context rate limiting allows.
Your total call capacity (usually per 15 minutes) = number_of_user_tokens X per_user_token_per_api_rate_limit.
Also, this way you can access private user data.
Which to use depends on your scenarios.
Don't know for sure but:
I use tweetsharp with .NET and there I see that the consumer-pair is used to create a twitterservice to be able to execute some actions.. The accessToken-pair is used to sign requests with your own Twitter account
Dim service As TwitterService = New TwitterService(obj.consumer_key, obj.consumer_secret)
service.AuthenticateWith(obj.access_token, obj.access_token_secret)