Reviewing OAuth Security
When talking to customers about OAuth and Identity I oftentimes come across a few misconceptions around how standardized and consistent OAuth is which has led to blind spots when reviewing potential security issues.
First things first, OAuth is a specification, not a standard, what this means is it is up to an individual implementation for which parts of the specification are followed, and how they are followed. This has led to organic differences in how OAuth functions between different providers. And while all implementations tend to have a few common elements, you are just as likely to run into cases that are unique or modifications from the baseline specification.
Second, OAuth is Delegation not Authorization (even though most applications will say Login/Authorize as end users are used to those terms). This tends to trip people up a lot. OAuth is a way for you to delegate an application to do something on your behalf. When the application is delegated, it can appear to be authorization of you as an end-user. But that authorization happens in the system you sign in to, not the one that is receiving the OAuth token. The other part of this is the receiving application is now your delegate. Making it so there is now an application that can say it's you. Because of this, as a best practice, you should always ensure that scopes are not just accepted but enforced in any application using OAuth. To ensure that the delegated rights are following least privilege ideals, and not allowing for escalation beyond what the application needs.
Generally, all implementations have one, or more, of these variations of the basics implemented:
3 Legged Authorization
This is the traditional method of OAuth.
- User attempts to perform an action against an application
- Application redirects to the OAuth provider with an Application Identifier like Client ID
- User logs in
- [Optional] User is prompted to authorize the application
- OAuth provider redirects to the initial requesting application
- Requesting application completes the token request with a POST against the OAuth provider to acknowledge receipt and get token details with an Application Secret like Client Secret
Headless Authorization
This is a variation of 2 legged auth, but instead of interactive authorization by the end-user in the browser the user authorizes the application through a separate device. Typically the user has to input a device code, or an MFA acknowledgment to authorize the requesting application. The application can then complete the validation and acknowledgment steps for generating a token. Like 2 legged auth, typically the requesting application gets a renewable token so end users don’t have to perform this step multiple times.
2 Legged Authorization
This is a form of delegated authorization. The requesting application tries to perform an action against a secondary application. A logged in user authorizes the requesting application to perform those functions on its behalf. Then the normal token validation and acknowledgment steps are followed. With few exceptions, the requesting application will have a persistent renewal token so the user doesn’t need to perform these steps multiple times.
0 Trust Authorization
0 Trust Auth is common with JWT based OAuth implementations like that used by Atlassian Cloud. It adds an additional two steps to the 3 legged auth route. With the first step being the creation of a one time use clientid/clientsecret for this specific token request session. This helps protects against MITM attacks by establishing trust between the OAuth provider and the source application. Then, once the normal 3 legged steps are performed, a JWT POST is performed using the one time use clientid/clientsecret.\
Common Differences Between Implementations
So, before even getting into the weeds of the specific capabilities of each basic type of implementation you can see theirs a lot of variabilities. Depending on the implementation of the OAuth provider you’ll find numerous possible differences. I’ll list some of the most common variations below, but in short, every implementation is unique and should never be considered to have all of the features and functions to manage security that you may want to assume to be in place.
Groups/Scope/Roles
Many OAuth providers have some mechanism for specifying what you want access to. But not all implementations have this. The naming convention for this function, and when it’s performed varies. And many implementations DO NOT enforce the scope boundaries defined leading to privilege escalation. So make sure to test for enforcement.
ClientID/ClientSecret
While something is always sent from the requesting app to the provider. What is sent and the level of protection provided by what is sent varies significantly. Some services use a certificate, others use a plain text message, while most use a server side generated code. If you’re using JWT over OAuth it can be a combination of terms used. With a certificate between provider -> app, and then a one time use code or a persistent message for negotiating the token. In short, while Client ID and Client Secret are common, they are not an absolute.
Forceful Token Expiration
Very few providers implement a method for invalidating tokens for a specific application or for all open tokens
Renewable Tokens
The majority of providers have an expiration time for a token, and many have a renewal token to be sent after the initial token has expired to continue communication between the app and the provider. However, not all do. So it should not be assumed that this exists.
Allowed Requestors
I’ve heard this at times called ‘Redirect URL’ as the name varies depending on the implementation. The Allowed Requestors list is a set of IP’s and DNS names for the allowed requestors to try and authenticate using a provider. However, not all implementations have this implemented. And not all implementations enforce this. So it’s important to check whether the allowed requestors list is actually enforced or not. Almost no implementation has this completely enforced. You can take the initial response code sent back from the OAuth provider and POST it back to the provider from any system for example (this opens the door to MITM attacks to create the OAuth session directly and re-routing future requests from the client to the application through themselves).
Redirect URL
The redirect URL is where to send users back to the OAuth provider. Typically application path/login or something to that effect. Many providers just take the original requesting URL that started the OAuth process and put it here as well.
Hopefully, this clears up some potential blind spots when reviewing the security of authorization paths when using OAuth.