OAuth 2 Client

We’ve taken a close look at OAuth 1 clients; this chapter will focus on the OAuth 2 client. OAuth 2 provides solutions for the same type of authorization problems OAuth 1 solves, it just does it in a slightly different manner. OAuth 2 is really more of a framework than a single protocol.

There are times when we’ll want to pull user content or resources from a third-party site into our application. For reasons described earlier, we don’t want to have to manage, store, or know our user’s credentials; nor do we want to have provide those credentials to a third-party service whenever we want their content. Doing this puts an unreasonable responsibility on us to ensure we’re the only other people who know these user name and password combinations.

In addition, our users are not going to be happy if they have to change the credentials for a single service on more than one site. Happy, well protected users are going to ensure they continue to use our application and aren’t scared away because of security or inconvenience.

Authorization Flow

In OAuth 2 we still rely on the individual external services to be primarily responsible for user name and password security. The process differs a little bit from OAuth 1, but still requires an exchange between an application and the service. In OAuth 2 we eliminate the need for signatures, which are one of the more difficult concepts in OAuth 1. Instead we swap out the use of signatures and instead use encrypted information over SSL. Without SSL, we don’t have OAuth 2, so keep that in mind when considering implementing OAuth 2. Figure 6.1 illustrates the basic workflow involved in OAuth 2.0.

Figure 6.1
Figure 6.1

The first thing we need to do is create an authorization request and send it to the server. This is generally a link we can redirect our users to which allows them to authenticate with the third-party application and allows our application to interact with their account. If this is successful, the application will send an Authorization Grant back to us. This tells us the user authenticated successfully and we can proceed to the next step. Once we have a successful authentication and authorization, we’ll need to exchange that grant for an access token. The access token identifies us to the third party server, so it’s important for these steps to flow together to ensure we’re being identified correctly. Once we have an access token (which can expire very quickly when compared to OAuth 1 access tokens), we can provide it in our requests to retrieve information from the third-party service.

Another change introduced is the idea of a refresh token. A refresh token is not a required part of OAuth 2, which means you should check to determine whether the service you are integrating with offers them. The idea behind the refresh token is if credentials expire, the application should alert you the tokens you provided are not valid (via an appropriate response and status code). At that point, a request providing the refresh token can be made in order to request a new access token. The only use for a refresh token is to request a new token, so it’s part of the authorization and not a part of the retrieval, removal, or modification of resources. To reiterate, this is not a required piece of OAuth 2, so verify the service you wish to use offers refresh tokens. If it does not, you’ll have to go through the normal authorization process again in order to obtain a new token when an access token expires.

There’s really not much else to it, the crux of the authorization framework is an exchange takes place and consistently identifies us correctly. Going forward, we need to ensure we provide our proof of identification—the access token—in a way the server is expecting so it knows how to authorize us when dealing with protected content.

Before you start thinking, “Wow that’s it? This is going to be a really short chapter”, there are a number of new concepts we’re going to have to comprehend in order to fully understand how this all works together.

Scopes

If you’re like me, you’ve always wondered why OAuth 1 was so difficult to understand, yet did very little to help solve the always tricky authorization problem. Authorization, in short, is making sure your users can see what they’re allowed to see and not allowing unauthorized users to see the same protected content. Obviously, protected content and how it is defined differs from application to application, but in short, someone who isn’t me or a person I’ve authorized (by friending, following, etc) shouldn’t be able to see my files, likes, pictures, and so on. Due to the variant nature of applications, it would be very difficult to come up with a universal access control system which would work for everyone. It would be so difficult and the implications of failure could be so disastrous, it’s really not even worth attempting.

OAuth 2 can, however, provide more control over what is available to an authenticated user in a given application. I’m sure we’ve all seen an authorization page which asks us if we want to connect to this application, but if you look closely it will also tell you what the application has access to. Consider Twitter as an example, you have read or read-write access across the board. Your application can either read all the protected resources or read and create content in all the protected resources. This might be acceptable for your application, but how would we handle restricting users from accessing direct messages? Long story short, we can’t.

Scopes can allow the application to determine what specific resources the access token is authorized to use, and how they are authorized to use them. Keep in mind, the application is still responsible for building the mechanisms to manage these scopes, so it’s still something you would have to consider when using or building with OAuth 2. Basically, we’re exchanging the model of “read and/or write everything” for a more specific model which asks, “what do you want to have read and/or write access to?”. As a prime example, take a look at the GitHub API; they require scopes when requesting access tokens and have a pretty detailed list of the resources you can manage. GitHub provides the following scopes:

  • user
  • user:email
  • user:follow
  • public_repo
  • repo
  • repo_deployment,
  • repo:status
  • delete_repo
  • read:org
  • write:org
  • read:public_key
  • write:public_key

