While working a project, we needed to access Google calendar’s API but with a difference – the application was supposed to create new event in the Google Calendar accessed by authenticated users. After a little bit of research, I came across the Google Service Accounts that allows back-end authentication using Google authorization service.
Basically, these Service Accounts allows you to access Google API’s using OAuth 2.0 on-behalf of the web application instead of an authenticated user i.e. it uses the application service account’s credential to prove its own identity. In our case, we had to use it for accessing the Calendar API but you can use it to access any other Google service.
To create a new service account using Google Developer’s console, you have to create new client ID with the application type as service account. It will create new service account with a unique client id, email id and a public/private key pair. Do remember to keep your private key securely in development and production environment and don’t add it to the source code management.
Now, before making any request to access API, we need to get an access token by using the service accounts credential. This request is a POST request with parameters as grant-type and JWT(JSON Web Token) signed with our private key.
The first parameter grant type is a jet-bearer (it means we need an access token without refresh token). The second parameter is the JWT which contains the service account’s credential in encrypted predefined format. The format contains the header, claim set and signature. Header defines the signing algorithm which is used in signing the JWT, the claim set contains the email address of service account, scope, expiration time etc. Signature is the signed composition of header and claim set.
After making a request to the authorisation server, we receive an access token that will last for at most one hour. Using this access token, we can now access Google APIs in the same way we access it by using a user’s credential.

Above process requires the application to create and cryptographically sign JWT’s, and it’s easy to make serious mistakes that can have a severe impact on the security of application. Instead, all these things can be done by using client libraries. Ruby contains google_api_client gem for fetching access token, creating requests to access API and parsing the results.
Here is the code snippet to access Google Calendar’s API using Google Service Account.
# Initialize the client client = Google::APIClient.new(application_name: 'Service account demo', application_version: '0.0.1') # load and decrypt private key key = Google::APIClient::KeyUtils.load_from_pkcs12('path/to/key/file', 'notasecret') # generate request body for authorization client.authorization = Signet::OAuth2::Client.new( :token_credential_uri => 'https://accounts.google.com/o/oauth2/token', :audience => 'https://accounts.google.com/o/oauth2/token', :scope => 'https://www.googleapis.com/auth/calendar', :issuer => '123456-abcdef@developer.gserviceaccount.com', :signing_key => key) # fetch access token client.authorization.fetch_access_token! # load API definition service = client.discovered_api('calendar', 'v3') # access API by using client client.execute(...)
If you get error like ‘invalid grant’ while accessing API, ensure that your system time is in sync (using the NTP service) and that you are using correct the public/private key pair 🙂
It’s important to note that we can’t login using service account’s email address. In our case, we had to share service account’s calendar with other logged in users calendar – so we managed this by inserting an access control rule.
body = { 'role' => 'owner/reader/writer/none', 'scope' => { 'type' => 'default/user/group/domain', 'value' => 'your_account@domain.com' } } client.execute(:api_method => service.acl.insert, :parameters => { 'calendarId' => 'primary' }, :headers => { 'Content-Type' => 'application/json' }, :body => JSON.dump(body))
I get this permission error when I try to *insert* an event (listing events works fine):
$ ruby india.rb
/Users/ami/.rvm/gems/ruby-2.2.1/gems/google-api-client-0.8.6/lib/google/api_client.rb:662:in `block (2 levels) in execute!’: Forbidden (Google::APIClient::ClientError)
from /Users/ami/.rvm/gems/ruby-2.2.1/gems/retriable-1.4.1/lib/retriable/retry.rb:27:in `perform’
from /Users/ami/.rvm/gems/ruby-2.2.1/gems/retriable-1.4.1/lib/retriable.rb:15:in `retriable’
from /Users/ami/.rvm/gems/ruby-2.2.1/gems/google-api-client-0.8.6/lib/google/api_client.rb:645:in `block in execute!’
from /Users/ami/.rvm/gems/ruby-2.2.1/gems/retriable-1.4.1/lib/retriable/retry.rb:27:in `perform’
from /Users/ami/.rvm/gems/ruby-2.2.1/gems/retriable-1.4.1/lib/retriable.rb:15:in `retriable’
from /Users/ami/.rvm/gems/ruby-2.2.1/gems/google-api-client-0.8.6/lib/google/api_client.rb:636:in `execute!’
from india.rb:63:in `’
Check if your service account have permission to edit the calendar.