REST API Security – OAuth2 ROPC vs Basic Auth for Public APIs

httpsoauthrest

The specific use case I'm interested in here is authenticating REST clients against publicly-available server endpoints (such as a public REST API).

The simplest solution here is Basic Auth. But I often hear OAuth2 touted as a superior auth solution in almost all circumstances.

The thing is, the only OAuth2 grant type that is feasible for a REST client authenticating against a REST server is Resource Owner Password Credentials (ROPC), because Code Grants and Implicit Grants require a UI/webpage (hosted by the Auth Server) for the user to login to and manually authorize the client app.

The way ROPC works is, by sending the resource owner's username/password, and the client ID as query string params?!? This is even less secure (IMHO) then Basic Auth, which at least base-64 encodes the credentials and sends them inside a header which can be encrypted by TLS!

So I ask: in the context of public REST APIs, is OAuth2 ROPC really any better than Basic Auth? What is more secure than OAuth2 ROPC?


Update

I just read this excellent article which explains Amazon's non-OAuth2 based REST security for AWS. It is essentially a private key-based solution where hashes of each REST request are generated and sent as sidecars along-side the normal (un-encrypted) request. Only the client and the server know the private key, so when the server receives the request (again, containing the normal request + the hashed request), the server looks up the client's private key, applies the same hash to the normal request, and then compares the two hashes.

This sounds way more complicated, complex and secure than OAuth2's ROPC! Unless I'm missing something major here, OAuth2 ROPC is just sending client_id, username and password as query string params…totally and utterly unsecure! This HMAC/hashed-based solution seems to be much more impressive and secure.

The thing is, even the author of that article goes on to say:

You [will] also slowly realize and accept that at some point you will have to implement OAuth…

Ba-ba-bwhat?!?! If OAuth2 is less secure than this clever HMAC/hash-based solution, why does the author of this article feel OAuth needs to be embraced at some point. I'm so confused.

Best Answer

The answer to your question can be at the code level, protocol level or architecture level. I will attempt to summarize here most of the protocol level issues since that is usually critical in pros and cons analysis. Keep in mind that OAuth2 is much more than Resource Owner Password Credentials which, according to the specification, exists for "legacy or migration reasons", is considered "higher risk than other grant types" and the specification explicitly states that the clients and authorization servers "SHOULD minimize use of this grant type and utilize other grant types whenever possible".

There are still many advantages of using ROPC over basic authentication but before we get into that, let's understand the basic protocol difference between OAuth2 and basic authentication. Please bear with me as I explain these and will come to ROPC later.

User authentication flows

There are four roles defined in OAuth2 specification. With examples, they are:

  1. Resource owner: The user who has access to some resource, e.g. in your case, different users may have different access level to the REST API;
  2. The client: usually the application the user is using, and needs access to the resource to provide services to the user;
  3. Resource server: the REST API in your case; and
  4. Authorization server: the server to which user's credentials are presented and which will authenticate the user.

When a client application runs, it is granted access to the resources based on the user. If a user has administrator privileges, the resources and operations available to the user in REST API may be far more than a user without administrator privileges.

OAuth2 also allows the possibility of using a single authorization server with multiple clients and for multiple resources. As an example, a resource server can accept user's authentication with Facebook (which can act as authorization server in such a case). So when the user runs an application (i.e. the client), it sends the user to Facebook. User types their credentials in Facebook, and the client gets back a "token" which it can present to the resource server. Resource server looks at the token and accepts it after verifying that Facebook in fact issued it and allow the user access to the resource. In this case, the client never sees user's credentials (i.e. their Facebook credentials).

But let's say you are managing your user's identities (and have an authorization server) instead of Facebook, which grants tokens to your client already. Now, let's say you also have a partner and you want to allow their application (i.e. client) to access your REST API. With basic authentication (or even ROPC), the user will provide credentials to that client which will send it to the authorization server. Authorization server will then provide a token that can be used by the client to access the resources. Unfortunately, this means that user's credentials are now visible to that client too. However, you would not want a partner's application (who could be external to your organization) to even know a user's password. That's a security issue now. In order to achieve that goal, you would want to use another flow (such as the authorization code grant) in which the user directly provides credentials to the authorization server.

Thus, with OAuth2, one would ideally not use ROPC in such cases rather use a different one, such as authorization code flow. This protects any application from knowing the user's credentials which are presented only to the authorization server. Thus, a user's credentials are not leaked. The same issues apply with basic authentication, but in the next section, I will explain how ROPC is still better because the user's credentials still do not need to be stored by the client in ROPC for persistent access by the clients.

