Skip to main content

Mobomo webinars-now on demand! | learn more.

I've been following the progress of Mozilla's BrowserID for some time now, and I'm a big fan. Having dove much deeper than most into the quagmire of fragmented authentication I've reached the same conclusion that Mozilla has: ultimately, authentication is a function that should belong to the user agent.

What is BrowserID?

BrowserID is a Single Sign-on service for the web, much like you can implement using OpenID or even Facebook or Twitter. However, BrowserID is fantastic for its simplicity: as an implementation of a simple "verified email" protocol, it is simply a way to be able to obtain the email of a user (and know that it's verified).

For now, this works via a Javascript authentication flow on a website that Mozilla is maintaining. However, the future of this technology is that you would verify your email directly within your browser and would then be able to sign in to supported websites using your browser itself.

But, you ask, why do we want authentication in the browser? Browsers are called User Agents for a reason: they are simply tools that help connect you to the content of the internet that interests you. And a lot of that content right now requires you to manage dozens of different passwords and store sensitive login information with a third party. BrowserID doesn't entirely solve this problem in its nascent web-based form, but once it is integrated into the browser itself BrowserID becomes a single, secure way to access content on the internet.

BrowserID + OmniAuth

I want BrowserID to succeed, and it will only succeed if people start using it. To that end, I've created OmniAuth BrowserID, a simple OmniAuth strategy that works with the BrowserID protocol. You can use it in your application like this:

# in Gemfile gem 'omniauth-browserid'  # in application use OmniAuth::Builder do   provider :browser_id end 

That's it! Now send your users to /auth/browser_id and they will be able to sign in using the BrowserID service. Of course you may prefer to implement your own Javascript flow. That's fine, too, just take a look at the project README for more information about customizing the flow.

BrowserID is an important idea and whether Mozilla's implementation is ultimately the one that gets adopted it's high time we started moving authentication to where it belongs: in the user agent.

Categories
Author

Today I'm happy to announce that OmniAuth version 1.0.0 has been released into the wild. The result of more than a month of heavy development, the newest version of OmniAuth brings along with it a slate of new features, a whole new structure, and the tools to let OmniAuth be your only authentication library. The one thing that hasn't changed is OmniAuth's mission: to assume nothing about how your app works and what you want to do with authentication.

Breaking up the Band

OmniAuth was first written to abstract the common parts of authentication to external service providers like Twitter and Facebook. It launched as a small collection of gems that each contained many strategies (for instance, the oa-oauth gem contained Twitter and LinkedIn strategies). As OmniAuth's popularity grew five strategies became fifty-five. Releases became fewer and further between because of the overhead of managing pull requests and issues for dozens of strategies.

No more. Starting with OmniAuth 1.0, each and every OmniAuth strategy will live in its own gem. The downside of this for end users is that you will have a few more lines to declare in your Gemfiles. The upsides, however, are numerous:

  1. There is no longer a gatekeeper to releasing an OmniAuth strategy. Just build a gem, release it, and link it from the new strategy list wiki page.
  2. Individual strategies are free to make releases as often as they'd like. Users don't have to wait for a massive OmniAuth patch or minor release to pick up fixes for changing APIs or other improvements.
  3. With a lean, focused core OmniAuth itself will be able to release more frequently and adapt itself to the needs of strategy authors.

As a final note about structural gem changes, OmniAuth 1.0 marks the beginning of strict semantic versioning for the project. For end users, this doesn't mean much. For strategy authors, that means that you can safely declare your dependency on ~> 1.0.

Identity for OmniAuth

As I began using OmniAuth in my day-to-day coding, I began to crave the flexibility of OmniAuth in even traditional authentication scenarios. I wanted a way to leverage the same unassuming, simple authentication structure even when my users logged in via username and password. Today, I'm happy to announce the first official release of omniauth-identity, an OmniAuth strategy that bridges the gap between traditional auth and OmniAuth.

With omniauth-identity you can quickly and easily set up internal identity management for your app that behaves exactly like other OmniAuth strategies. The library is simple but its implications are powerful: you can now treat internal and external authentication exactly the same in your application.

OmniAuth now ships with a Developer strategy that is essentially "fake authentication" you can use as a placeholder until you determine your app's real authentication strategies. Combined with the potential of Identity, authentication no longer has to be that annoying "first thing" you have to do before you can get down to the real business of building your app. Just drop in OmniAuth, use the Developer strategy, and implement other strategies down the road when it works for the timeline of your app. This is how I'll be building all my apps from now on, and since OmniAuth is just Rack middleware even Sinatra and other non-Rails apps can use the same techniques.

For more information on how to use omniauth-identity, see the README on GitHub.

Strategy Builders: Better Docs, Better Tools

For the 1.0 release in addition to all of the new features and structure I also tried to significantly improve the documentation for the project, especially for those who are interested in building a strategy. You can see the results of those efforts on the OmniAuth wiki which is the official repository of all documentation for OmniAuth.

Along with better documentation for developers OmniAuth 1.0 also brings along a more declarative DSL for building strategies. The new strategy API gives developers clear ways to implement consistent functionality and makes everything cleaner across the board. For more information on the tools available for strategy developers, take a look at the Strategy Contribution Guide.

App Developers: Consistency, Dynamic Strategies

While many of the improvements in OmniAuth are structural and made for strategy developers, there's also some great stuff available for everyday users of OmniAuth! Here's some highlights of new features that work across all strategies:

Auth Hash. Some small tweaks have been made to the omniauth.auth hash that is returned after authentication completes. For one, you can now access keys using method accessors (e.g. env['omniauth.auth'].info.name. The user_info key has also been renamed simply to info. The schema can be considered a stable part of the public API and any breaking changes will trigger a major version release (you can rely on OmniAuth 1.9 to support the same schema as 1.0).

Options Everywhere. As of OmniAuth 1.0, strategy authors are encouraged to make all strategy configuration happen through the options hash that is passed in on initialization. You will still have strategies that have additional arguments (such as consumer keys and secrets) for convenience, but even those can be configured instead by passing in a single options hash. This means that every configurable aspect of the strategy is handled at runtime, which brings us to the next improvement.

Better Dynamic Strategies. OmniAuth 1.0 makes it easy to dynamically alter strategies for each request using the new, universally available setup phase. Simply set the :setup option to a Rack endpoint and you can modify the strategy or anything else about the environment before passing it along to OmniAuth for normal operation.

Skip Info. Some strategies will be able to determine the UID without making additional API calls. You can pass true, false, or a lambda that takes a UID and returns true or false as to whether additional info is required. This gives you the ability to make fewer API calls for cases where you already have a user in your system, for instance.

Custom Forms. If you are utilizing an OmniAuth strategy that displays the standard OmniAuth form, you can now pass in :form => (true || false || lambda) to the strategy to instead render a custom form that conforms better to your application. This replaces the previous poorly conceived method of requiring /auth/:provider to return a 404 in order for OmniAuth to trigger.

Calling All Companies

Now that each strategy for OmniAuth is its own gem, I'm putting a public call out to any and all companies with APIs, but especially companies that are already on a Ruby stack. I would like to get companies on board for maintaining their own "official" OmniAuth strategies. This gives developers using your API the simplest possible means of authenticating to your service and will only help you get more developer traction and experimentation.

I'm also happy to announce that our first "official" strategy maintainers are none other than GitHub! You can say hello to the official GitHub OmniAuth strategy and be sure that any changes to the GitHub API will be safely transitioned into the gem immediately. My hope is that going forward many more companies will join the official strategy ranks. If you're interested in maintaining an official strategy.

Where's That Strategy?

Because of the structural changes to OmniAuth not all existing strategies are available at launch. I fully expect that in the coming weeks the strategy count will regain lost ground and even surpass the count as of the last 0.x release, but if your favorite strategy is missing from the official list here's what you can do about it:

  1. Find the source code for your strategy in the 0-3-stable branch
  2. Clone omniauth-contrib and add the strategy there
  3. Follow the strategy adaption guide to update the strategy for 1.0
  4. Submit a pull request!

The omniauth-contrib repository is a temporary repository for strategies that have been written but aren't robust and supported enough to have their own gem yet. This repository is not going to be maintained as an actual RubyGem and the strategies contained inside are meant to eventually be adopted by developers to become their own gems.

One More Thing

One last thing that I wanted to do for 1.0 is create a kind of living example that the community could update to have a simple example of as many strategies as possible. You can now visit omniauth.org and try out a number of authentication strategies that OmniAuth has to offer. The code is all open so you can see how simple it is to add and use OmniAuth in your applications today!

Welcome to 1.0

OmniAuth 1.0 marks an important milestone for the project and I'm looking forward to a new, leaner trajectory that lets us make changes more nimbly (and keeps the outstanding issue count low to zero). While the changes for 1.0 were mostly written by me, OmniAuth has been an outstanding community effort and it couldn't have gotten to where it is today without the efforts of @sferik and countless other contributors. I hope you enjoy the new release and look forward to hearing your feedback!

Categories
Author

I had the opportunity to speak at RailsConf 2011 about OmniAuth, outlining some of the reasoning behind it as well as some current and upcoming features of Intridea's own "authenticate with anything" middleware. While the session wasn't video recorded, a little trick I've picked up is to run a screencasting program in the background while I present to generate a "poor man's Confreaks" version of the talk. Well, that's exactly what I've done for OmniAuth: From the Ground Up!

I'm also embedding the slides below for a "click-through" tour of the talk, but there were a few livecoding sections that are only represented in the video form.

I had a great time at my fourth RailsConf and I hope those who had a chance to attend enjoyed my talk. I also want to say thanks to all of OmniAuth's contributors, they've given me the ability to really ratchet up the awesome on the library and I couldn't have done it without them.

Categories
Author

When you're building a web application, there's always the question of how to handle the site-wide administration. You probably have a small list of people at your company that should be able to access it. If you're like Intridea, you also use Google Apps to handle e-mail etc. Using OmniAuth it is trivially simple to set up a simple "admin login system" for your Rails 3 app. Here's how to do it.

Step One: OmniAuth Up and Running

First we'll need to include OmniAuth in our Gemfile. Just add it like so:

gem 'omniauth' 

Next, we should configure OmniAuth for our Google Apps login. Note that you can add this even if you're already using a different Google Apps strategy for OmniAuth. Create the file config/initializers/omniauth.rb and put this in it:

Rails.application.config.middleware.use OmniAuth::Builder do   provider :google_apps, OpenID::Store::Filesystem.new('/tmp'), :domain => 'yourcompany.com', :name => 'admin' end

This makes it so that going to /auth/admin from your application will have you authenticate through your company's Google Apps account (and ONLY your company's accounts will work).

Step Two: Routing

Next let's set up our routes for the admin panel. In this case I'm supposing that you want to scope everything to an 'admin' subdomain and also that all of your controllers are module scoped to admin (i.e. Admin::UsersController), but you could easily use namespace to make it a path prefix instead. In config/routes.rb, add:

match '/auth/admin/callback', :to => 'sessions#authenticate_admin'  constraints :subdomain => 'admin' do   scope :module => 'admin', :as => 'admin' do     root :to => 'users#index'     resources :users     # etc.   end end

What this has done is created an OmniAuth callback route and a group of routes that are constrained to the "admin" subdomain and will be prefixed with admin_ in the named routes. Now that we've got the routes set up, let's actually add the controllers!

Step Three: Controllers

First we'll want to make the callback active. Generate a "sessions" controller if you don't already have one, and add this code to it:

class SessionsController  '401 Unauthorized', :status => 401     end   end end

What we do here is take the e-mail that is provided to us by OmniAuth and store it in the session as the :admin_user. We then check to see if that e-mail has admin priveleges (using a method we'll write in just a moment) and redirect them to the root of the admin section if so. Next we need to add the admin? helper to ApplicationController:

class ApplicationController   def admin?     session[:admin_user] && (ENV['ADMINS'] || "").split(',').include?(session[:admin_user])   end   helper_method :admin?      def admin_required     redirect_to '/auth/admin' unless admin?   end end

This checks to see if our :admin_user is in a comma-separated list of approved administrators set at the environment level (a useful strategy for Heroku deployments, but you could do lots of things here such as load a list from YAML etc.). We've also written a method that will be used as a before_filter to require admin login.

Next up let's actually make our protected resources! If you don't already have it, generate a user admin controller:

rails g controller admin/users 

Next up let's just add a simple action to make sure it works:

module Admin   class UsersController  'Hello from the admin panel!'     end   end end

With that, you're done! When you go to admin.yourapp.com you should be redirected to log in using Google Apps. Once you've done that, if your name is on the comma-separated list you will be authorized to access the protected controller. This is a simple method that is independent of database storage so can be very useful in just about any application. When OmniAuth makes it so easy, there's no reason not to make your administrative login as smooth and painless as possible!

Categories
Author

The web application landscape has changed drastically in the past year or two. Where once every site was a silo unto itself and could reasonably expect users to create a unique login and password for each site, it is now a different story. I sigh every time I have to fill out yet another registration form, wishing instead for a simple "Connect with Facebook", "Sign in with Twitter", or "Log in with OpenID". At the same time, services are more interconnected than ever. One of the best ways to increase the popularity and viability of a new service is by piggybacking it onto the existing user bases of apps such as Twitter, Facebook, and Foursquare.

There are lots of authentication solutions out there for Rails. Many of them even have ways to connect to services such as Facebook or Twitter. But as I used these in project after project I noticed an emerging pattern: they all make too many assumptions about how I want to handle authentication in my application. Sure that makes it a quick start for the vanilla use case, but I honestly can't think of a time when I've dropped in an authentication solution and I was good to go. It's time for a change in perspective.

OmniAuth: The Unassuming Authentication Library

Today is the public release of OmniAuth. OmniAuth is a Rack-based authentication system that abstracts away the gritty, difficult parts of external authentication without assuming anything about what you actually want to do with that authentication information.

What does this mean for you? This means that you can make your app authenticate through Twitter, Facebook, LinkedIn, Google Apps, GitHub, Foursquare, and more and then have complete control from there.

Installation

OmniAuth is available as a gem:

gem install omniauth 

Diving In

Using OmniAuth is as simple as using any other Rack middleware. Of course, that's because OmniAuth is simply a Rack middleware. No complicated framework-specific configuration, just a collection of middleware to take the pain out of external authentication. Let's say I have a Sinatra app that I want to be able to authenticate via Twitter or Facebook. Here's what's required:

require 'omniauth' use Rack::Session::Cookie # OmniAuth requires sessions. use OmniAuth::Builder do   provider :twitter, "CONSUMER_KEY", "CONSUMER_SECRET"   provider :facebook, "APP_ID", "APP_SECRET" end

That's it! Now if I want to send my user to authenticate via Twitter, I send them to the URL /auth/twitter. For Facebook, /auth/facebook. The user will automatically be redirected to the appropriate site where they will be able to authenticate. Once authentication is complete, they will be redirected back to /auth/providername/callback and OmniAuth will automatically fill the omniauth.auth environment key with information about the user, so for my Sinatra client I just need to add:

get '/auth/:provider/callback' do   auth = request.env['omniauth.auth']   "Hello, #{auth['user_info']['name']}, you logged in via #{params['provider']}." end

Of course, I could do a lot more than just print out the user's name. I could also:

  • Check for an existing user via the uid key of the auth hash and log them in if one exists.
  • Create a user based on the uid and information from the user_info hash.
  • If a user is already logged in, associate this new account with the user so that they can log in using either service or post to both services using respective APIs.

The point here is that OmniAuth doesn't assume that you simply want to log a user in. It lets you make that judgment call and gives you all the information you need to do just about anything you need to do.

OmniAuth works right now for a wide variety of providers, and this list will continue to grow. OmniAuth today supports:

  • Facebook
  • Twitter
  • 37signals ID
  • Foursquare
  • LinkedIn
  • GitHub
  • OpenID (meaning Yahoo, Aol, Google, and many more)
  • Google Apps (via OpenID)
  • CAS (Central Authentication Service)
  • LDAP

A Breath of Fresh Auth

OmniAuth has been my worst-kept secret library for some time now. I've been using it as the go-to authentication strategy for new projects big and small for the last few months, and it feels really refreshing to have so much control over authentication without losing the drop-in ease of use. If you need external authentication but have found existing solutions to lack flexibility, please take a look!

OmniAuth is on GitHub with a growing set of documentation on the GitHub wiki and I have also set up a Google Group to handle any questions that might arise.

Categories
Author
1
Subscribe to Omniauth