Claims Management

Next, we need to think carefully about claims. A claim is simply the name/value pair embedded within our Access and ID Tokens. For example, you might have a user_id or email claim so downstream applications can use them to create profiles or make decisions. The confusing part is that the OAuth Core specification doesn’t introduce the concept of claims or even include the word claim. This is useful because we can define however we need. Unfortunately, the challenge is that people will define them however they need. The JWT specification (RFC 7519) introduces the concept and defines a basic structure but still doesn’t set any conventions for names, structures, etc.

Using OpenID Connect protects us quite a bit. It defines a simple set of claims for user details such as name, address, and similar. If we only use those and limit access according to the proper scopes, the user knows what information they are sharing and applications know how to use it.

Alternatively, as we add extra claims, the natural desire is to have a user-unique identifier. If we’re thoughtful about it, we use an obfuscated primary key that has no meaning outside our system. If we’re not careful, that could be a customer identifier, employee number, or even a Social Security Number. This is the same situation where Facebook is struggling with the implications of sharing too much information about a user’s network via their API.

We have to be thoughtful and consider the consequences of the information we put into our tokens. We should never include data “just in case” and instead wait for specific use cases that we choose to support. Anything else is risky at best and irresponsible at worst.

Grant Types - When and Why

While I jumped straight into scopes and claims, the other most common mistake is related to the specific OAuth grant types or flows. The four grant types - Authorization Code, Implicit, Resource Owner Password, and Client Credential - define how an application can retrieve tokens from your OAuth server and are used in different use cases.

Authorization Code

The Authorization Code flow is the most powerful and most secure by default. When the application redirects the user to the Identity Provider to authenticate, the IdP passes back a short-lived, one-time use authorization code. The application uses the authorization code to retrieve the Access Token.

The important part is twofold: First, by the time the user sees the authorization code, it’s already been consumed and therefore can’t be used again. Second, the Access Token is kept by the application in the backend. Assuming the application is built securely, a malicious user has to find another way to attack it.

Unfortunately, this doesn’t work for client side applications such as many Javascript apps or most mobile apps as the application itself can be attacked or decompiled for sensitive information. Therefore, we need a different approach.

Implicit

The Implicit flow is designed specifically for mobile apps or client side Javascript apps where embedded credentials could be compromised. The mechanics are simple in that the application redirects the user to the Identity Provider to authenticate, the IdP passes back token(s), and the application uses it according to the scopes it has.

Since it’s quite likely that the user could interact with the token(s), it’s important that our use cases reflect that. If we have a banking app, allowing the send_wire_transfers_to_russia scope may be a bad idea unless we have additional factors baked into our authentication process to validate that the right user is using it. The next time you lose your phone, you’ll appreciate that.

As a result, this is often used for OpenID Connect scenarios where a user wants to provide trusted profile information to a third party but not necessarily access or permissions to other systems. Since the underlying concepts are the same and the implementation looks very similar, it’s most of the benefit for the same effort.

Resource Owner Password

Compared to the previous grant types, Resource Owner Password makes me nervous. With both the Authorization Code and Implicit flows, the application redirects the user to the Identity Provider to submit their username and password. As a result, the application never sees their credentials. With the Resource Owner Password flow, the application itself accepts the credentials and submits them on behalf of the user.

If the application is malicious or even just poorly developed, it could store those credentials and compromise the user’s information. Therefore, you should only use this if you’re building applications for your users to interact with your legacy systems. For example, a bank may implement this for an internal employee portal.

But remember: Fundamentally, you’re training users to put their credentials into applications they may not trust which is a bad habit at best and a security risk at all times.

Client Credential

The Client Credential grant type is designed exclusively for backend server to server operations. Think of it as a server’s username and password. Conceptually, it’s not far from how your application connects to other backend systems such as your database or Twilio. The benefit is that your OAuth provider can return configuration information or other details within the token itself.

Finally, since there’s not a user involved, it doesn’t support OpenID Connect.

In Closing

While this entire post has been about OAuth, you’ve probably noticed that I didn’t include any code. The reason for that is simple: The design decisions are still more important.

If your scopes are too broad or your claims include sensitive information or you implement the wrong flow for the environment, the best libraries in the world won’t protect you. Your users’ information will be compromised, your applications will be vulnerable, and your company will suffer the consequences. Alternatively, if you understand the use cases for your software and what your users are trying to accomplish, your software will be better, more secure, and you can limit the “We’re sorry..” emails to your customers.

For Further Reading

From here we can keep going into the protocols, individual libraries, or great books on the subject. If you want to understand how the individual RFCs fit together, check out Aaron Parecki’s book OAuth2.0 Simplified and his accompanying Map of OAuth 2.0 Specs. It’s my go to cheatsheet on links to the key specs and which one covers what. All of the above inspired my guide for Recommended Practices for API Access Management which details good design and development principles for OAuth Clients, Authorization Servers, API gateways, and your applications.