Centralizing Identity Data
On this page
Overview
This article describes a common use-case. An organization has many clients and APIs that all need some portion of identity data about a user. How can the claims infrastructure be used to accommodate all parts of the organization.
The Problem: Multiple Claims and APIs
An organization has a online store, lets call it Company, with the following setup:
- A Shopping website (
ShoppingWebClient
) - An Admin website (
AdminWebClient
) - A Shopping mobile application (
ShoppingMobileClient
) - A Store API for selling items in the store
- An Inventory API for managing and viewing items in the store
Each of these systems require some details (claims) about the user to be able to operate properly. The following image overlays the claims on each system.
sub
- the username, can be changed by the user.customer_id
- the customer id can be used to show discounts etc. Cannot be changed by the user.address
- to know where to deliver and to present to user where to deliverregion
- all items for sale are not available to all countries. This claim tells us what region the user belongs to.store_id
- the company has more brands, so the store the client is acting against has an id.admin_id
- when and admin user is updating the store theadmin_id
is used instead ofcustomer_id
.
The Claims based approach
By defining these claims centrally in the Token Service, and then mapping them to the appropriate tokens and clients, we can make sure that each part of the system only gets the information it needs.
Firstly, we define a number of scopes that contains the claims we're interested in. The scope is a grouping of claims, think of it as "Scope of Access". This makes it more manageable from both the Clients and the sys-admins perspectives.
The Shopping website might know what claims it needs for the website itself but it probably doesn't know what claims the shopping API requires in order to be able to place orders. So requiring the client to request claims for the API is usually not a good idea. Instead we map the claims to scope, and then also map these claims to tokens, so that some claims end up in the tokens that the client can read, and some end up in the tokens that the API can read. For more details about these mappings see claims explained.
With the requirements defined in the problem section we get the following mapping table:
Scope | Claims |
---|---|
order_place | address , customer_id |
inventory_read | region , store_id |
inventory_write | store_id , admin_id |
address | address |
openid | sub |
The address
and openid
scopes are standard scopes with standard claims mapped to them from the OpenID Connect Specification.
Then we also map the claims to tokens for the clients like this:
Scope | Token | Claim |
---|---|---|
order_place | access_token | address , customer_id |
order_place | id_token | - |
inventory_read | access_token | region , store_id |
inventory_read | id_token | region |
inventory_write | access_token | store_id , admin_id |
inventory_write | id_token | admin_id |
address | access_token | - |
address | id_token | address |
openid | all tokens | sub * |
*
- sub
is actually always present in all tokens so the openid
scope serves no purpose for claims mappings in this example. But it is still needed since the client wants an ID Token which is only issued when the openid scope is requested.
Now if ShoppingWebClient
requests tokens it can simply as for the scopes order_place
, inventory_read
, address
and openid
and the tokens it receives will be mapped as expected for each recipient.
Why do we explicitly have the address scope when the order_place
contains the same claim? This is for two reasons, firstly there is a standard mapping in OpenID Connect for the address, which is good to use. Secondly, it is a claim that the client may or may not be interested in, so if a third party client would operate against the store, it may not need the address since it will perhaps not be meaningful for that client. To avoid unnecessary data leak we let the client ask for the address when it needs it. The API will anyway receive it, since it's mapped in the access token.
Token Mappings
The mappings can be done differently for different clients by using different mappers.
Tokens and Clients
This can be confusing for newcomers to claims based systems and OpenID Connect, but the point here is that there are two types of tokens being issued. ID Tokens, which the client can read, and Access Tokens, which the client receives but cannot decode. So we can safely put claims in the access token and be sure that only the API is the reader of that data.
The access tokens is normally an opaque token, meaning it holds no data, only a reference to data. The API can look this up, but the client cannot.
JWTs and tokens
The ID Token is always a JWT which means the client can always read it.
The Access Token could be a JWT, but in the use-case presented it must not be, since that would leak data to the client when it's not desired to do so.
Conclusion
The claims infrastructure is a powerful tool to keep the identity data secure and maintain full control over what part of the system gets access to which information. This is critical in larger organizations and even more important when conforming to regulations such as GDPR.
Jacob Ideskog
Identity Specialist and CTO at Curity
Join our Newsletter
Get the latest on identity management, API Security and authentication straight to your inbox.
Start Free Trial
Try the Curity Identity Server for Free. Get up and running in 10 minutes.
Start Free Trial