What grant type to choose and why: Demystifying OAuth 2.0 grant types

Atif Shafi
Geek Culture
Published in
7 min readJun 14, 2021

--

When a user logs into a web application, the app obtains an ‘access token’ to fetch data from the server. Browser (client) would use this token, on behalf of the user, to navigate to different pages of a web application, make requests and so on. So this token works as an identifier for the user.

But exactly how is the token collected? This article will talk about some of the work flows which are followed in the industry. Note that the article will not talk about the origin of OAuth 2.0 and how it came to be. It is targeted for readers who are already familiar with the basics of REST APIs, providing them an overview of typical workflows of grant types used in requests.

When we think about users getting authenticated (and acquiring access token) in web apps, the first thing we would probably think of is the use of ‘username/password’ to log in.

Let’s discuss how that workflow might work.

In this approach, the resource owner simply passes its credentials to the application directly. That is, the application is highly trusted to handle such sensitive data.

In the diagram above —

  • Resource Owner: The user, someone who’s trying to log in.
  • Application: Web Application
  • Authorization Server: Dedicated server that web app uses to authenticate users
  • Resource Server: Where user’s data is stored for the user

Resource owner provides its credentials to the application, then, the application sends them to the authorization server for validation. After validating user’s credentials, auth server issues an access token and sends it back to the client. Client would use this token to access resources from the resource server whenever it needs to (as requested by the user, of course).

This flow of acquiring access token is using ‘Resource Owner Password’ Grant Type.

Fairly simple, but with a caveat, trusting the application to faithfully handle the sensitive data. Generally, this grant type is used via back channels (server-server communication), as opposed to front channels (browser-server communication) for security reasons. That is, requests in the flow take place using back-end services and not the browser.

What if you don’t have any users and you want to have some sort of authentication process for the incoming requests?

In this approach, apps often use services that call APIs without users.

Here, auth server issues access token for requests coming from the application without validating any ‘user/password’. So without users, how does the auth server know the validity of the incoming requests? Where do we use this grant type and why?

Let’s take a look at step # 1. The application makes a request to the auth server with Client ID and Client Secret.

Client ID is a public identifier for apps. When, as a developer, you want to access a third-party application to use their resources (accessing APIs) for an app you are developing, you would need to register your app with the third-party application. For example, if you want use Google Maps APIs for the web app you are designing, your app needs to be registered with Google, with a Client ID.

Client Secret is a private identifier for apps. It is stored on server side securely and not available to public. This is optionally used to register with a third-party app for enhanced security. More on this later.

The idea is, auth server would validate the ‘client credentials’ — Client ID/Client Secret, attached with the incoming requests and issue an access token accordingly.

So who’s this for and when is it secure? In general, this flow is targeted for clients who need access to protected resources that are not owned by the users (persons). To ensure security, it is often used on back channels. For example, in a microservice based app, one service is talking to another service (machine to machine communication) on the backend where there’s no user involved and the environment is secured.

This flow of acquiring access token is using ‘Client Credentials’ Grant Type.

Both of the grant types discussed so far are well suited for back channel use cases, where you don’t want to send the request directly from your browser to the auth server, but would rather like your back-end to do the dirty work. But what if there’s no back channel? What if it’s a pure javascript app based on React or Angular which doesn’t have any back-end (a static page)? Perhaps there is some back-end APIs it’s calling but it doesn’t have any back-end to render a page or to run some code.

In those cases, the only option is to use front channel.

In this approach, transaction takes places using front channel.

The first step is to access the application on a browser. The app will prompt the user for their username and password. The user will also see a list of permissions for the app. Based on the permissions granted by the user, the app can access resources on their behalf.

You might be wondering, this is new! In ‘‘Resource Owner Password’ grant type’ (where we similarly provided username/password), we didn’t see any such prompt. This is because for that grant type, we are trusting the app by providing user credentials directly to the app and granting all access by default.

Here, however, note that the resource owner provides its credentials directly to the auth server, not the app (step # 3). What does that mean?

We want our app users to talk to an auth server directly and we don’t want to handle sensitive information. A real life example (of step # 3) would be signing in to various web apps using services like Google or Facebook.

Say you want your web app users to log in by using their gmail account. First step would be to go to Google’s auth server and create Client ID and Client Secret for the app. Once the app is registered with Google’s auth server, it will identify your app as a ‘trusted app’. However, for this flow, Client Secret doesn’t get used since the flow is only meant for front channel use.

Once the user grants appropriate permissions (step # 3), the auth server will generate a token and return it to the app (step # 4).

So how’s the token returned? Is it really secure since everything is on front channel? How does Google know where to redirect after authentication?

Let’s take a look at the following diagram for a better understanding.

When the client sends a request to Google for the ‘sign in’ page (step # 3), it also sends ‘Redirect URI’, ‘Response type’, ‘Scope’ with the request as query parameters.

  • ‘Redirect URI’ tells the auth server where to go after validating the user
  • ‘Scope’ defines the permissions granted by the user.
  • ‘Response type’ tells auth server to return the access token

Once auth server validates the credentials, it generates access token (since response type is set to ‘token’) and returns it to the provided callback URI. Note that the token exchange is taking place using front channel and is public.

This can easily compromise an access token (access tokens should be considered as sensitive data since it can be used to access sensitive resources). However, for single page applications, this flow can be implemented as long as we are aware of the security risks.

This flow of acquiring access token is using ‘implicit’ Grant Type.

Now, let’s talk about the one which is actually prominently used in many web applications today.

Implicit grant type introduced us to the idea of how an external (third-party) auth server can be used to log in. But as we found out, it’s not entirely secure and tokens can easily extracted from the browser.

The big issue of implicit grant type was using only front channel to exchange tokens. This flow will make the best use of both, front channel, and back channel.

In this approach, both front channel and back channel is utilized to provide enhanced security.

The first 3 steps of this flow is similar to implicit grant type barring one key difference. During step # 3, ‘Response type’ is set to ‘code’ instead of ‘token’, to return something called ‘auth code’. What is that? Well, it’s a code used by the client to get access token via back channel.

In step # 5 and 6, the token exchange takes place when the client grabs that code and makes a request from the back-end server to the auth server. Once the auth server validates the auth code generated in step # 4, along with some other information, such as Client Secret, it returns the access token back to the client. Note that the exchange can not happen using front channel since ‘secret’ keys are privately stored on the sever and not on a browser. Exchanging via back channel would also prevent malicious attempts of intercepting requests and extracting auth code to generate access tokens since the ‘secret’ will still be secured on the server.

The client continues to use back channel to access resources from the resource server (step # 7 and 8).

This flow of acquiring access token is using ‘Authorization Code’ Grant Type.

That’s all for now. I hope it was useful. :)

Written by: Atif Shafi

References

--

--