This isn’t the complete list; it can be found at GitHub API Scopes1.

From the few I chose to detail, you can see a much finer level of access control managed with the tokens. It’s very likely the management of public keys or the ability to delete repositories might not be something your application really wants users to do. By providing a list of scopes when you make your authorization request, you can effectively limit the use of the API to perform those actions. In a sense, it provides a little bit more clarity to the authorization flow and how it can be managed on the server.

Scopes are only used in the process where we are retrieving tokens and can (but don’t have to) be used in the generation of the actual access token. Any calls which made to protected resources do not require those scopes to be passed along or maintained from call to call. They become strictly part of the authorization and authentication process. The service provider will verify the scopes allowed for any given access token.

We’ve taken a cursory look at how the authentication flow works, but as you might suspect, there’s more to it than that. We’re starting to approach usability, but it’s important to understand the specifics on how we retrieve our access tokens, what implications it might have, and–if we have a choice–when to use which type of grant. We’re going to be covering that next.

Grants

Up to this point, we’ve covered this whole authentication flow process from a really basic standpoint. While it’s good to understand the basic flow of things, it’s equally important to understand the specific mechanisms which make this flow work. In this section, we’re going to cover the grants we can use to retrieve our access token. If you recall from he OAuth 1 Client chapter, we were given an access token and an access secret. We needed both to build the signature. In this model, we’re only going to be retrieving one token, the idea of the access secret goes away. Because of this, don’t be surprised if you are unable to see the actual access token in the third party application settings. This token should be be treated with the same sensitivity as a password and not be shared with the world at large.

Authorization Code Grant

The authorization code grant can be used to obtain both access tokens and refresh tokens. This grant is what most people think of when they think of OAuth because it requires a callback and returns a token once the process is completed. This grant requires the user to authenticate with the third-party service directly before continuing. Once the token is retrieved, it can be stored by the calling application and used to make future requests as long as the token is valid.

To break down how this grant works in practice, let’s step through the complete process. The third-party service provides an authorization endpoint and the user is directed there. The endpoint, according to the OAuth 2 RFC2, must have a response type which is set to code and a client ID. The redirect_uri option is regarded as optional documentation for the service you are trying to use and will often provide more information about the callback. If your service uses scopes, this is the step where you’d provide them. If there are multiple scopes, as in our GitHub example, they can be provided as a comma-delimited list. Finally, there is an option called state, which is regarded as recommended because it acts as a protection against Cross-Site Request Forgery attacks. The state is passed back by the authorization server after the request is made. This acts as a way to ensure the request wasn’t altered while en route. Here’s an example of how we’d build a request for GitHub, assuming we’d like our key to have scope for user:follow, public_repo, and read:org.

https://github.com/login/oauth/authorize?client_id=CLIENT_ID
&response_type=code&scope=user:follow,public_repo,read:org
&redirect_uri=http://example.com/callback&state=bced12345ace

When a user visits this link from your application, completes his or her login, and gives your application access to his or her account, your application will receive a temporary code. This is generally done as a redirect to the callback with a code in the query string. This temporary code will be used as a required parameter to obtain an access token. It’s short-lived, so you’ll have to move the process forward within a reasonable amount of time.

Once you obtain your temporary code, you’ll have to make a POST request to the access token endpoint. The body of that POST request must contain the following fields: grant_type, code, redirect_uri, and client_id. The grant type you would use for the Authorization Code grant is authorization_code. The code is the temporary value you retrieved from the authorization step. If the redirect_uri was provided in the authorization step, it must be identical to the callback in the first request; it is a required field during this step. Finally, the client_id, which helps identify your application, must be sent over as well. If this is sent correctly, you will be redirected to the callback with an access token. If the service provides a refresh token, it can also be provided at this point. Now, you’ll have an access token and be able to authenticate and authorize requests to protected resources on the third-party application.

Implicit Grant

The Implicit Grant is a little bit different than the Authorization Code Grant. The process starts out the same, where the user is directed to an authorization endpoint where they will login with their credentials. Once authenticated, the user will be redirected, but the access token is provided on the first redirection. There is no temporary code exchange required to retrieve the access token.

