Beginner’s guide to OAuth: Understanding access tokens and authorization codes using Google API
Tags: oauth, authentication, ruby
Published: 2019-08-16 04:13:35

---
title: Beginner’s guide to OAuth: Understanding access tokens and authorization codes using Google API
published: true
description: 
tags: beginners, oauth, authentication, ruby
---

As a user, it’s easy and convenient to use your Google account (or Facebook, Twitter, etc.) to sign into other services.

1. You click the "Sign in with Google" button
2. You get redirected to a consent screen
3. You click "Allow"
4. The page redirects to the actual application

But there's actually a lot going on under the hood, and it can be useful as a developer to understand it. When I implemented OAuth in Rails for the first time, I was using an external library (the [`sorcery`](https://github.com/Sorcery/sorcery) gem’s external module), which made it easy for me to gloss over the process. Yet as soon as I wanted to customize something, I realized it was necessary to have a better understanding of it. I decided to re-implement the flow without the help of any authentication helper gems.

Based on what I learned, I wrote this basic explanation of the OAuth flow and what authorization codes and access/refresh tokens are. I’m using Google as the OAuth provider.

This post is meant for people who are not very familiar with OAuth. In other words, if you already know how it works and can understand Google's OAuth [guide](https://developers.google.com/identity/protocols/OAuth2WebServer), this post may be too elementary for you.

