Skip to content

OpenID and Google Apps

mattetti edited this page Feb 1, 2013 · 18 revisions

When utilizing the OpenID and Google Apps strategies with OmniAuth, there are a few extra things to keep in mind.

Example

Gemfile:

gem 'omniauth-openid'
gem 'ruby-openid-apps-discovery'
require 'omniauth-openid'
require 'openid'
require 'openid/store/filesystem'
require 'gapps_openid'

# set the path to your ca file so https calls are verified. (change to wherever your cert lives)
OpenID.fetcher.ca_file = "#{Rails.root}/config/certs/cacert.pem"

use Rack::Session::Cookie, :secret => 'supers3cr3t'

# provide us with a /auth/admin endpoint to authenticate via Google Apps Auth
# note how the domain was appended to the identifier url.
use OmniAuth::Builder do
  provider :open_id,  :name => 'admin',
                      :identifier => 'https://google.com/accounts/o8/site-xrds?hd=yourdomain.com',
                      :store => OpenID::Store::Filesystem.new('/tmp')
end

Google uses its own discovery protocol, that's why we need to use ruby-openid-apps-discovery.

See Matt Aimonetti's blog post for more information (Jan 2013).

NOTE: The following information seems to only apply to pre 1.0 versions.

OpenID Store

You will need to provide some kind of storage solution for the data transferred during the OpenID authentication process. For many hosting providers you could use a simple filesystem store like so:

    require 'openid/store/filesystem'
    use OmniAuth::Strategies::OpenID, OpenID::Store::Filesystem.new('/tmp')

However, for hosting providers that have read-only filesystems this may not be the case. You will have to find and utilize some other kind of store (for example, an ActiveRecord Store). On Heroku you can change the path to "./tmp" or use Memcached.

If you get "openid/store/filesystem (LoadError)" then you may need to add this to your Gemfile:

gem "oa-openid"

Specifying a Provider

If you want to provide "NASCAR Links" (i.e. logo links that initiate authentication with a specific provider) you can easily do so. Simply add an openid_url parameter to the authentication call. For example, to authenticate people with their Yahoo account, you could send them to /auth/open_id?openid_url=yahoo.com. If you would like some free provider buttons, check out the AuthButtons library.

Creating a Special Provider

If you (for some reason) want users to only authenticate through a specific OpenID provider, you can do so by providing the discover URL directly when you initialize the middleware. For example, if I wanted a 'Yahoo' specific authentication provider, I would write:

    use OmniAuth::Strategies::OpenID, OpenID::Store::Filesystem.new('/tmp'), :name => 'yahoo', :identifier => 'yahoo.com'

The :name option lets you specify the name for use in the auth URL (the example above would be accessed at /auth/yahoo while the :identifier parameter should be a discovery URL for an OpenID.

For Google OpenID, you can do this:

    use OmniAuth::Strategies::OpenID, OpenID::Store::Filesystem.new('/tmp'), :name => 'google', :identifier => 'https://www.google.com/accounts/o8/id'

The nil instructs OpenID to use the default store, which is the Memory store (list of all OpenID stores).

Google Apps

Google Apps accounts have a special kind of OpenID discovery that is supported by OmniAuth. In order to allow people to log in to your application using Google Apps accounts, simply use the Google Apps strategy:

    use OmniAuth::Strategies::GoogleApps, OpenID::Store::Filesystem.new('/tmp')

When you now send your users to /auth/google_apps, OmniAuth will prompt them for their Google Apps domain and then log them in accordingly. If you already know the domain for some reason, you can bypass the prompt by passing it to the URL like so: /auth/google_apps?domain=somedomain.com.

Specifying a Domain

If you're building an app, you may want to utilize Google Apps for the domain to provide a screen to administrative access. One easy way to do this is to provide a special named authentication provider for your company's Google Apps account.

    use OmniAuth::Strategies::GoogleApps, OpenID::Store::Filesystem.new('/tmp'), :name => 'admin', :domain => 'intridea.com'

Now if you send a user to /auth/admin it will automatically redirect them to login with their Intridea Google Apps account. Not only that, but your omniauth.auth hash will have a provider value of "admin" (or whatever else you name it) allowing you to easily find out when someone has logged in with admin priveleges.

Google Apps Marketplace

With OmniAuth it's easy to integrate with the one-click application install of the Google Apps Marketplace. First you need to do is add the :google_apps provider to your application:

    use OmniAuth::Builder do
      provider :google_apps, OpenID::Store::Filesystem.new('/tmp')
    end

Next, simply add a template to your Google Apps Marketplace manifest that looks like this:

    <Extension id="navLink" type="link">
      <Name>Example Link</Name>
      <Url>http://omniauth.example.com/auth/google_apps?domain=${DOMAIN_NAME}</Url>
    </Extension>

Make sure you also add your OpenID realm so that the sign-in won't require an additional authorization step:

    <Extension id="realm" type="openIdRealm">
      <Url>http://omniauth.example.com</Url>
    </Extension>

Once you've done this and someone has installed the app from the Google Apps Marketplace, they will be able to click to login to your app with one step. If you want to then automatically create or manage accounts by domain, you can simply parse the UID passed back from OpenID in your Google Apps callback:

    require 'uri'
    account_domain = URI.parse(request.env['omniauth.auth']['uid']).domain

That's all you need to do to integrate with the Google Apps Marketplace. Pretty cool, huh?