OAuth Login in Rails: What the Tutorials Leave Out
Setting up OAuth login for a Rails project is one of those tasks that sounds simple until you actually try it. Combined with Devise — an authentication library that's powerful but famously opaque — the process quickly turns into a scavenger hunt through blog posts and Stack Overflow answers.
Following a well-written tutorial (like DigitalOcean's guide to Devise and OmniAuth) gets you surprisingly far. GitHub login works almost immediately. But when you need a custom OAuth provider — say, for the Recurse Center — a few non-obvious details surface. Here are the two that caused the most trouble.
The Access Token Is Not the User Profile
A common misconception: once the OAuth server hands back an access token, the authentication flow is "done." It isn't. The access token is just your key to fetch user information from the provider's API.
Take this line, lifted from the omniauth-oauth2 template:
access_token.get('/me')
On the surface, it looks like it's reading a /me key from a hash called access_token. In reality, it's making an HTTP request to the provider's API using that access token, hitting the /me path. That response is where the user's name, email, and other profile fields actually come from — which makes the path critical to get right.
If the path is wrong, the request silently fails and nothing works. Fixing the path — not the token handling, not the callback — was what finally made the integration function.
Rails Decides Between HTTP and HTTPS via a Header
OAuth requires sending a redirect_uri to the provider — the URL on your site where the user returns after authenticating. For this setup, that needs to be https://mysite.com/users/auth/github/callback. But the app kept generating an http:// URL instead.
The culprit is the X-FORWARDED-PROTO header. Rails checks this header from nginx to determine whether to construct HTTPS or HTTP links. When the site sits behind a Cloudflare proxy, the requests arriving at the server are still plain HTTP — so Rails dutifully builds every callback URL as http://....
The fix is one line:
proxy_set_header X-FORWARDED-PROTO https;
With that header set, Rails correctly generates HTTPS URLs, and the OAuth provider accepts the redirect_uri.
Devise May Be Optional After All
The original assumption was that Devise was a required dependency for using the OmniAuth gem. It turns out that's not the case — OmniAuth can be used standalone.
Now that the OAuth flow works, the question is whether to keep Devise's complexity or strip it out entirely in favor of a simpler OmniAuth-only setup. The pragmatic answer depends on whether auth becomes a feature-building bottleneck or just an implementation detail worth leaving as-is.



