API Security - Part 3 - Design OAuth Scopes, Claims based access
In part 1 I wrote about JSON Web Token (JWT) is an open standard for creating access tokens that assert some number of claims. We also looked at the structure of the JWT. JWT is compact can be sent through a URL, POST parameter, or inside an HTTP header. Additionally, the smaller size means transmission is fast. JWT is also self contained meaning, the payload contains all the required information about the user, avoiding the need to query the database more than once.
We also learnt the key principles like segregation of concerns and decoupling of Authentication & Authorization from Resource Server applications as a criteria for choosing the standards or protocols. We have two standard protocols SAML and OAuth which were developed to address the Authentication and Authorization between two entities; a Service provider (Resource Server) and an Identity provider.
Security Assertion Markup Language (SAML) is an XML-based framework. Authentication information is exchanged through digitally signed XML documents.. It’s a complex single sign-on (SSO) implementation that enables seamless authentication, mostly between businesses and enterprises.
Created in 2006, OAuth2 is an open standard for authentication protocol that provides authorization workflow over HTTP and authorizes devices, servers, applications, and APIs with access tokens instead of credentials. OAuth gained popularity thanks to Facebook, Google, Microsoft, and Twitter, who allow usage of their accounts to be shared with third-party applications or websites. Just because of the shear popularity and ease of use and widespread adoption, I focused on OAuth2 as the choice for getting the tokens.
In Part 2, I focussed on OAuth2 terminologies, Discretionary Access Control and Mandatory Access Control. In Part 3 we shall learn about how JWT works, what information should the token carry, and to use it secure API covering both the aspects of Discretionary and Mandatory Access control
Lets understand the basic architecture of Identity and Access Management(IAM)
Now lets look at how "OAuth2 - delegation protocol" tried to answer the authorization questions
- How to give power to delegates (Clients) without revealing too much (passwords)? --- access tokens
- How to restrict the power of delegates on server apps? --- Scopes
OAuth defined Scopes a hint to Access Right, which is defined as string. In OAuth2 spec, Resource server permits access depending on scope, but didn't define on how to map scope to access right. Authorization servers has just the list of Scopes
If we see the overview of the technology map we see a gap in how to effectively define the access control language and the rule engines to be used for the RESTful APIs
In this article we shall just focus on how to generate the JWT with the desired claims for the resource server to interpret. We can look at the resource server implementation in our future articles
How do JWT work?
In today's world of hybrid application or Single page application contact multiple backends (split up into seperate micro-service authentication servers, databases, machine learning servers, etc). In authentication, when the user successfully logs in using their credentials, a JSON Web Token will be returned and must be saved locally (typically in local storage, but cookies can be also used), instead of the traditional approach of creating a session in the server and returning a cookie. Now you can use that token to do whatever you want to do with the server (that you have authorization to do).
A Familiar Example – Airline Boarding Pass (Self Contained Token)
Lets look at another familiar analogy is the authentication protocol you follow each time you visit an airport.
You can't simply walk up to the airport terminal gate and present your passport or driver's license. Instead, you must first check in at the ticket counter. Here, you present whatever credential makes sense. If you're going overseas, you show your passport. For domestic flights, you present your driver's license. After verifying that your picture ID matches your face (authentication), the agent looks up your flight and verifies that you've paid for a ticket (authorization). Assuming all is in order, you receive a boarding pass that you take to the airport terminal gate.
A boarding pass is very informative. Gate agents know your name and frequent flyer number (authentication and personalization), your flight number and seating priority (authorization), and perhaps even more. The gate agents have everything that they need to do their jobs efficiently.
There is also special information on the boarding pass. It is encoded in the bar code and/or the magnetic strip on the back. This information (such as a boarding serial number) proves that the pass was issued by the airline and is not a forgery.
In essence, a boarding pass is a signed set of claims made by the airline about you. It states that you are allowed to board a particular flight at a particular time and sit in a particular seat. Of course, agents don't need to think very deeply about this. They simply validate your boarding pass, read the claims on it, and let you board the plane.
It's also important to note that there may be more than one way of obtaining the signed set of claims that is your boarding pass. You might go to the ticket counter at the airport, or you might use the airline's website and print your boarding pass at home. The gate agents boarding the flight don't care how the boarding pass was created; they don't care which issuer you used, as long as it is trusted by the airline. They only care that it is an authentic set of claims that give you permission to get on the plane.
The contents of the Boarding Pass:
- Airline Name/Code (Issuer)
- Issued Date/Flight Name/Boarding Time/Gate No (Validity)
- Passenger Name (Subject)
- Seat No/Meal preference (Claims)
Whats is a Claim?
A claim is a statement that one subject makes about itself or another subject. The statement can be about a name, identity, key, group, privilege, or capability.
Whenever the user wants to access a protected route or resource, the user agent should send the JWT (Claim), typically in the Authorization header using the Bearer schema. For example, the content of the header should look like the following:
Authorization: Bearer <token>
This is a stateless authentication mechanism as the user state is never saved in the server’s memory. The server's protected routes will check for a valid JWT in the Authorization header, and if it's present, the user will be allowed to access protected resources. As JWTs are self-contained, all the necessary information is there, reducing the need to query the database multiple times.
This allows you to fully rely on data APIs that are stateless, and even make requests to downstream services. It doesn't matter which domains are serving your APIs, so Cross-Origin Resource Sharing (CORS) won't be an issue as it doesn't use cookies.
Advantages of JWT
- No Session to Manage (stateless): The JWT is a self contained token which has authentication information, expire time information, and other user defined claims digitally signed.
- Portable: A single token can be used with multiple backends.
- No Cookies Required, So It's Very Mobile Friendly
- Good Performance: It reduces the network round trip time.
- Decoupled/Decentralized: The token can be generated anywhere. Authentication can happen on the resource server, or easily separated into its own server.
Claims simplify Authentication and Authorization Logic
For an application or the Resource API Service developer, the advantage of this system is clear: your application or API Service Implementation doesn't need to worry about what sort of credentials the user presents. Someone who determines your company's security policy can make those rules, and buy or build the issuer. Your application simply receives the equivalent of a boarding pass. No matter what authentication protocol was used, Kerberos, SSL, forms authentication, or something more exotic, the application gets a signed set of claims that has the information it needs about the user. This information is in a simple format that the application can use immediately.
Claims-based identity allows you to factor out the authentication logic from individual applications. Instead of the application determining who the user is, it receives claims that identify the user. Claims help you to factor authentication logic out of your applications.
Think of it like a hotel key: you register at the front-desk, and they give you one of those plastic electronic keys with which you can access your room, the pool, and the garage, but you can't open other people's rooms or go into the manager's office. And, like a hotel key, when your stay has ended, you're simply left with a useless piece of plastic (i.e., the token doesn't do anything anymore after it's expired).This concept is called as Claims Based Access Management
The Resource Server is orchestrated to check that the incoming request has its access token and validates the token for validity and determines whether the scopes included with the token include that which entitles the client to the resource. The context includes even in the case of API chaining
If we try to generalize the interaction highlighted as shown above with the brown dotted line boundary, is the fundamental model of access control system.
- a subject: an active entity which initiates a query to access a resource,
- an object or a resource: a passive entity that needs protection from unauthorised use,
- an action: an operation that the subject does to the resource when the access is granted, and
- a reference monitor: an abstract machine that mediates all accesses to objects by subjects.
The first step in developing access control system is to identify the objects that needs protection, the subjects which initiate the access requests to the objects and execute activities and the actions that can be executed on the objects and must be controlled
If you are need to achieve this, tsecurity access token (JWT) passed to the Resource Server, should capture the security requirements defined by 5W + 1H questions (Who, What, When, Where, Why and How)
- Who can access?
- to What Resource?
- from What device?
- When the access is allowed (or denied)
- at What time?
- Where the access is allowed or denied
- from What Location?
- Why the access is allowed or denied, for What purpose, and
- How the access is given
The reference monitor (JWT Validator on Resource Server) should have the following properties
tamper-proof: the reference validation mechanism should be temper proof.
complete mediation: the reference validation mechanism must mediate all accesses to the system and its resources.
verifiable: the reference validation mechanism must be small enough to be subject to analysis and tests, the verification methods and the completeness of which can be assured.: the reference validation mechanism must mediate all accesses to the system and its resources.
The Discretionary Access Control (DAC) policies enforce access control based on the identity of the subject (requestor) and on explicit access rules stating what subjects are (or are not) allowed to do. The owner of the object or the person who has authorisation to control the object's access has the discretion to decide who can have access to the objects. In general, DAC is used to limit a user's access to an object
Security Policy
A security policy provides a way to enforce uniform security throughout all System, Process & Experience APIs. Through policy, you can assign a role, or collection of rights, to individual users. Each policy entry specifies rights for a user or group
Implementing Claims-Based-Identity
There are some general set-up steps that every claims-based system requires.
Step 1: Add Logic to Your Microservices Or API Proxy to Support Claims
- When you build a claims-based Services, it needs to know how to validate the incoming security token and how to parse the claims that are inside.
Step 2: Acquire or Build an Issuer
Step 3: Configure Your Service to Trust the Issuer
- After you build a claims-based service and have an issuer to support it, the next step is to set up a trust relationship. An service trusts its issuer to identify and authenticate users and make claims about their identities.
- There are several important things to know about an issuer when you establish trust with it:
- What claims does the issuer offer?
- What key should the application use to validate signatures on the issued tokens?
- What URL must users access in order to request a token from the issuer?
Step 4: Configure the Issuer to Know about the Service
- The issuer needs to know a few things about an service before it can issue it any tokens:
- What Uniform Resource Identifier (URI) identifies this application?
- Of the claims that the issuer offers, which ones does this application require and which are optional?
- Should the issuer encrypt the tokens? If so, what key should it use?
- What URL does the application expose in order to receive tokens?
Resource Server Workflow
The resource server (Policy Execution Point) needs to perform the following tasks
- Validate access token : There are three alternatives available with the OAuth2 approach. I would suggest Option 1, as it provides the best performance and provides the simple architecture constrain for each of the resource server implementation
- Is the client correct? No hacking?
- Interpret scope of access token
- Interpret additional information
- Depending on interpretation, decide what kind of information to return
Lets revisit the basic architectural components of Identity and Access Management
Lets check the various access control solutions/patterns available in industry
Let try to focus on the access control component, as most of the other components are fairly well defined by in the OAuth2/OIDC standards. Lets exploit the possibility of Resource Server applications defining the custom scopes, configuring claims associated with those scopes to manage the fine grained access model as much as possible(i.e ABAC)
Attribute based access control is based on Rules or Conditions of attributes about User, Resources, Environment (time, device, etc.). Normally these rule are defined as policies (Security Policies). We can use ALFA for defining fine-grained authorization rules in a JSON-like policy language (which compiles down into XACML). APIs that handle sensitive data pose security and data access control threats, require advanced security solutions.
These Rules are based on 4 parts:(based on XACML rules)
- Attributes (Conditions) : On data of resources, user, environment(device, time .. etc) and other information sources
- Action: permit/deny
- Obligations
- Advices
Example in an Enterprise Senario
Imagine we are creating a System APIs to access the account information from Salesforce.com & Product information from Apptus & Order Information from Salesforce. These APIs are consumed by
- A Partner Mobile App (App 1), where a Partner logs in using his Salesforce Account & view the price of the products & place an Order
- A Warehouse Web App (App 2), where a warehouse operator (employee) logs in using his Enterprise Account & updates the shipping status of the order in SAP
- A Pricing Web App (App 2), where a Marketing Head (employee) logs in using his Enterprise Account & updates the pricing data for the products in Apptus
Based on the requirement, a single API should be exposed to add or retrieve account, order, product price etc. There will be different access requirements that are unique to each member and operation. These types of requirements need the implementation of a fine-grained access control mechanism. This mechanism should ensure that it provides an organization with maximum flexibility while making sure that unauthorized users are not allowed to access resources
Any web-hosted resource that integrates with Identity and Access Management has a resource identifier, or Application ID URI..
By defining these types of permissions, the resource has fine-grained control over its data and how the data is exposed. A third-party app can request these permissions from an app user. The app user must approve the permissions before the app can act on the user's behalf. By chunking the resource's functionality into smaller permission sets, third-party apps can be built to request only the specific permissions that they need to perform their function. App users can know exactly how an app will use their data, and they can be more confident that the app is not behaving with malicious intent. In IAM and OAuth, these types of permissions are called scopes. They are sometimes being referred to as OAUth2Permissions. A scope in IAM is represented as a String value
- Read salesforce account information using Account.Read
- Update credit limit for account using Account.UpdateCreditLimit
- Update account contact Information using Account.UpdateContactInformation
Similarly, we can define the permissions for the Orders Resource as
- Read order information using Orders.Read
- Update shipping information using Order.Ship
- Place a new order using Order.Create
After the user consents to permissions for your app, your app can acquire access tokens that represent your app's permission to access a resource in some capacity. An access token can be used only for a single resource, but encoded inside the access token is every permission that your app has been granted for that resource. At the highest level, we need to scope based claims for the resources. Fine grained access model would be like this
ResourceType: It’s the ResouceType that the activities or rights attached for. For Example, these are
- Account
- Order
- Product
- Catalog
- Quote
Activity/Rights defines the action the user or application the user can take place on that Resource or ResourceType like update the datasheet information of the catalog or price to be displayed on the catalog etc
- Account.Read
- Account.UpdateCreditLimit
- Account.UpdateContactInformation
- Orders.Read
- Orders.Ship
- Order.Create
- Catalog.RegularRead
- Catalog.PartnerRead
- Catalog.Write
ScopeOrRoleControlContextEvaluator defines the higher order scope requested that can be requested for getting the rights/claims for a user or application. Each Activity/Right can be part of multiple ScopeOrRole definition. It also holds the context to choose the appropriate rights based on the OIDC access token context claims like acr (Authentication Context Class Reference), amr (Authentication Methods References) or Groups etc.
ResourceScopes: A ResourceScopes represents a uniquely secured object or set of objects. For Example
- You can create scope for Account#123 or Order#223
- The Actual Scope may look like User.223.Account.Read.AccountID_553, which describes that user 223 can read the account 553 details (Resource)
A principal is a user or group that is used to control security. If you grant user access to a Resource, the user is the principal, if you grant group access to a resource, then group is the principal. The key to scaling security is to keep the number of principals per scope reasonable. By using groups, a smaller number of principals can be used to grant access to a much larger number of users.
For Example:
OAuth is a necessary protocol within the security workflow — but OAuth cannot authenticate. A a separate Authentication Server (example: OpenID Connect server) must tell OAuth who the user is. Normally an authentication chain is built around using the U2F standards
{
subject:
clientID:
scope:
expiration:
}
Federation is used to solve a different problem, that allows for the leverage and reuse of identity credentials across multiple domains and hence it holds accounting for the login information. We describe the authentication between federated systems by logging the following information
{
subject: Who logged in?
auth_time: When the login occurred?
acr: Short for Authentication Context Class Reference, this stipulates how the login happened. This is where the communicating parties can describe and understand the form of authentication used for the login, whether it be Facebook, Google+, or others.
}
Within the OAuth token, scope is an interesting data point. Scope specifies the extent of tokens and are akin to the permissions listed on a consent UI. They are extremely useful, as scopes can be used to delineate API access tiers. Furthermore, OAuth doesn’t specify that you have to give the same scopes that you are requesting — if the scope changes you must simply notify the client/user. For access management designers, this grants us a lot of power and flexibility in how we handle scopes and identity. We’ll see that building an API with scopes hardwired into the design can be extremely helpful.
Let’s build a sample API to see what we’re talking about. Let’s say we are designing our Catalog API, where we would like to display Catalog Information. The API provides access to customers, who are reading the catalog, as well as to employees, who are writing the content to catalog. The Catalog API also has a premium/partner subscription plan, so the API should reflect this higher access tier as well. Essentially, the API must provide the ability to read, add, delete, and update API definition/Information.
On the other end, CatalogReader is an application that consumes the catalog API. You can think of CatalogReader as the client in our OAuth flow. As it’s a reader client, it will be limited in scope without editing capability.
So how do we create permissions? To do so means we define the scopes in the API. The beautiful magic here is that we assign these scopes with different strengths as follows:
So the slightly modified version of the access control components interaction with OAuth2 would look like this
Since we can change the scopes throughout the process, when CatalogReader sends a request with an catalog scope, a new flow would look like this
- The CatalogReader Client makes request to the OAuth Server sending a basic read scope.
- The OAuth Server next delegates authentication responsibility to a third party Authentication Server (Facebook,Google, SFDC).
- The User enters credentials with Google, the Authentication Server, to authenticate.
- The Authentication Server tells the OAuth Server the authentication was successful, and sends an OAuth Token. Within the token is information that will affect the scopes, namely the ACR [Authentication Context Class Reference] (which in this case is social) and the subject (the username).
- The OAuth Server checks its Partner Database to see if the username is in fact a customer.
- In this case it does find the username among the customer files, and thus grants the client an Access Token with both the catalog_regular_read and catalog_premium_read scopes. Note the OAuth Server also tells the Client what scopes it returned, since these were different from the initial scope that was requested. However, keep in mind that the Client must under no circumstances dissect the actual token — it is only meant for the API to consume.
- The ArticleReader Client then sends the Access Token to the Articles API Resource Server. At this point we now know many more things than simply the social ACR.
- The Resource Server verifies with the OAuth Server that the Token is valid.
- The Resource Server (API) then sends the data to the Client app.
Staff Developer Advocate
4 年Amazing article. I love the analogy of the airplane boarding ticket! Thanks for explaining this so eloquently.
API | Cloud Solutions Architect | Software Architect | Tech Lead | B2B | AWS | Azure | GCP
6 年You were able to present a complex subject in a simple and visually pleasing way. Congrats!
Engineering Leadership | Data Analytics | Agile Sofware Development | Lean/Agile Expert
6 年As the other two articles in the series, very well illustrated and explained. Thanks Gangs!