Search code examples
rubyoauth-2.0google-analytics-api

GoogleAnalytics ServiceAccount auth


While attempting to use the Legato gem with service accounts, we're receiving an error from Google Authorization failed. Server message: { "error" : "invalid_grant” }.

def token
  OAuth2::AccessToken.new(oauth_client, client_authorization.access_token,
    expires_in: 1.hour
  )
end

def oauth_client
  OAuth2::Client.new("", "", {
    authorize_url: "https://accounts.google.com/o/oauth2/auth",
    token_url: "https://accounts.google.com/o/oauth2/token",
  })
end

def client_authorization
  @_client_authorization ||= client.authorization = service_account.authorize
end

def service_account
  Google::APIClient::JWTAsserter.new({{ secret email address }},
                                     "https://www.googleapis.com/auth/analytics.readonly",
                                     key)
end

def key
  Google::APIClient::KeyUtils.load_from_pem({{ secret keyfile path }}, {{ not so secret keyfile passphrase }})
end

def client
  Google::APIClient.new(
    application_name: {{ app name }},
    application_version: 1,
  )
end

We know a few things:

  1. The keyfile/pass are correctly working. If they were not, we’d see "Invalid keyfile or passphrase”.
  2. The code works in development (consistently and as expected)

Hypothesized issues:

  1. Can we only generate one grant (per hour) for the service account?
  2. Do we need to somehow share the grant between the servers?
  3. Do we need to manually fetch a token and use it instead?
  4. Is there an IP restriction somewhere that doesn’t apply to localhost?

Solution

  • There are 2 common problems that cause invalid_grant errors:

    1. Your server's clock is out of sync with NTP
    2. You've exceeded the refresh token limit

    More details can be found here.