Note that when the user goes to the authorization server, the authorization server can also ask user to confirm that they want to allow the client to access the resources on their behalf or not. That is why it is called the authorization server because the process of authorizing a client to access resources is entailed in the process. If the user does not authorize the client, it will not get access to the resources. Likewise, if the user themselves do not have access to the resources, the authorization server can still deny access and not issue a token.

In basic authentication, even the authorization server and resource server are combined into a single entity. Thus, the resource server wants to authorize the user, so asks the credentials from client. The client furnishes those credentials which are used by the resource server to authenticate the user. This means that multiple resource servers will essentially be requiring credentials from the user.

Token issuance

The clients get tokens from authorization server, keep them around and use those to access the resources (more details on tokens themselves below). The clients never know the user's password (in flows other than ROPC) and do not need to store it. In ROPC, even though the clients do know the user's password, they still do not need to store it because they use these tokens to access resources. By contrast, in basic authentication, if a client does not want to have user to provide credentials in every session, then the client has to store the user's password so they can furnish it the next time around. This is a major drawback to using basic authentication unless the client is only a web application in which case, cookies can address some of these concerns. With native applications, that's usually not an option.

There is another aspect of OAuth2 which is entailed in how tokens are issued and they work. When a user furnishes credentials to the authorization server (even in ROPC), the authorization server can give one or more of the two types of tokens: 1) access token, and 2) refresh token.

Access tokens are sent to the resource server which will grant access to the resources after validating it, and usually they have a short lifetime, e.g. 1hr. Refresh tokens are sent to the authorization server by the client to get another access token when it expires, and usually have a large lifetime (e.g. a few days to months or even years).

When the client provides the access token to the resource server, it looks at the token and after validating, looks inside the token to determine whether to allow access or not. As long as access token is valid, the client can keep using it. Let's say the user closes the application and starts it the next day, and the access token is expired. Now the client will make a call to the authorization server and present the refresh token assuming it's not expired. Authorization server, since it already issued the token, verifies it and can determine that the user does not need to provide the credentials again and thus gives another access token to the client. The client now has access to the resource server again. This is how typically the client applications for Facebook and Twitter ask for credentials one time and then do not require the user to provide credentials again. These applications never need to know the users credentials and yet can access resources every time user starts the application.

Now the user can go into the authorization server (e.g. in their Facebook user profile), change password without impacting any client applications. They will all continue to function properly. If the user loses a device on which they already had an application with refresh tokens, they can tell authorization server (e.g. Facebook) to "log them out" of those applications which the authorization server (i.e. Facebook) will accomplish by not honoring any existing refresh tokens and forcing the user to provide credentials again when they try to access resources through those applications.

JWT is simply the token format that is usually used with OAuth2 and OpenID Connect. The methods of signing the token and validating it is also standardized with libraries available for those instead of every resource server implementing yet another solution. Thus, the advantage lies in reusability of code that has been vetted and continues to be supported.

Security implications

Basic authentication will be weaker when any of the above scenarios are in the picture. There is also an extensive threat model for OAuth2 available for developers who can use the suggestions in it to avoid common vulnerabilities in their implementations. If you go through the threat model, you will see that many implementation related vulnerabilities (such as open redirector and CSRF) are also covered in it. I did not go through comparison of those against basic authentication in this response.

The last major advantage of OAuth2 is that the protocol is standardized and multiple authorization servers, clients and resource servers honor it. Numerous libraries are available to developers, which are maintained so as security issues are found in implementations, the libraries are updated while allowing interoperability.

Conclusion

If you are writing a new application, IMO, the ideal case would be to avoid both the basic authentication and ROPC because of the issues inherent in them. However, each application has different needs, timelines, developer proficiency etc. so the decision is case-by-case. But even if you did not have any more need than basic authentication, by choosing it, you could lock yourself into an architecture that may not be easy to extend (e.g. if you have multiple servers in the future, you would not necessarily want to have the user provide credentials to each one of them rather just provide to authorization server once, which can hand out tokens, etc.)

Note that I did not address your comment about how the credentials are sent over the wire because those can be secured using TLS or a similar protocol, or proof of possession etc. As someone already suggested, base 64 encoding is 0 security, please do not be deluded by that. The differences mentioned above are usually at the architectural level and thus that is where I focused because architecture is the hardest to change once implemented.

Azure Active Directory B2C Basic, a service which I work on and was recently released for public preview, allows third party application to use AAD as the authorization server with interoperability with social IDPs (such as Facebook, Google, etc.). It also allows users to create their own accounts instead of using social IDPs and those can later be used for authentication purposes. There are a few other services also like that (e.g. another one I know of is auth0) which can be used by developers to completely outsource authentication and user management for their applications and resources. The same protocols characteristics that I mentioned above is used by developers to decouple authorization server (AAD), a resource (e.g. their REST APIs), the client (e.g. their mobile applications), and users. I hope this explanation helps somewhat.