API Security - Screen
API Security - Screen
This booklet gathers a selection of articles that cover the most important aspects of securing
APIs and microservices. It gives an introduction to related issues, such as how to utilize well-
established standards, like OAuth 2, OpenID Connect and SCIM, and how to connect these to
your applications, systems and user identities.
We hope you find this useful, and that it helps you secure your current and upcoming APIs.
This is why we’ve created the API Security Maturity Model. Inspired by the Richardson Maturity
Model, which outlines increasing degrees of web service development maturity, the API
Security Maturity Model reframes the model within the context of security. Within this model,
security and trust are improved the higher up you go.
More on the specifics of that below. But first, let’s expand on each maturity stage within the
model to understand its benefits and drawbacks.
For example, consider an eCommerce store. It makes API calls to a payment API based on
user purchases. It sends authentication in the form of an API Key or Basic Authentication
in the header to the app and passes it to APIs. The user ID is placed in the Body or URL.
In the example below, there are two APIs: BILLING and INVENTORY. Since HTTP Basic
Authentication or API keys only authenticate the STORE_WEB, the store must pass on user
data.
/INVENTORY
USERID
AGE
SHIRT_SIZE
ADDRESS
STORE_WEB
/BILLING
/INVENTORY
USERID
AGE
SHIRT_SIZE
ADDRESS
AD
D_
PR
OD
UC
T
Authorization: Bearer eyEFGH
BUY BACK OFFICE
Authorization: Bearer eyABCD
E
AG
AN
M
STORE_WEB
/BILLING
One great benefit of OAuth is Scopes. Scopes can be utilized as “named permissions” within
a token. These Scopes can specify user privileges. OpenID Connect defines [standard scopes]
that can be used to generate standard identity arguments. Or, you can create [custom scopes]
for your API. Scopes have more useful data and are better than building ‘if’ statements into a
system.
Let’s consider our eCommerce store again. Now, we introduce Scopes, so that the public web
store and back-office can have different privileges. However, some operations overlap. The
Scope LIST is used to list invoices in the billing API. The ID to list for is in the URL or passed
as a request parameter. Thus, it’s possible to manipulate the call to list invoices for another
user. Thus, the Scope is not sufficient. Scopes also lock down what the client application is
allowed to do; they don’t help with the particular user since they are only “names” and not
“values.” Instead, Claims should be used so that the parameter is baked into the token. Then
it’s easy to separate back office privileges from store_web privileges.
/INVENTORY
USERID=ID_123
AGE
SHIRT_SIZE
ADDRESS
/B
I
Au LLIN FG
H
tho G E
riz /ID_1 ey
ati
on 23/A er BACK OFFICE
ar
VIEW SC
:B
ea LL Be
INVOICES OP rer n: E
io AG IST
E: ey at
ID_123 LIS AB riz AN L
STORE_WEB
T CD
tho M PE:
O
Au S C
/BILLING
What are JWTs? Well, to clarify common misconceptions, a JWT is NOT a protocol. It’s a
signed piece of data. OAuth flows utilize JWTs to verify transactions. JWTs can be used to
share Scopes.
And Claims? Claims are essentially assertions. For example, consider a written statement:
“Jacob is an identity specialist, says Travis.” This claim has a Subject (Jacob), an Attribute
(that he is an identity specialist), and an Asserting Party (Travis). If you trust Travis, then you
trust the Claim. Many Attributes can make up identity. There are Subject attributes, like name,
age, height, weight, etc. For these attributes, the Asserting Party would be the police or tax
authorities. There are also Context Attributes, such as the situation, timing, location, weather,
etc.
Instead of trusting the attributes themselves, it’s far better to trust claims made by common
parties. Identity systems use Claims with similar anatomy for verification. If you trust
the OAuth Server that issues keys, then you trust the claim being made. To verify a claim
(simplified):
As the API Security Maturity Model displays, highly mature APIs place trust in very few
sources. Especially, these evolved APIs place trust in the issuer of tokens. This does not
guarantee the truth but is the closest representation to validating the identity of requesting
parties. Furthermore, standardizing this process with centralized trust removes spaghetti
code and wasted effort on custom code.
Essentially, the pinnacle of API security is to trust claims, not attributes. When building an
identity-based API security system based on claims, remember some best practices:
Without a holistic approach, your API may be incredibly secure, your OAuth server locked
down, and your OpenID Connect Provider tucked away in a safe enclave. Your firewalls,
network, cloud infrastructure, or the mobile platform may open you up to attack if you don’t
also strive to make them as secure as your API.
To account for all three of these security concerns, you have to know who someone is and
what they are allowed to do. To authenticate and authorize someone on your servers, mobile
devices, and in your API, you need a complete Identity Management System. At the head of
API security, enterprise security and mobile security is identity!
Only after you know who someone (or something) is can you determine if they should be
allowed to access your data. We won’t go into the other two concerns, but don’t forget these
as we delve deeper into API security.
Provisioning SCIM
Authorization
This protocol suite gives us all the capabilities we need to build a secure API platform. The
base of this, OAuth and OpenID Connect, is what we want to go into in this article.
Overview of OAuth
OAuth is a sort of “protocol of protocols” or “meta protocol,” meaning that it provides a useful
starting point for other protocols (e.g., OpenID Connect, NAPS, and UMA). This is similar to
the way WS-Trust was used as the basis for WS-Federation, WS-Secure, etc., if you have that
frame of reference.
Beginning with OAuth is important because it solves a number of important needs that most
API providers have, including:
• Delegated access
• Reduction of password sharing between users and third parties (the so called
“password anti-pattern”)
• Revocation of access
When the password anti-pattern is followed and users share their credentials with a third-
party app, the only way to revoke access to that app is for the user to change their password.
Consequently, all other delegated access is revoked as well. With OAuth, users can revoke
access to specific applications without breaking other apps that should be allowed to
continue to act on their behalf.
Scopes
OAuth defines something called “Scopes.” These are like permissions or delegated rights that
the Resource Owner wishes the client to be able to do on their behalf. The client may request
certain rights, but the user may only grant some of them or allow others that aren’t even
requested. The rights that the client is requesting are often shown in some sort of UI screen.
Such a page may not be presented to the user, however. If the user has already granted the
client such rights (e.g., in the EULA, employment contract, etc.), this page will be skipped.
What is in the scopes, how you use them, how they are displayed or not displayed, and pretty
much everything else to do with scopes are not defined by the OAuth spec. OpenID Connect
does define a few, but we’ll get to that in a bit.
1. Access Tokens: These are tokens that are presented to the API
2. Refresh Tokens: These are used by the client to get a new access token from the AS
(Another kind of token that OpenID Connect defines is the ID token. We’ll get to that in a bit.)
NOTE: The Authorization Server may or may not issue a refresh token to a particular client. Issuing
such a token is ultimately a trust decision. If you have doubts about a client’s ability to keep these
privileged tokens safe, don’t issue one!
Passing Tokens
resource type, and share a set of common attributes.
As you start
You’reimplementing
probably already OAuth, you’ll
familiar with find
these that
sets of attributes, since they are common in pretty much all
you haveidentity
moremanagement
tokens than you ever
systems. knew
All SCIM what
types are to
identified by the schema in the payload, like the User
By Value
do with! How you pass these around your system
will certainly affect your overall security. There are
two distinct ways in which they are passed:
– Identifies the source of the data. This could be an ID from your database or a
Twitter handle – wherever you got the user or resource from originally
1. By value – Common metadata, such as a timestamp for when the resource was created and
By Reference
, as well as where you can find it, or the location (URL) of the given resource.
2. By reference
These are analogous to the way programming language pass data identified by variables.
The run-time will either copy the data onto the stack as it invokes the function being called
(by value) or it will push a pointer to the data (by reference). In a similar way, tokens will either
contain all the identity data in them as they are passed around or they will be a reference to
that data.
1. Bearer tokens
You can think of bearer tokens like cash. If you find a dollar bill on the ground and present it
at a shop, the merchant will happily accept it. She looks at the issuer of the bill and trusts that
authority. The salesperson doesn’t care that you found it somewhere. Bearer tokens are the
same. The API gets the bearer token and accepts the contents of the token because it trusts
the issuer (the OAuth server). The API does not know if the client presenting the token really
HoK tokens are like a credit card. If you find a credit card on the street and try to use it at a
shop, the merchant will (hopefully) ask for some form of ID or a PIN that unlocks the card.
This extra credential assures the merchant that the one presenting the credit card is the one
to whom it was issued. If your API requires this sort of proof, you will need HoK key tokens.
This profile is still a draft, but you should follow this before doing your own thing.
NOTE: You may have heard of MAC tokens from an early OAuth 2 draft. This proposal was never
finalized, and this profile of tokens are never used in practice. Avoid this unless you have a very
good reason. Vet that rational on the OAuth mailing list before investing time going down this
rabbit trail.
Token Format
We also have different formats of tokens. The OAuth specification doesn’t stipulate any
particular format of tokens. This was originally seen by many as a negative thing. In practice,
however, it’s turned out to be a very good thing. It gives immense flexibility. Granted, this
comes with reduced interoperability, but a uniform token format isn’t one area where interop
has been an issue. Quite the contrary! In practice, you’ll often find tokens of various formats
and being able to switch them around enables interop. Example types include:
• Sending
WS-Security tokens, especially SAML tokens
a Post request to the user’s endpoint creates a new resource
• JWT tokens (which I’ll get to next)
• Legacy tokens (e.g., those issued by a Web
Access Management system)
• Custom tokens
Custom tokens are the most prevalent when passing them around by reference. In this case,
they are randomly generated strings. When passing by val, you’ll typically be using JWTs.
• The issuer
• The subject or authenticated user (typically the Resource Owner)
• How the user authenticated and when
• Who the token is intended for (i.e., the audience)
If it helps, you can compare JWTs to SAML tokens. They are less expressive, however, and
you cannot do everything that you can do with SAML tokens. Also, unlike SAML they do not
use XML, XML name spaces, or XML Schema. This is a good thing as JSON imposes a much
lower technical barrier on the processors of these types of tokens.
JWTs are part of the JSON Identity Suite, a critical layer in the Neo-security Stack. Other
things in this suite include JWA for expressing algorithms, JWK for representing keys, JWE
for encryption, JWS for signatures, etc. These together with JWT are used by both OAuth
(typically) and OpenID Connect. How exactly is specified in the core OpenID Connect spec
and various ancillary specs. In the case of OAuth, this is including the Bearer Token spec.
OAuth Flow
OAuth base specification defines different “flows” or message exchange patterns. These
interaction types include:
• OAuth is not used for authorization. You might think it’s from its name, but it’s not.
• OAuth is also not for authentication. If you use it for this, expect a breach if your data is
of any value.
• OAuth is also not for federation.
• API identity control now maps your access tiers, enabling easy enforcement for freemium
OAuth is for
So what is it for? It’s for delegation, and delegation
• Constructing scopes into APIonly! delegatedmeans
design rather than third party authentication access
freedom of any
authentication method without bothering the APIs with all the details;
This is your plumb line. As you• Can help in separating private, public, partner APIs — complementing platform strategy and
architect your OAuth
deployment, ask yourself: In this scenario, am I using OAuth for
anything other than delegation?• AsIf so, godepartments
marketing back to the drawing
have high demand on smooth customer journeys, this provides a
quicker time to market when it comes to authentication.
board. ONLY!
one and only one pattern is needed for microservices design
To see how this nuance makes a very big difference, imagine you’re a business owner.
Suppose you hire an assistant to help you manage the finances. You consent to this assistant
withdrawing money from the business’ bank account. Imagine further that the assistant
goes down to the bank to use these newly delegated rights to extract some of the company’s
capital. The banker would refuse the transaction because the assistant is not authorized —
certain paperwork hasn’t been filed, for example. So, your act of delegating your rights to
the assistant doesn’t mean squat. It’s up to the banker to decide if the assistant gets to pull
money out or not. In case it’s not clear, in this analogy, the business owner is the Resource
Owner, the assistant is the client, and the banker is the API.
As I’ve mentioned a few times, OpenID Connect defines a new kind of token: ID tokens. These
are intended for the client. Unlike access tokens and refresh tokens that are opaque to the
client, ID tokens allow the client to know, among other things:
• How the user authenticated (i.e., what type of credential was used)
• When the user authenticated
• Various properties about the authenticated user (e.g., first name, last name, shoe size,
etc.)
This is useful when your client needs a bit of info to customize the user experience. Many
times I’ve seen people use by value access tokens that contain this info, and they let the
client take the values out of the API’s token. This means they’re stuck if the API needs to
change the contents of the access token or switch to using by ref for security reasons. If your
client needs data about the user, give it an ID token and avoid the trouble down the road.
• openid (required)
• profile
• email
• address
• phone
You can also (and usually will) define others. The first is required and switches the OAuth
server into OpenID Connect mode. The others are used to inform the user about what type of
data the OP will release to the client. If the user authorizes the client to access these scopes,
the OpenID Connect provider will release the respective data (e.g., email) to the client when
the client calls the user info endpoint. This endpoint is protected by the access token that the
client obtains using the code flow discussed above.
NOTE: An OAuth client that supports OpenID Connect is also called a Relying Party (RP). It gets this
name from the fact that it relies on the OpenID Connect Provider to assert the user’s identity.
Conclusion
In this post, I dove into the fundamentals of OAuth and OpenID Connect and pointed out their
place in the Neo-security Stack. I said it would be in depth, but honestly, I’ve only skimmed
the surface. Anyone providing an API that is protected by OAuth 2 (which should be all of
them that need secure data access), this basic knowledge is a prerequisite for pretty much
everyone on your dev team. Others, including product management, ops, and even project
management should know some of the basics described above.
Unlike a traditional monolithic structure that may have a single security portal, microservices
pose many problems. Should each service have its own independent security firewall? How
should identity be distributed between microservices and throughout my entire system? What
is the most efficient method for the exchange of user data?
There are smart techniques that leverage common technologies to not only authorize but
perform delegation across your entire system. In this article we’ll identify how to implement
OAuth and OpenID Connect flows using JSON Web Tokens to achieve the end goal of creating
a distributed authentication mechanism for microservices — a process of managing identity
where everything is self-contained, standardized, secure, and best of all — easy to replicate.
The move toward microservices could have dramatic repercussions across the industry,
allowing SaaS organizations to deploy many small services no longer dependent on large
system overhauls, easing development, and on the user-facing side allowing easy pick-and-
choose portals for users to personalize services to their individual needs.
1. The Client requests access to the Resource Server by calling the Authorization Server.
2. The Authorization Server redirects to allow the user to authenticate, which is usually
performed within a browser. This is essentially signing into an authorization server, not
the app.
3. The Authorization Server then validates the user credentials and provides an Access
Token to the client, which can be used to call the Resource Server.
5. The Resource Server asks the Authorization Server if the token is valid.
6. The Authorization Server validates the Token, returning relevant information to the
Resource Server i.e. time until token expiration, who the token belongs to.
7. The Resource Server then provides data to the Client. In our case, the requested emails
are unbarred and delivered to the Client.
An important factor to note within this flow is that the Client — our email notification app
— knows nothing about the user at this stage. The token that was sent to the client was
completely opaque — only a string of random characters. Though this is a secure exchange,
the token data is itself useless to the client. The exchange thus supplies access for the
client, but not user information. What if our app needed to customize the User Experience
(UX) based on which membership level the user belonged to, a group they were a member
of, where they were located, their preferred language, etc.? Many apps provide this type of
experience and for that they require additional user information.
To give the client something other than the opaque token provided in the OAuth flow, use an
alternative flow defined in OpenID Connect. In this process, the Authorization Server, which
is also called an OpenID Connect Provider (OP), returns an ID Token along with the Access
Token to the client. The flow is as follows:
1. The Client requests access to the Resource Server by calling the Open ID Connect
enabled Authorization Server.
3. The Authorization Server then validates the user credentials and provides an Access
Token AND an ID Token to the client.
5. The Client then sends the Access Token to the Resource Server
6. The Resource Server responds, delivering the data (the emails) to the Client.
Client
Access Token Resource Server (RS)
Describing Login Information
Considering these three important actors Resource Server (the API), Authorization Server (OAuth),
Authentication Server (Login), we need to know who is requesting access, which type of application
requesting access, and the privileges that user has. Accounting for the login process is important as it
completes the picture of these flows.
Sessions
The ID token contains information about the user, such as how they authenticated, the name,
email, and any number of custom data points on a user. This ID token takes the form of a
JSON Web Token (JWT), which is a coded and signed compilation of JSON documents.
The document includes a header, body, and a signature appended to the message. Data +
Signature = JWT.
Using a JWT, you can access the public part of a certificate, validate the signature, and
understand that this authentication session was issued — verifying that the user has been
authenticated. An important facet of this approach is that ID tokens establish trust between
the Authorization Server/Open ID Connect Provider and the Client.
This type may contain necessary user information that the client requires. The data is
compiled and inserted into the message as an access token. This is an efficient method
because it erases the need to call again for additional information. If exposed over the web,
a downside is that this public user information can be easily read, exposing the data to an
unnecessary risk of decryption attempts to crack codes.
1. The Reference Token is issued by the Authorization Server. The client sends back when
it’s time to call the API.
2. In the middle: The Authorization Server validates the token and responds with a JWT.
In the middle we essentially create a firewall, an Authorization Server that acts as a token
translation point for the API. The Authorization Server will translate the token, either for a
simple Reverse Proxy, or a full-scale API Firewall. The Authorization Server shouldn’t be in the
“traffic path” however — the reverse proxy finds the token and calls the Authorization server to
translate it.
• We need to identify the user multiple times: We’ve shown how to leave authentication
to OAuth and the OpenID Connect server, so that microservices successfully provide
access given someone has the right to use the data.
• We have to create and store user sessions: JWTs contain the necessary information
to help in storing user sessions. If each service can understand a JSON web token,
then you have distributed your identity mechanism, allowing you to transport identity
throughout your system.
Token Translation
In microservice architecture, an access token should not be treated as a request object, but
rather as an identity object. As the process outlined above requires translation, JWTs should
be translated by a front-facing stateless proxy, used to take a reference token and convert it
into a value token to then be distributed throughout the network.
Why Do This?
By using OAuth with OpenID Connect, and by creating a standards-based architecture that
universally accepts JWTs, the end result is a distributed identity mechanism that is self-
contained and easy to replicate. Constructing a library that understands JWT is a very simple
task. In this environment, access as well as user data is secured. Creating microservices that
communicate well and securely access user information can greatly increase agility of the
whole system, as well as increase the quality of the end user experience.
As OAuth doesn’t authenticate by itself, the way these flows are structured means that API
access often ultimately relies on user social logins, which is an unfavorable dependency
that actually decreases API security and scalability. APIs are far better secured with a proxy
in-between the API and authentication mechanism, utilizing scopes that delineate the type of
access that the API grants.
Authorization needs to be done on different levels. We now focus on the coarse-grained level,
where we can decide if we should at all consider the request. The next article will discuss the
fine-grained setup where we can make decisions on a per user/request level.
In this article we’ll see why APIs and microservices should decouple user identity from
their designs, and how to go about this implementation. We’ll review some sample flows,
and briefly walk through how OAuth scopes can be used to create a more valuable,
knowledgeable API. Following these cues, the end result will emboss state of the art Identity
and Access Management (IAM) practices within actual API design, in effect utilizing identity
data to secure the entire API lifecycle.
AAA
When an API call is made, we must know who made the request, and if they are allowed to
read and access the requested data. Identity and Access Management is also described as
AAA; an important initialism made up of:
• Authentication: Validation that the user is who they say they are.
• Authorization: Validation of the user, their application, and privileges.
• Auditing: Accounting for user behavior, logging metadata like what is accessed, when
it’s accessed, with what device, and more.
Caching user logs is great, but it doesn’t prevent malformed requests to the server from the
onset. We don’t want to waste resources, so verifying requests must be processed as early as
possible in the code pipeline. So, typically you block this with a proxy. BUT how do you make
sure that the proxy knows what to do? How do we instruct the proxy to decipher what user or
application is accessing the data, and what data they are allowed to access?
Authentication Server to authenticate. to enhance the UX and typically stores the user data in its own
5. The OAuth Server sends the Token to the Resource Owner (RO)
OAuth Server
Client.
Scopes are tied to the client which is where this becomes useful from a coarse-grained
perspective. Consider an Invoicing API, the API can create and list invoices. Customers using
the company app should only be able to view the invoices, while the internal Finance systems
should be able to create invoices. It doesn’t matter if a super admin, or a regular customer
logs in with the customer app, they will only ever be able to list invoices. In the next article
we’ll discuss which invoices they will be able to list.
Let’s build a sample API to see what we’re talking about. We could in example design an
Invoice API that taps into an e-commerce platform. The API provides access to customers,
who are listing the invoices, as well as to employees, who are writing the invoices.
On the other end, ECommerceApp is an application that consumes the Invoices API. You can
think of ECommerceApp as the client in our OAuth flow. As it’s a customer 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:
invoice_write Strong The application must be internal and the user needs
to login using internal credentials on the corporate
network.
1. The ECommerceApp Client makes a request to the OAuth Server sending a basic read
scope.
3. The User enters credentials with Google, the Authentication Server, to authenticate.
4. 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 (which in this case is social) and the subject (the username).
5. The OAuth Server checks its Customer Database to see if the username is in fact a
customer.
6. In this case it does find the username among the customer files, and thus grants the
client an Access Token with the invoice_read scope.
7. The ECommerceApp Client then sends the Access Token to the Invoice API Resource
Server.
This architecture is opposed to the traditional monolithic approach that consolidates
all web components into a single system. The downside of a monolithic design is that
version control cycles are arduous, and scalability is slow. The entire system must be
continuously deployed since it’s packaged together.
The move toward microservices could have dramatic repercussions across the industry, allowing SaaS
organizations to deploy many small services no longer dependent on large system overhauls, easing
development, and on the user-facing side allowing easy pick-and-choose portals for users to personalize
services to their individual needs.
8. The Resource Server verifies with the OAuth Server that the Token is valid.
9. The Resource Server (API) then sends the data to the Client app.
Using this flow, the API becomes much more knowledgeable. By returning different scopes
in step 6, we give the client the ability to tailor the UI and enable or disable certain functions.
Even better is that since the power of the scope told it that sufficient strength was used
during authentication, the API now doesn’t even care which authentication was originally
made or if the user was a customer or not. Empowered with data on the client, the user, and
the access granted by the scopes, it can effectively filter data to the proper channels using an
improved provisioning schematic.
invoice_read
invoice_write
Now we have a more secure, strict API front end that only allows access once these three
rules are met, blocking unregistered users in the proxy.
This is data tied to the user which can be communicated using claims in the OAuth Access
Token.
For that reason, we typically split attributes in two categories: Subject Attributes and Context
Attributes.
Subject Attributes are true about the user no matter how the user logged in. Depending on
authentication method and orchestration during login, you may receive different Subject
Attributes. I.e. if a user logs in using Google, Google will provide certain attributes, and when
they login using Active Directory other attributes may be present. It’s up to the authentication
service to normalize these attributes and make sure the relevant Subject Attributes are
always present.
Context Attributes on the other hand tell us something about the circumstances under which
the Subject Attributes were established. The time of authentication, the location, what
authentication method was used etc. These are relevant when issuing OAuth tokens, because
certain properties of a token may be considered more sensitive and should perhaps only be
present if we’re fairly confident the user is close to the computer. So, if the authentication
time is further back in time than say 30 minutes, we can drop properties in the token to
weaken its strength.
Now that we understand attributes, we need to look at claims. Attributes are only interesting
if we trust the party that issued them or put in other word: if we trust the party that claim
them to be true.
A claim has the following form: Jacob has a Horse, says Travis:
{
sub: [email protected]
name: Jane Doe
iat: 1546300800
exp: 1893456000
iss: https://login.curity.io
subscriber_id: ABC_123
phone_number: +46 123 123 123
}
This JWT contains the following claims: “name”, “iat”, “exp”, “subscriber_id”, “phone_number”.
It also has a subject “sub” and an issuer “iss”. The JWT is normally signed by a key that
matches what the issuer has documented or published out of band. A receiver of this token
can verify that the “iss” field is a host it trusts and use a key provided by that host to verify
that the token has indeed been issued by that party. Once that is done, we can rely on the
claims in the token and act on the information.
OpenID Connect describes standard claims for ID Tokens, but the claims infrastructure is not
limited to only those tokens. Access Tokens can use the same structure, even when using
other formats than Json Web Tokens.
This makes claims very powerful when designing systems in need of finer grained
authorization.
Scopes Revisited
In the previous article we discussed the scope’s role in authorizing access for the client. But
scopes play a deeper role in a claims-based system. Without claims, a scope is just a space
separated list of strings with Scope Tokens or Scope Names.
It’s good to think of the scope parameter as Scope of Access. I.e. this lists the things the client
needs to access.
We give each of these meaning in coarse grained authorization, to see if the client should be
allowed to query the API. But as discussed in the scope article, even if a scope of
invoice_read is present in the token, we don’t know which invoice it should be allowed to read.
OpenID Connect defines the scope as a group of claims. So, the “email” scope token is
mapped to the “email” and “email_verfied” claim. The claims have values associated to then
while the scope token is just a name. This means that a scope is simply a bag of claims.
Requesting a scope will result in zero or more claims to be issued and present in the tokens.
Each OpenID claim is associated with a scope as shown in the image below.
This can be generalized to arbitrary scopes and claims. When it comes to API access this
becomes very useful.
invoice_list
invoice_read
invoice_write
As already discussed, it’s not enough to authorize the particular request based on only
this information. The API needs to know which invoices that it’s allowed to list. Listing the
actual invoice IDs in the token is not very efficient, but let’s assume we have a claim which is
account_id. It’s the financial account that is associated with the user.
If any of these scopes are requested, the resulting token will contain the claims needed with
an associated value for that user. Now the API can easily know if the requested operation
should be authorized or not.
What we have done now is create a contract. The API knows that if the role=customer
it needs to check the account_id claim to see for which account the invoices should be
provided and if the role=finance, it allows writes.
This mitigates many risks. The API no longer needs to rely on data provided from unreliable
sources, but can safely operate on the account, and scope information when performing the
task. It makes it virtually impossible for a third party to inject a different account_id in the
request and the API doesn’t have to look up additional data about the user.
The example should be considered illustrative but shows the essence of how to use claims.
As mentioned previously, the Context Attributes provide this information. Using the OpenID
Connect ID Token, the client can determine not only who logged in, but also when and how.
These are part of the standard claims that are associated with the openid scope implicitly.
Knowing how the user logged in can also be important, since it can help in decisions around
what actions a user may be allowed to take. A user that logged in with a strong authentication
could be allowed to change its account details, while a user that didn’t may perhaps only view
the same data.
Conclusion
Claims are the contents of a token. They are asserted by the issuer, which in this case is the
OAuth or OpenID Connect server. They provide a powerful mechanism to help both the API
and the Client make qualified authorization decisions.
Claims are based out of the OpenID Connect standard and provide a mechanism to help the
API being more fine-grained in the authorization of the requests.
However, one requirement has stayed the same over the years. The system still needs to
know who the caller is, or at least know a little something about the caller. Only when the
caller is known can the data be released. Identity is a prerequisite to authorization.
So how do we fulfill this requirement in ever changing environments? One way is to adhere
to the standards that are available. Following standards ensures interoperability, and well-
written standards help with scalability. But which ones to choose? There are hundreds of
standards that could apply to the subject. For identity alone there are ~50 different ones that
could be relevant depending on the use case.
OAuth2 and OpenID Connect. This should not come as a surprise to anyone, they have been
around a while now and have become de facto standards for digital identity and delegated
access. Together, these two make up the core of a secure API platform.
So, if I install an OAuth/OpenID server, am I done? No, but you’re well on your way. There are
still some measures to be made, and I’ll give you a few tips on how to avoid some of the
pitfalls when deploying largely scaled platforms.
9f3f5786-d9e8-45fd-bbdd-08713188b804
{
”sub”: ”dlindau”,
”name”: ”Daniel Lindau”,
”exp”: 1516239022,
”iat”: 1516236022,
}
The Phantom Token flow is something that we architectured to fulfill the need of hiding
data from clients, and at the same time share all the data the APIs need for making
their authorization decision. Although it’s not a standard in itself, it ties together several
standards in a nice and comprehensible way. It’s a pattern that we have deployed at all of our
customers, with very good results.
The idea is that you allow your OAuth server to issue an opaque access token, a token that is
merely a reference to the token data. The opaque token is represented by a random string, so
there is no way for a potential attacker to extract any data from it. This also means that the
client receiving the token isn’t able to read any data from it. This is because the token is not
really for the client, it’s for the API. When the client uses the token to call an API, the API will
have to de-reference the data by using the introspection capability of the OAuth server. This
will not scale very well, since all APIs would have to do the same thing for every incoming
request and would more or less force the APIs to create their own cache. So instead, we
introduce the API gateway.
With the API gateway in place, we can allow it to perform the introspection for the API. This
means several things. First, it allows us to move the cache to the API gateway which will
give us control over it. Second, we can have the OAuth server respond with more than just
the document that explains if the token is valid or not. It can also respond with the access
token in the form of a JSON Web Token (JWT). The JWT is a JSON representation of the
But now consider this, in a distributed environment, where there are multiple instances of the
API gateway. If you’re unlucky, the API requests might hit new gateways each time, so the
benefits of caching would be lost. To mitigate against this, the OAuth server could be allowed
to warm up the cache for the gateway instances. Depending on the gateway, that could
mean to push the reference/value token pair to the gateway. Or in other cases, push to some
common cache.
Token Validation
When using the Phantom Token flow, the API is able to validate the tokens using the public
key of the OAuth server. To obtain the key, it can use the metadata of the server. The
metadata and where it’s obtained is described in RFC8414 or/and OpenID Connect Discovery
depending on the server. So if your OAuth server supports one of these, it means we can get
the public keys using http requests. The keys are represented in a JWKS, and look something
like this.
{
“keys”: [{
“kty”: “RSA”,
“kid”: “1555934847”,
“use”: “sig”,
“alg”: “RS256”,
“n”: “rCwwj0H1f2Gl3W6...8QlB9R9M_DxcKRQ”,
“e”: “AQAB”
}]
}
This document contains one key with id 1555934847. It could contain a full list of keys.
eyJraWQiOiIxNTU1OTM0ODQ3IiwieDV0IjoiOWdCOW9zRldSRHRSMkhtNGNmVnJnWTBGcmZ-
RIiwiYWxnIjoiUlMyNTYifQ.eyJhdF9oYXNoIjoiV3RDYWN6N3hrNHBHZDE0Y29PeTM3dy-
IsImRlbGVnYXRpb25faWQiOiJiNWZmYjMyZC0zNDdiLTQyYWQtODQzMS03MGEzM2I0N2U-
wMjIiLCJhY3IiOiJ1cm46c2U6Y3VyaXR5OmF1dGhlbnRpY2F0aW9uOmh0bWwtZm9ybT-
podG1sLXByaW1hcnkiLCJzX2hhc2giOiJraUdtTUN0YmNmUy1rZ2FUSTZXLWNRIiwidXB-
kYXRlZF9hdCI6MTU0MDE5NzU2NSwiYXpwIjoidG9vbHMiLCJhdXRoX3RpbWUiOjE1NT-
c3ODMxMjMsInByZWZlcnJlZF91c2VybmFtZSI6ImphY29iIiwiZ2l2ZW5fbmFtZSI6Ik-
phY29iIiwiZmFtaWx5X25hbWUiOiJJZGVza29nIiwiZXhwIjoxNTU3Nzg2NzMzLCJuYmY-
iOjE1NTc3ODMxMzMsImp0aSI6IjExOGYyMDJkLTcyZjctNGI5Zi05MTk0LTU5MDZiYzA-
wNjQwMiIsImlzcyI6Imh0dHBzOi8vbm9yZGljYXBpcy5jdXJpdHkuaW8vfiIsImF1ZCI-
6InRvb2xzIiwic3ViIjoiamFjb2IiLCJpYXQiOjE1NTc3ODMxMzMsInB1cnBvc2UiOiJpZCJ9.
DnY8tSaT2VoDfVUazp28JnKPnl1o0bOaCZRRx6nR31vebG8xkTQLGGD56piiwp6HroehRECtniOx-
OMuPi91w7NBqVky3jbxDNYRyfmbTMxz6TRk2k1M-Tc2d1UrQposSf-GNeMxchVB47pzArUAcnACM-
58vB83RpCzdsbv3VxdLcP9Bp8hGSU3bGKSLDJIEYlWYV9au2qYrwLA2Avzj-ZCv4qK6WxIlcbQdfHk-
w3hsF_JULTxxvMHFwE6EAzxEXu5DRiNVJqn57P_jc4wW5SLkxS0fhBXFG2LZ2tnSGaoNc3JZ5g6L-
nJ-7IXvg14NWtzLM6yPMv5Dw_KxC5bBIFjFw
This is a JWT. It has a header in pink, body in grey, and the signature in green. The header and
body are encoded JSON documents, and the signature is encoded binary data. The parts are
separated with a period (‘.’) character. If we decode the header, it looks like this
{
“kid»: “1555934847”,
“alg”: “RS256”
}
The “kid” (key ID), points to the key in the JWKS that was used to sign this JWT, and the “alg”
(algorithm) describes how it was signed. So to validate the JWT, the API can use the key
from the JWKS and validate that the signature is correct. If the validation passes, the data
of the body can be trusted, and the API can base its authorization decision on it. Mission
accomplished!
That means to validate an incoming token, the API must do the following:
• Get server metadata
• Cache keys locally
• Validate the signature
Important to note here is that if a token comes to the API with a “kid” that is not recognized, it
can mean two things. Either the server rolled its keys, or the token comes from an untrusted
source. To be sure, the API must first update its keys, and if the kid still isn’t found it means
that the source is untrusted. This way, the server can roll its keys at any time without getting
dropped requests by the API.
This works really well in all environments that can keep a state, like traditional web servers,
Docker containers, Kubernetes and so on. But for other things like lambda functions we need
something else.
The OAuth server can now issue JWTs with slight difference from before
{
“x5c»: “MIICojCCAYoC…xMjExMjJaFw0yNDAxMjcxM”,
“alg”: “RS256”
}
Instead of the “kid” we had from before, we have a “x5c”. x5c contains the full certificate
that corresponds to the key used to sign the JWT. So to validate the token, the API needs to
extract the certificate, validate that it’s issued by the CA and validate the signature using the
public key of the certificate.
So we have enabled lambda functions to validate JWTs, without the http overhead. And the
server can still roll keys by getting a new signing certificate.
Final Thoughts
By following these patterns in your platform, you allow all the components in the platform
to be distributed or to dynamically scale. But maybe even more important, it allows you to
enforce your access policies in both APIs and gateways. The policy enforcement can be
made without calling out to a third party, since all the data needed is provided in the request.
What enables us to create these patterns is the use of standards. We separate the concern of
every component in the platform, and by tying them together with the use of open standards
we’re not only allowing them to scale separately, but we also allow them to be replaceable.
Since the glue of the components are standard protocols, it makes it easier to replace
components. All of this will make you able to build a truly scalable platform.
OpenID Connect is a modern federation specification. It’s a passive profile, meaning it’s boun
What is SCIM?
SCIM stands for “System for Cross-domain Identity Management” and is firstly a
standardized way of representing users, groups, and anything related. Secondly, SCIM
helps to standardize methods for acting on this data, such as creating, querying, searching,
updating, and deleting. In other words, it’s an API model.
These two parts of SCIM are split into two standards: a Core Schema (RFC7643) controlling
how the data is modelled, and a Protocol for interacting with the data (RFC7644).
an also (and usually will) define others. The first is required and switches the OAuth server into
ct mode. The others are used to inform the user about what type of data the OP will release t
If the user authorizes the client to access these scopes, the OpenID Connect provider will rele
Standards can still be frightening, complex, over engineered, and/or boring. With SCIM,
however, all data is represented as JSON and the protocol is built on REST. Also, you’re
probably already handling users so there is a pretty good chance that you are familiar with
some aspects of SCIM. By the end of this article, you’ll hopefully be able to look at SCIM and
similarly say “I know this.”
A huge plus of using a standard interface is that there is no need to document each system
separately; if you have a unified way for user management, the documentation is in the
specification itself. It’s important to note that the SCIM specification focuses on what is
needed for user management, not security. Therefore, things like how to secure access to a
system and the permissions to access a system are left to other standards like OAuth.
Another benefit of SCIM is that you are free to extend these fields with your own schemas or
resource types.
So what is a user?
Within almost all systems handling users, we find some common attributes. Amongst these
are:
• Username
• Names (first name, last name, etc.)
• Contact (phone numbers, email addresses)
• Groups
• Locales (time zone, location, etc.)
• Password (never visible in payload, i.e. a “write only” attribute)
Passwords are a bit special in SCIM. It’s an attribute handled in the standard, but you
can never view a password when you request a user resource. You can still query and do
authentication through SCIM, but you can’t get a list of passwords, or a password to a
specific user.
Less common attributes are things like social media or instant messaging handles. For
example, the specification even mentions ICQ!
A regular GET request to one of those endpoints lists all resources for that resource type, but
naturally you want to have some limitations on entries, pagination, and the current position.
Browsing is as simple as passing in the “pagination” parameters (and optionally, sorting) in
the request. It’s also possible to show (include/exclude) specific attributes of interest.
1 {
2 “totalResults”: 100,
3 “itemsPerPage”: 10,
4 “startIndex”: 1,
5 “schemas”: [“urn:ietf:params:scim:api:messages:2.0:ListResponse”], “Resource”:
[{
6 …
7 }]
8 }
When using GET to retrieve information it’s often not ideal to show passwords or personal
IDs in the URL. While GET requests are RESTful, it exposes parameters in the URL. Adding
/.search to the URL makes it possible to search by POST as well, which is ideal for
sensitive data like credentials or other personal information.
/Users?filter=userName eq “teddy”
/Users?filter=emails.value ew “curity.io” and meta.lastModified lt
“2017-01-01T00:00:00Z”
/Users?filter=name.familyName co “O’Malley”
/Users?filter=title pr
/Users?filter=filter=emails[type eq “work” and value co “@example.com”]
/Groups?filter=displayName eq “Curity” or displayName eq “Twobo”
/?filter=(meta.resourceType eq User) or (meta.resourceType eq Group)
{
“schemas”: [“urn:ietf:params:scim:api:messages:2.0:SearchRequest”], “filter”:
“userName
eq \”teddy\” and password eq \”F&1!b90t111!\””
}
/ServiceProviderConfig
A sort of meta thing of SCIM is that it also defines what you as a service provider support.
You can choose yourself what you want to support. The /ServiceProviderConfig endpoint is a
way to advertise which features are supported by the service provider.
While features like this certainly add additional functionality within niche contexts, not all
SCIM features make sense for all implementations. For example, advertising specific service
provider features is a great resource for anyone interacting with your SCIM API.
Overview of OAuth
OAuth is a sort of “protocol of protocols” or “meta protocol,” meaning that it provides a useful starting point
for other protocols (e.g., OpenID Connect, NAPS, and UMA). This is similar to the way WS-Trust was used as
the basis for WS-Federation, WS-SecureConversation, etc., if you have that frame of reference.
Beginning with OAuth is important because it solves a number of important needs that most API providers
have, including:
• Delegated access
• Reduction of password sharing between users and third-parties (the so called “password
anti-pattern”)
• Revocation of access
When the password anti-pattern is followed and users share their credentials with a third-party app, the only
way to revoke access to that app is for the user to change their password. Consequently, all other delegated
“I Know This”
Hopefully, you’ve found this article valuable and see that SCIM isn’t all that scary — at least
not as scary as being chased by dinosaurs. In the future, the image above likely illustrates
what you’ll say the next time you come across a SCIM system.
About Curity
OAuth and OpenID Connect done better
Curity is the leading supplier of API-driven identity management, providing unified security for
digital services.
Curity Identity Server is the world’s most powerful OAuth and OpenID Connect Server; it’s
used for logging in and securing millions of users’ access to web and mobile apps over
APIs and microservices. Curity Identity Server is built upon open standards and designed for
development and operations. We enjoy the trust of large organizations in financial services,
telecom, retail, energy and government services with operations across many countries which
have chosen Curity for their enterprise-grade API security needs.
To learn more, visit curity.io or contact us at [email protected] or +46 8-410 737 70.