Last Updated: February 25, 2016
·
7.692K
· michiels

How to simply roll your own OAuth2 provider with direct user/pass access

For one of our clients, we are building an interface application and an API layer. All authentication and stuff is going to happen in the API and our interface will use OAuth to authenticate with the API.

Initially, we won't want any interface code in the API application so I was looking for a solution where we could directly pass the username and password from a login form in the interface to our API OAuth Provider.

Since we are writing both apps we don't have a need to have the user accept it's app access. Here's the code in the controller:

app/controllers/authorize_controller.rb

class AuthorizeController < ApplicationController
  skip_before_filter :verify_authenticity_token

  def sign_in

    u = User.find_by_username(params[:username])

    Songkick::OAuth2::Provider.handle_passwords do |client, username, password, scopes|
      user = User.find_by_username!(username)
      if user.authenticate?(password)
        user.grant_access!(client)
      else
        nil
      end
    end

    oauth = Songkick::OAuth2::Provider.parse(nil, env)
    response.headers = oauth.response_headers

    if body = oauth.response_body
      render :text => body, :status => oauth.response_status
    end
  end
end

Here are the routes:

config/routes.rb

OauthProvider::Application.routes.draw do
  post "/oauth/token" => "authorize#sign_in"
end

I am using the <a href="songkick-oauth2-provider">https://github.com/songkick/oauth2-provider</a>. If you want to know how to set up your models, please read their README.

I built a little Rake task to test a connection by trying to grab an access token from the provider.

lib/tasks/oauth_test.rake

require 'oauth2'

namespace :oauth do

  desc "Test our oauth connection" 
  task :test => :environment do

    client = OAuth2::Client.new(
      "h171cbibzlqfzkdojeqpwbjzt235xw5", 
      "4vs772iob20vtvtaxgy6ndnpauv2sj", 
      :site => "http://oauthprovider.dev")

    token = client.password.get_token("michiel", "password")
    puts token.inspect

  end

end

All works fine!

If you have questions about the details. Please hook me up at <a href="http://twitter.com/michiels">@michiels</a> or <a href="mailto:michiel@firmhouse.com">michiel@firmhouse.com</a>!