OAuth 2.0 in R

April 2019 · 7 minute read

Many APIs require some form of authentication. A very common form used with many cloud providers and commercial APIs is OAuth 2.0. In this post, I want to give you an introduction to how OAuth 2.0 works and use it to authenticate with Microsoft Azure services.

OAuth 2.0 - Overview

The OAuth 2.0 specification is not what you would commonly describe as ‘easy to understand’. Eran Hammer, the former lead author for the OAuth 2.0 project actually resigned and removed his name from the specification. He even wrote a Medium post titled ‘OAuth 2.0 and the Road to Hell’. His core concern is that OAuth 2.0 might be too complex for most developers to implement securely. However OAuth 2.0 is more or less the de facto authentication standard and used by Google, Facebook and Microsoft to secure access to their APIs, so we have to learn to work with it to a certain extend.

Note that the authorization server and the resource server do not need to be distinct servers. In practice, the authorization request is not made directly to the resource owner, but handled by the authorization server. The client gets an authorization grant which it can use to get an access token to access protected resources.

There are four different authorization grant types:

authorization code,

implicit,

resource owner password credentials and

client credentials

It is possible to define additional custom grant types as well. Let’s look at them in more detail:

Authorization Code

The client redirects the resource owner to the authorization server via its user agent (usually a browser). The authorization server then redirects the resource owner back to the client with the authorization code.

response_mode: specifies how the token should be send back to the client

response_type: with the value code.

scope: missing in this case, but tells us which authorization we want (space delimited list of scopes, but ignored in Azure)

state: optional, but highly recommended to help mitigate CSRF attacks. Can be an arbitrary string. This option can also be used to put the user back to the page from where the login was made.

redirect_uri: optional, this is the URI where we get the return from the authorization server. If not set, the default is used. Note that the redirect_uri ‘http://localhost:3000’ has been url-encoded to ‘http%3A%2F%2Flocalhost%3A3000’.

Using authorization code grant is quite involved and in some cases a simpler authentication is more appropriate:

Implicit

The implicit grant is an authorization flow optimized for clients implemented in a browser or any app that cannot protect a client secret. The implicit grant flow is the same as the authorization grant flow above, but instead of getting an authorization code first that is exchanged for an access token after presenting the client secret with the authorization code, the authorization server returns an access token immediately.

Note that apparently industry best practices now recommend to use the authorization code flow without a client secret instead of implicit grant flow (see here and here).

Resource Owner Password Credentials

In this case we use the resource owner credentials directly to login to a given service. Since the app obviously collects password and user name from resource owner, this grant flow should only be used when the application is trusted to a very high degree by the resource owner. However, credentials do not need to be stored as the client gets an access token from the authentication server.

Client Credentials

When the authorization scope is limited to the resources owned by the client, the client can use its client id and client secret to request an access token. This grant flow is more or less the same as the resource owner password credentials flow, except that the client is under control of the protected resources.

Access and Refresh Tokens

Access tokens allow access to protected resources and are usually short lived to minimize harm in case they are leaked. Refresh tokens on the other hand are usually long lived and can be used to request new access tokens after the old ones have expired.

The client_id in the example above is from the Azure CLI client. Also note that compared to the example we had earlier we are accessing /common/ instead of /<tenant-id>/. Pasting the above URL into your browser will return a redirect url of the following form:

You should now be redirected to a browser window where you can sign-in to your Azure account. There is also a library called AzureAuth as part of the cloudyR project, but I like that we can cover the entire flow with httr and no further dependencies.