I'm using the omniauth and omniauth-linkedin gems for
general OAuth functionality, but I'm not able to make them play
nice with the linkedin gem, even when calling authorize_from_access
as per this documentation. Schematically, I'm doing this:
GET /auth/linkedin
receive callback at /auth/:provider/callback => sessions#create
auth = Authorization.new(:auth => request.env['omniauth.auth'].to_json)
# at this point I can verify that I'm logged into LinkedIn
client = LinkedIn::Client.new
token = auth["credentials"]["token"]
secret = auth["credentials"]["secret"]
client.authorize_from_access(token, secret)
client.profile => 401 error
I get:
LinkedIn::Errors::UnauthorizedError: (401): OAuthProblemException while parsing OAuth request
Can someone point out what I'm doing wrong? Does my web server need to have external access? Or perhaps I'm using the wrong fields from the omniauth.auth structure? FWIW, token and secret have the form:
token = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
secret = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
configuration notes
- I am running my controller with
force_ssl
. - I am using localhost:3000 (not externally accessible)
config:
- Ruby version 1.9.3 (x86_64-darwin10.8.0)
- RubyGems version 1.8.15
- Rack version 1.4
- Rails version 3.2.2
- oauth (0.4.7)
- omniauth (1.1.0)
- omniauth-linkedin (0.0.8)
- omniauth-oauth (1.0.1)
- linkedin (0.3.7)
TL;DR
The relevant routes / controllers / models are posted here.
# file: config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :linked_in, 'xxxxxxxxxxxx', 'xxxxxxxxxxxxxxxx'
end
# config/routes.rb
Nlp::Application.routes.draw do
...
match "/login" => "sessions#new"
match "/auth/:provider/callback" => "sessions#create"
match "/logout" => "sessions#destroy"
end
# app/controller/SessionsController.rb
class SessionsController < ApplicationController
def new
end
def create
self.current_user = Authorization.authorized_user(request.env['omniauth.auth'])
redirect_to root_path, :notice => "Signed in!"
end
def destroy
self.current_user = nil
redirect_to login_path, :notice => "Signed out!"
end
end
class ApplicationController < ActionController::Base
protect_from_forgery
force_ssl
protected
def current_user
@current_user ||= User.find_by_id(session[:user_id])
end
def current_user=(user)
@current_user = user
session[:user_id] = user && user.id
end
def logged_in?
!!current_user
end
def require_login
unless logged_in?
redirect_to login_path, :alert => "You must be logged in to access this page."
end
end
helper_method :current_user, :logged_in?, :require_login
end
class Authorization < ActiveRecord::Base
belongs_to :user
validates_presence_of :user_id, :uid, :provider
validates_uniqueness_of :uid, :scope => :provider
# Find User associated with auth's UID and provider, creating one if
# needed.
def self.authorized_user(auth)
authorization = Authorization.where(:uid => auth["uid"], :provider => auth["provider"]).first_or_create! do |authorization|
authorization.user = User.where(:name => auth["info"]["name"]).first_or_create!
authorization.access_token = auth["credentials"]["token"]
authorization.access_token_secret = auth["credentials"]["secret"]
authorization.auth = auth.to_json
end
authorization.user
end
end