While there are fewer steps in this process, it should generally only be used in situations where the access token cannot be stored securely. This token should be treated as public knowledge, and it’s advisable to not allow any overly destructive permissions to be carried out via this token. The Implicit Grant also doesn’t allow for refresh tokens to be distributed, since they would be potentially publicly available as well. In order to retrieve new tokens, the authorization process must be completed again.

Resource Owner Password Credentials Grant

In the last two grants, we’ve seen how we’ve been redirected to the third-party website to authenticate and authorize the application. This third kind of grant does not utilize redirection at all and is therefore pretty scary to consider using. In fact, the RFC states it should only be used when there isn’t a viable alternative. In this scenario a POST request is made to the authorization server and the following fields must be present in the request: grant_type set to 'password', username, and password. Additionally, scopes can be set the same way as described earlier in the chapter. The authorization server is required to only store the sent credentials until an access token is provided, at which point it cannot store them. Keep in mind, this requirement is only in place to remain OAuth 2 compliant, there is no actual mechanism forcing the server to remove your credentials.

You can probably see how scary this is, just based on the fact you are sending your username and password. The specification requires this POST request to be sent over with Transport Layer Security (TLS). But keep in mind this sends your user’s password directly in the request.

I just want to take another opportunity to be cautious when considering this grant. The reason is simple: tokens are generally short-lived and easily revoked. If a token is compromised, it can be invalidated very quickly. When a password is compromised, a user is open to all the same issues as a compromised token. In addition, the attacker now has access to the user’s account on the third-party service. This could allow for passwords to be changed and accounts to be hi-jacked. Only use this grant in a situation where there is an extremely high level of trust and even then only if you absolutely must.

While it can be dangerous, it is a valid grant type in OAuth 2 and it’s important to understand some of the concerns associated with using it. With any application, it’s very important to follow secure password practices in order to maintain your users’ online security. Ideally, users would have longer passwords with varying character types (letters, symbols, numbers, etc.) and would not use the same password on more than one application. Any problem posed by a password being leaked out can be magnified if one password allows access to other online accounts.

Client Credential Grant

The last type of grant we’ll be covering is the Client Credential Grant. Similar to the previous kind of grant, it requires the sending over of a different set of credentials. As with the previous grant, this should only be used by clients who are not public facing. When implementing this grant, the client_id and client_secret are used as opposed to the resource owner’s credentials. The client_id and client_secret are the values which are used to identify the application, so it goes without saying, these values need to be protected from the outside world. They can be used for a service having no outside access, a private network for example, and where the ID and secret can be shared with little to no risk.

To use this grant, a request has to be made to the token endpoint with a parameter for the grant_type set to 'client_credentials' and, optionally, a list of scopes. To send the ID and secret along, you can use an Authorization header which utilizes Basic authentication. Basic authentication is created when the identifier and secret are combined and separated by a colon. So for example if my client_id is '123' and my client_secret is 'abc', you would start with the string '123:abc'. This value is then base64 encoded and added to the authorization header. If those values are authenticated, then an access token is returned. Below is a value of what the Basic Authorization header would look like, with a place holder for the encoded value.

Authorization: Basic <base64 encoded identifier:secret string>

It’s very simple; of course, since they have to be authenticated they have to be encoded and not hashed. This means anyone with access to the string can base64 decode it and get access to the original information. PHP provides a function to do this called, base64_decode. For this reason, I’d stress again you should only use this in confidential situations.

Presenting the Access Token

Obtaining the access token is the most involved part of this process. Unlike OAuth 1, there isn’t a lot we have to do to identify ourselves to protected resources once we have it. The simplicity of OAuth 2 makes it a bit easier to use on a request to request basis. The trade off is the access tokens tend to have a much shorter life than the access credentials in OAuth 1.

The service will return a token and token type upon the successful request for access tokens. It’s important to check with the service you are using to see how the service requires the token to be presented. Some services state you should put them in the URL, while others have different token types which are required for use in the Authorization header. There will be more on this in the OAuth 2 implementation chapter. For example, GitHub documentation says to use the following:

Authorization: token <token>

Other examples replace the word token with bearer and for an example of a service which states to use it as a query parameter, we can take a look at Foursquare:

https://api.foursquare.com/v2/users/self/checkins          
?oauth_token=ACCESS_TOKEN

There’s no single way to present the token in a request. The important aspect is that it’s presented in a way the resource server can access and identify the token. Always be sure to check the documentation for any differences in how to present your token. Also in addition to the examples listed above, it’s possible there are other methods for presenting the tokens which are specific to a particular service.


  1. https://developer.github.com/v3/oauth/#scopes

  2. RFC 6749, https://tools.ietf.org/html/rfc6749

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.161.116