# What are authorization codes and access tokens?
In the OAuth flow, your app needs to send two requests to Google. The first request is to get an __authorization code__, the second is to get an __access token__. They both take the form of [long strings](https://stackoverflow.com/a/10299106/11249670), but have different purposes.
This kind of similar terminology can be tricky at first, so let's first briefly cover what they are.

I bet this screen looks familiar. The __authorization code__ is a code that Google sends back to your app once the user consents on this screen.

<img src="https://thepracticaldev.s3.amazonaws.com/i/txuse5twhl8flhukvj5l.png" width="250">

This code can be used to get an __access token__. Once you've received the authorization code, you put it in the params and send a second request to Google, essentially saying "Give me an access token so I can send requests on behalf of this user?"
Google's response to that should include an access token. By putting this token in your request headers, you can do things like create a new event in the user's Google Calendar or access a user’s Gmail.

## Key things to note:

### Authorization Code

  - Only valid for one-time use, since its only usage is to exchange it for an access token
  - Expires very quickly (according to this [article](https://www.oauth.com/oauth2-servers/authorization/the-authorization-response/), the OAuth protocol's recommended maximum is 10 minutes, and many services' authorization codes expire even earlier)

### Access Token

  - Can be obtained using the authorization code
  - Put in the headers of any API requests to Google on behalf of the user
  - Expires after one hour (the expiration time may vary if you're using something besides Google)

What do you do after an hour when the access token expires? Do you have to make the user re-login to get a new one?
No. You can get something called a __refresh token__, which allows you to get new access tokens. More on this in the [last section](https://dev.to/risafj/beginner-s-guide-to-oauth-understanding-access-tokens-and-authorization-codes-2988#use-refresh-tokens-to-get-new-access-tokens) of this article.

# OAuth step-by-step
Let's go over the basic OAuth flow again, except this time, we're looking at it from the developer's point of view, not the user. I've included Ruby code snippets as well.

Note: I am skipping over the very first configuration you have to do, which is to create your `client_id` and `client_secret` in the [Google API Console](https://console.developers.google.com/apis/dashboard). This [guide](https://developers.google.com/adwords/api/docs/guides/authentication#create_a_client_id_and_client_secret) walks you through the steps.

### Step 1. User clicks the "Sign In With Google" button in your app

### Step 2. Redirect to the Google consent screen
In my case, clicking the button calls the `oauths_controller`'s `oauth` method, which then redirects the page.

```ruby
# oauths_controller.rb
def oauth
  args = {
    client_id: ENV['GOOGLE_CLIENT_ID'],
    response_type: 'code',
    scope: 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/calendar',
    redirect_uri: 'http://my-app.com/oauth/callback?provider=google',
    access_type: 'offline'
  }
  redirect_to 'https://accounts.google.com/o/oauth2/v2/auth?' + args.to_query
end

```

A quick explanation of the query parameters:

* `client_id` is the one you created in the Google API Console. I’ve just stored it in an environment variable.
* `response_type: 'code'` signals that you'd like an authorization code for obtaining an access token.
* `scope` defines what kinds of permissions you need. I needed access to the user's Google Calendar in addition to the user's name and email address, which is why I have the three scopes above. The full list of scopes can be found in the [docs](https://developers.google.com/identity/protocols/googlescopes).
* `redirect_uri` is the URI that Google redirects to once the user hits "Allow". You can't put any random URI here; it needs to match one of the URIs you added in the Google API Console.
* `access_type: 'offline'` has to do with the refresh tokens I mentioned above, and we will cover this [later](https://dev.to/risafj/beginner-s-guide-to-oauth-understanding-access-tokens-and-authorization-codes-2988#use-refresh-tokens-to-get-new-access-tokens).
 

### Step 3. The user clicks "Allow" on the consent screen
### Step 4. The page redirects to your `callback_uri`
Google handles this part. In my case, the `oauths_controller`'s `callback` method gets called.

```ruby
# routes.rb
get 'oauth/callback', to: 'oauths#callback'
```

The parameters of this incoming request from Google includes an authorization code (in `params[:code]`).

### Step 5. Exchange the authorization code for an access token
Next, you need to make an HTTP POST request to Google's token endpoint (`/oauth2/v4/token`) to get an access token in exchange for the authorization code you just received.

Note: I’m using the [`HTTParty`](https://github.com/jnunemaker/httparty) gem to make HTTP requests, but of course this isn’t mandatory.

```ruby
# oauths_controller.rb
def callback
  # Exchange the authorization code for an access token (step 5)
  query = {
    code: params[:code],
    client_id: ENV['GOOGLE_CLIENT_ID'],
    client_secret: ENV['GOOGLE_CLIENT_SECRET'],
    redirect_uri: 'http://my-app.com/oauth/callback?provider=google',
    grant_type: 'authorization_code'
  }
  response = HTTParty.post('https://www.googleapis.com/oauth2/v4/token', query: query)

  # Save the access token (step 6)
  session[:access_token] = response['access_token']
end
```

As for the params in this POST request, [this article](https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type#exchange-the-authorization-code-for-an-access-token) provides a good explanation if you're interested.

### Step 6. Save the access token
As seen in the final part of the snippet above, I'm saving the returned `access_token` in the session. Now, whenever I want to make a request to the Google API on behalf of the user, I can do so using this token.

For example, to get a list of the user's Google Calendar events:
```ruby
headers = {
  'Content-Type': 'application/json',
  'Authorization': "Bearer #{session[:access_token]}"
}
HTTParty.get(
  'https://www.googleapis.com/calendar/v3/calendars/primary/events',
  headers: headers
)

```

There we go! Now we've successfully implemented the OAuth flow using authorization tokens.

# Use refresh tokens to get new access tokens
As mentioned above, access tokens expire after a certain amount of time (e.g. 1 hour). If your app's login also expires at the same time or earlier, you have nothing to worry about - the user would have to re-login anyway.

But what if your app allowed users to be logged in for longer (after all, in many cases, being kicked out of an app after an hour could be obnoxious)? Google's access token would still expire, so any requests to the Google API would be rejected.


That’s where __refresh tokens__ come in. You can get one in the same response as the one that returns an access token (Step 5), as long as you specified `access_type: 'offline'` in the initial redirect (Step 2). 

Unlike access tokens, refresh tokens have no set expiration time. If your access token has expired, you can get a new one using a refresh token with an HTTP POST request like below:

```ruby
query = {
  'client_id': ENV['GOOGLE_CLIENT_ID'],
  'client_secret': ENV['GOOGLE_CLIENT_SECRET'],
  # Assuming we've saved the refresh_token in the DB along with the user info
  'refresh_token': current_user.refresh_token,
  'grant_type': 'refresh_token',
}
response = HTTParty.post(
  'https://www.googleapis.com/oauth2/v4/token',
  query: query
)

session[:access_token] = response['access_token']
```


## Refresh tokens gotchas
### 1. You should reuse them
You’re generally expected to keep using the same refresh token each time you request a new access token. For this reason, Google only gives you a refresh token the first time the user consents and logs in to your app ([docs](https://developers.google.com/identity/protocols/OAuth2WebServer#offline) on offline access):

> This value instructs the Google authorization server to return a refresh token and an access token the first time that your application exchanges an authorization code for tokens. 

This means that it’s important to store refresh tokens in long-term storage, like the DB.

Note: If you really need to get a new refresh token every time the user logs in, you can add `prompt=consent` to the parameters in the authorization request in [Step 2](https://dev.to/risafj/beginner-s-guide-to-oauth-understanding-access-tokens-and-authorization-codes-2988#step-2-redirect-to-the-google-consent-screen). This will require the user to consent every time they log in, but the response will always include a new refresh token.

### 2. They can become invalid too
While refresh tokens don’t expire after a set amount of time, they can become invalid in some cases ([docs](https://developers.google.com/identity/protocols/OAuth2#token-expiration)):

> You must write your code to anticipate the possibility that a granted refresh token might no longer work. A refresh token might stop working for one of these reasons:
* The user has revoked your app's access.
* The refresh token has not been used for six months.
* The user changed passwords and the refresh token contains Gmail scopes.
* The user account has exceeded a maximum number of granted (live) refresh tokens.
There is currently a limit of 50 refresh tokens per user account per client. If the limit is reached, creating a new refresh token automatically invalidates the oldest refresh token without warning.


For example, if the user revoked your app’s access, any requests to obtain a new access token using the existing refresh token would cease to work. In such cases, you would need to get the user to log out and re-login in order to get a new refresh token.  

------------
In this post, I handled everything manually without relying on gems like `devise`, `sorcery` or `omniauth-google-oauth2`. I'm not saying that's the best approach here; realistically, it might be easier to use those gems. The goal of this post was to walk through what is actually happening, in order not to blindly let the gems handle everything. Thanks for reading!