This post is for the guy in the spot I was in last week: Googling things like “authenticate Google Calendar API via OAuth2 in Ruby on Rails”, and finding no clear result. I hope this saves you some hours.

If there’s a one-stop answer on how to make Ruby on Rails, OAuth2, OmniAuth, and the Google Calendar API all play nice with one another, I haven’t found it. Typically, when I hit a roadblock while programming, I’m able to google-copy-paste my way through it, but figuring out how to sync a Ruby on Rails app with Google Calendar has required a patchwork of solutions from a number of sources.

The watershed came when I stopped trying to find a quick-fix, put aside the app I was working on, and took the time to learn more about OmniAuth, and the Google API OAuth2 strategy. Here’s how it went…

Register your app via the Google API Console

Before you do anything, you have register your app via the Google API Console. Create a new project, turn on the Google Calendar API, and click API Access. You’ll end up at a screen that looks like this:

We’ll need that CLIENT ID and CLIENT SECRET later, but for now click Edit Settings and add an Authorized Redirect URI of:

1

http://localhost/auth/google_oauth2/callback

Clone RailsCast Episode 241 Source Code

If you haven’t worked with Omniauth before, watch Ryan Bates’ Simple Omniauth RailsCast. Once I learned how to use OmniAuth to interact with the Twitter API, I was halfway to figuring out how to use OmniAuth to authenticate with the Google Calendar API via OAuth2.0. To make it easier to follow along (both with the RailsCast and this post), open a terminal, and clone the Episode 241 Git Repo inside a new directory:

omniauth, ‘1.1.0’

Google Calendar API v3 requires OAuth2.0 authentication, which is only supported by OmniAuth versions 1.0 and above. OmniAuth 1.0 is significantly different from the version used in the RailsCast.

omniauth-google-oauth2

OmniAuth uses swappable “strategies” to connect to services such as Facebook, Twitter, FourSquare, etc. We are replacing the Twitter strategy from the RailsCast with the Google OAuth2.0 strategy. To make this work right, replace the existing app/initializers/omniauth.rb with:

Replace with the keys you got from the Google API console. The proper way to do this is to store the values in a YAML file, but for the sake of moving fast, just copy and paste them into the code for now.

This is a good place to get tripped up. You would think you would only need to request the calendar scope, but because of the way that OmniAuth makes the request, if you do not also include the _userinfo.email_scope, you will receive an error that looks like this:

Add a callback route

OmniAuth automagically sets up a route for /auth/google-oauth2 (which does not appear in routes.rb) that sends the user to Google to ask if he’d like to give permission to our app. We need to set up a route to catch the response when Google sends us a callback. We’ll use the same one from the RailsCasts, but if you’re not following along with his code, it looks like this in your routes.rb:

1

match"/auth/:provider/callback"=>"sessions#create"

Notice that the path /auth/google-oauth2/callback matches the callback URI we gave in the Google API console.

Create the callback function

Our routes.rb redirects the callback URI to the create function in the sessions controller. We’ll blow away Ryan’s callback function and replace it with one modified from Google’s Your First App. This controller does two things:

Get authentication data that was given to Omniauth by Google

Use the token from that auth data to request a list of calendars

123456789101112131415

classSessionsController<ApplicationControllerdefcreate#What data comes back from OmniAuth? @auth=request.env["omniauth.auth"]#Use the token from the data to request a list of calendars@token=@auth["credentials"]["token"]client=Google::APIClient.newclient.authorization.access_token=@tokenservice=client.discovered_api('calendar','v3')@result=client.execute(:api_method=>service.calendar_list.list,:parameters=>{},:headers=>{'Content-Type'=>'application/json'})endend

View the results

My view simply dumps the contents of @auth and @result.data to the screen

Do It!

Now we just need a link to the OmniAuth path to kick off the party. In /app/views/layouts/application.html.erb with, replace line 17 (the “Sign in with Twitter” bit) with:

1

<%=link_to"Sign in with Google","/auth/google_oauth2"%>

Launch your rails server, visit the home page, and click the link. OmniAuth takes over, directing you to a screen you’ve probably seen before:

Confirm, and if all goes well, you’ll get output that looks like this:

In @auth you can see the token, request token, and expires_at, which you’ll presumably want to store in the database. Below, in @result.data, you can see that I am the proud owner of two Google calendars.

Once you’re here, the hard part is over. Anything else you want to do with the calendar – add events, check free/busy, etc. – can be accomplished by changing the two lines below using your favorite functions and parameters from the Google Calendar API reference.