Authenticating with OmniAuth and OpenID Connect (OIDC) in Ruby on Rails applications
What is OpenID Connect?
Have you ever wondered how websites let you log in using your Google or Facebook account without you having to remember yet another password? That magical process is often powered by something called OpenID Connect (OIDC). Think of OIDC as the friendly bouncer at the club (or not so friendly depending on your intentions and actions) who checks your ID and lets you in without any hassle.
OpenID Connect is a simple identity layer built on top of the OAuth 2.0 protocol. It allows applications to verify the identity of users based on the authentication performed by an authorization server, and to obtain basic profile information about the user in an interoperable and REST-like manner.
In a nutshell, OIDC is like a digital passport system. Just like you don’t need a new passport for every country you visit, you don’t need a new username and password for every website that supports OIDC. You just log in with a trusted provider, and you’re good to go!
Who Provides These Services?
Now, you might be wondering, “Who are these providers that let me log in with my social accounts?” Well, modern tech giants like Google, Facebook, and Amazon offer OIDC services. They act as the passport control agents in our analogy, validating your identity and making sure you are who you say you are.
But what if you want to create your own passport control? Providers like Cloudflare with its Secure Access feature, Okta, Auth0, and even AWS Cognito let you build your own OIDC authentication servers. They provide the tools and infrastructure to set up your own ID verification system, so you can manage who gets in and who stays out. It’s like being the bouncer and the club owner at the same time!
Why Should We Care?
As software developers, we like things to be simple, secure, and efficient. OIDC ticks all these boxes. It offers secure user authentication, simplifies the login process, and provides flexibility by allowing users to log in with an identity provider of their choice. With OIDC, you don’t have to manage user credentials yourself, which saves you from the headache of password resets and security breaches.
Plus, OIDC is super friendly to developers. With OIDC, you can integrate authentication into your app without reinventing the wheel. You get to focus on the fun stuff — like building awesome features for your users — instead of worrying about security. Sounds like a win-win, right?
The Quest for the Perfect Gem
Well, I embarked on a quest to integrate OIDC with my application using OmniAuth
. OmniAuth is a gem that provides a standardized way to handle authentication in Rails applications. It’s like a Swiss Army knife for logging in users. You just plug it in, and it handles the nitty-gritty details of authentication for you.
There are several existing gems for integrating OIDC with OmniAuth, like openid_connect, omniauth-openid-connect and omniauth_openid_connect. The openid_connect
gem is solid, but it lacks detailed documentation and the methods are difficult to understand unless you are very familiar with the details of OIDC. Trying to figure out how to configure it was like solving a Rubik’s Cube blindfolded. Not exactly a walk in the park!
On the other hand, the omniauth-openid-connect
seemed promising, but unfortunately it is no longer maintained, while its successor the omniauth_openid_connect
did not work well with my OIDC provider (shout out to Cloudflare, my trusty gatekeeper). It felt like trying to fit a square peg into a round hole.
If You Want Something Done Right…
After grappling with existing solutions and feeling like I am lost in a maze, I decided to take matters into my own hands. I rolled up my sleeves, grabbed my coding sword, and built my own OmniAuth strategy for OIDC.
I created my own gem that meets my needs and works seamlessly with my OIDC provider. It’s designed to be simple to use, flexible, and easily customizable. If you’re in the same boat as I was, them omniauth_oidc might just be the lifesaver you’re looking for.
How Does the Gem Work?
Instead of diving into installation details (you can find those in the gem’s repository with step-by-step instructions), let’s explore how this gem handles OIDC authentication with minimal configuration.
Your app needs to get a “passport” for the user from an OpenID Connect (OIDC) provider. This starts with configuring the gem. Unlike other gems that require a laundry list of configuration details, omniauth_oidc
keeps it simple. You only need four things:
client_id
client_secret
config_url
(the URL to your OIDC provider’s configuration)name
(to differentiate OIDC providers within your app)
Using the openid_config_parser the gem retrieves other crucial details from the OIDC provider’s configuration, such as: issuer, OIDC endpoints for authorization, user info, token, available scopes, etc.
The gem uses the openid_connect
to build a client and start the request phase. The gem constructs a request URL with redirect_uri
that is formed in the format of auth/<name you specified in configuration>/callback
. This redirect_uri
is where the user will be redirected after they log in with the OIDC provider.
Once the user logs in, the OIDC provider sends back a code. This is where rack-oauth2 comes into play. Using redirect_uri
specified earlier during the initial request phase, the rack-oauth2
catches the response before it hits your app and allows the omniauth_oidc
to make another request to the OIDC provider to exchange the code for an access token.
With the access token in hand, the gem pings the token endpoint to verify the token and ensure it’s legit. This verification step ensures that the token is correct.
After verification, the gem uses the access token to hit the user info endpoint of the OIDC provider. The provider sends back details like the user’s name, email, and other profile data.
The user data is then passed as an environment parameter omniauth.auth
, which is a common parameter used by many OmniAuth strategies. This allows your Rails app to authenticate or build a user profile using the information in response from the OIDC provider.
In my own case I updated Rails routes so that all URLs used by the gem redirect to a callbacks controller:
# config/routes.rb
Rails.application.routes.draw do
match 'auth/:provider/callback', via: :get, to: "callbacks#omniauth"
end
And in the callbacks_controller
I have a one-size-fits-all omniauth
method to handle all cases.
For detailed installation and setup instructions, please hop over to the gem’s repository. The gem supports a wide range of optional configurations to provide maximum flexibility and cover as many use cases as possible.
And there you have it! With OpenID Connect and OmniAuth, you can build a secure, user-friendly authentication system in your Rails application. Whether you’re letting users log in with their social accounts or setting up your own OIDC provider, this guide should help you get up and running in no time.