OAuth Is Not Meant For Authentication!

As we work with software development teams to help them apply security principles and practices to their applications, we commonly identify misunderstandings or gaps in the team's understanding regarding security features, APIs, or frameworks they are using. It's important to identify and correct these misunderstandings as early on as possible. When such security elements are misused, systemic security flaws are produced in the application that are difficult to resolve without significant reworking of the code or architecture.


One such example is the use of OAuth. As useful as OAuth is, it must be used for its intended purpose. If we try to make it do things it wasn't designed or intended to do, we get into trouble. Let's clarify the fundamental purpose and use of OAuth and in doing so, clear up a common misunderstanding with it.

OAuth is not meant for authentication. OAuth is for authorization.

Here are a few points demonstrating why:

OAuth has four Grant Types:
  • Authorization Code
  • Implicit
  • Resource Owner Password Credential
  • Client Credentials
For "Authorization Code" and "Implicit" grants the specification doesn't govern the submission of a username or password. It's something totally outside of the scope of OAuth. This is a great warning flag that OAuth is not intended to be used directly for authentication.

"Client Credentials" does have a username and password. It is sent as a Basic Authorization Header (Base64 encoded "username:password"). BUT, it's not a grant used by users. Here's what the specification says:
"Client credentials are used as an authorization grant typically when the client is acting on its own behalf (the client is also the resource owner) or is requesting access to protected resources based on an authorization previously arranged with the authorization server." - https://tools.ietf.org/html/rfc6749#section-1.3.4
An example client could be a third-party API, that a user has granted an "offline" token. That third-party API may make requests without a user interacting with it.

Now for "Resource Owner Password Credentials." Yes, you can use it to login with a username and password, but you probably shouldn't. Not because it's insecure, but because it doesn't scale well and isn't flexible. The specification says:
"The resource owner password credentials (i.e., username and password) can be used directly as an authorization grant to obtain an access token.  The credentials should only be used when there is a high degree of trust between the resource owner and the client (e.g., the client is part of the device operating system or a highly privileged application), and when other authorization grant types are not available (such as an authorization code)."
So why shouldn't you use the Resource Owner Password Credentials grant for authentication? Well, let's start by looking at the login request and response:
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=johndoe&password=A3ddj3w"
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache 
{
"access_token":"2YotnFZFEjr1zCsicMWpAA","token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
You submit a username and password and you get back and access token. The access token can then be used to call an API. Sounds ok, right? Let's add some complexities. First, OAuth is often used in combination with a stateless REST service. There's no session on the server-side. There's just the access token sent by the client, which is often a base 64 encoded set of claims with a signature (like a JWT). With that in mind, what if you need to do multi-factor authentication? What about security questions? What if there are several different ways a user can log in? How do you integrate all those options with the OAuth Resource Owner Password Credentials grant?

One common approach is to make it an API call and have a mobile or web application force you to complete it. But, if the application is stateless and you already have an access token why not just call any other API method directly with that token and ignore the secondary authentication step. It's trivial to bypass in a client-side application (mobile, thick-client, web page). So, that means attackers can bypass that multi-factor system that helps meet compliance and regulatory requirements.

Ok, how about if it's made as part of the login process? Well, that's not really OAuth any more. You have to add fields, add steps, and/or go through more process before issuing an access token. Are you going to write your own custom OAuth client library and server to do it? You might as well write a normal forms based authentication process instead?

OAuth IS NOT FOR AUTHENTICATION!

How do others do it then? Instead, they use the OAuth Authorization Code or Implicit grants and a separate login server (or identity provider) to handle all the authentication and pass back a user with an access token. In fact, that's exactly what the Authorization Code and Implicit grant is for. That identity server can offer as many options and schemes for authenticating users as it wants. The authentication process is centralized and isolated from the applications that rely upon them. When it's done authenticating the user, it passes the user back to the application fully authenticated. With this in mind, you can see that this is exactly what the OAuth Specification Authors had in mind when you read the Introduction section here:  https://tools.ietf.org/html/rfc6749#section-1

This issue seems to come up in assessments more and more often lately. I keep seeing software development teams download a copy of Thinktecture's IdentityServer (a great open source product by the way), and then implement it just for their application using the resource owner password credentials. Then, they later bolt on security questions, finger print scanners, multi-factor authentication, and "remember me" features. As a result, their stateless application has easily bypassable authentication controls that are very time consuming to fix (or they have to compromise on having the API be stateless).

If you are considering implementing OAuth or you already have, reach out to Security PS to help with the design and architecture. You could also watch some of these videos to help avoid common mistakes:

Improving User Acceptance of Account Lockout Responses for Login Processes

The purpose of a login process is to identify a particular individual and validate their identity before granting them access to an application. It's critical that the process only allows the owner of an account to login, and it must prevent an attacker from logging in as another user. This post discusses one aspect of protecting authentication processes: using an account lockout response. And, it specifically focuses on decreasing the frustration users experience as a result of that control.

An account lockout response is a security control developers apply to all of the application's authentication processes to limit the number of times an individual can enter the wrong credentials consecutively. For example, if an attacker incorrectly guesses another user's password five times in a row, the application will disable the user's account and notify the user by email. Organizations must choose an appropriate lockout threshold and choose how accounts are unlocked.

When should an organization use an account lockout response? That's difficult to answer unless a company is compelled to implement the control due to a regulation or compliance requirement. The development team, security team, and marketing or user experience groups really need to discuss the pros and cons of such a process. On one hand, the application will have significantly more resistance to password guessing attacks, protecting users' accounts from being compromised. On the other hand, it may frustrate users, raise customer support costs, or even drive customers away from using the application. If an account lockout response is implemented (which Security PS generally encourages), it must be carefully designed to increase user acceptance.

One of the frustrations users experience related to account lockout responses is that they may not know their password (or sometimes their username) and they lockout their account accidentally. On top of that, the user doesn't know their account is locked out. This occurs because the application cannot display notifications on the login page that the account is locked out. If it did, the process would inform an attacker that a particular username is valid resulting in a username harvesting vulnerability. This is one of the key challenges to solve in order to increase user acceptance of the account lockout response control.

To address the notification challenge, Security PS recommends several user experience improvements that don't expose the application to additional risk. First, the application can email the user when a failed login attempt occurs. Additionally, if the account is locked out, the application can immediately email the user instructions for unlocking the account. These notifications do not cause username harvesting vulnerabilities, because only the account owner will receive those email notifications not the attacker.

Email notifications are helpful, but what if the user doesn't check their email while using the application? They can still get frustrated easily. So, developers should consider sending SMS notifications when a user's account is locked out or potentially before the lockout occurs. The message can be short, direct, and can point the user to their emailed instructions for unlocking their account or resetting their password. The hope is that the user receives this notification before getting frustrated that they can't login.

Finally, the messaging in the application itself can remind users that a lockout response is present and that they can check their email if they believe their account is locked out. This messaging can be displayed all the time or after a specific number of failed attempts per session. Key here is that this is not a specific number of failed attempts per username or account, but per session. Otherwise, username harvesting vulnerabilities are introduced.

Authentication processes, especially complex, multi-step, multi-credential authentication processes are difficult to get correct. It's easy to introduce vulnerabilities in the user creation/registration step, forgot username/password step, and login process itself. If you are in the process of designing an authentication process, whether it's using an OAuth2, OpenID Connect, or custom forms based authentication, contact Security PS to have a partner come along side you and help ensure the design and implementation are secure.