Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
An updated OAuth2 controller for a Rails app (implies you have ClientApplication and AccessGrant)
class OauthController < ApplicationController
class ApiOAuthError < StandardError
attr_accessor :code, :description, :uri, :state
def initialize(code, description, uri = nil, state = nil)
@code = code
@description = description
@uri = uri
@state = state
end
end
before_filter :authenticate_user!, :except => [:access_token]
before_filter :expires_now
skip_before_filter :app_initialization, :retrieve_api, :verify_authenticity_token, :only => [:access_token]
rescue_from ApiOAuthError, :with => :oauth2_error
def oauth2_error(e)
# see http://tools.ietf.org/html/draft-ietf-oauth-v2-10
error = { :error => e.code }
error[:error_description] = e.description unless e.description.blank?
error[:error_uri] = e.uri unless e.uri.blank?
error[:state] = e.state unless e.state.blank?
render :json => error, :status => 401
end
def authorize
# client id
client_id = params[:client_id]
raise ApiOAuthError.new(:invalid_client, "missing client_id", nil, params[:state]) if client_id.blank?
# response type
response_type = params[:response_type]
raise ApiOAuthError.new(:unsupported_response_type, "missing response_type", nil, params[:state]) if response_type.blank?
raise ApiOAuthError.new(:unsupported_response_type, "unsupported response_type: #{params[:response_type]}", nil, params[:state]) unless response_type == 'code'
# client application
application = ClientApplication.where({:app_id => client_id}).first
raise ApiOAuthError.new(:invalid_client, "invalid client_id: #{client_id}", nil, params[:state]) unless application
raise ApiOAuthError.new(:access_denied, "invalid client_id: #{client_id}", nil, params[:state]) unless application.access_granted
# TODO: raise unauthorized_client if client is disabled
AccessGrant.prune!
access_grant = current_user.access_grants.create({:application => application})
redirect_uri = access_grant.redirect_uri_for(params[:redirect_uri], params[:state])
redirect_to redirect_uri
end
def access_token
# client id
client_id = params[:client_id]
raise ApiOAuthError.new(:invalid_client, "missing client_id", nil, params[:state]) if client_id.blank?
# client application
application = ClientApplication.where({:app_id => client_id}).first
raise ApiOAuthError.new(:invalid_client, "invalid client_id: #{client_id}", nil, params[:state]) unless application
# TODO: raise unauthorized_client if client is disabled
application = ClientApplication.authenticate(params[:client_id], params[:client_secret])
raise ApiOAuthError.new(:access_denied, "invalid client_secret: #{params[:client_secret]}", nil, params[:state]) unless application
# grant type
grant_type = params[:grant_type]
case grant_type
when "authorization_code" then
code = params[:code]
raise ApiOAuthError.new(:invalid_grant, "missing code", nil, params[:state]) if code.blank?
access_grant = AccessGrant.authenticate(code, application.id)
raise ApiOAuthError.new(:invalid_grant, "invalid code: #{params[:code]}", nil, params[:state]) unless access_grant
when "credentials" then
AccessGrant.prune!
email = params[:email]
raise ApiOAuthError.new(:invalid_grant, "missing e-mail", nil, params[:state]) if email.blank?
password = params[:password]
raise ApiOAuthError.new(:invalid_grant, "missing password", nil, params[:state]) if password.blank?
user = User.where({email: email}).first
raise ApiOAuthError.new(:invalid_grant, "invalid e-mail or password", nil, params[:state]) if user.nil? or ! user.valid_password?(password)
access_grant = user.access_grants.create({:application => application})
else
raise ApiOAuthError.new(:unsupported_grant_type, "unsupported grant type: #{params[:grant_type]}", nil, params[:state])
end
access_grant.start_expiry_period!
token =
{
:access_token => access_grant.access_token,
# :refresh_token => access_grant.refresh_token,
:expires_in => access_grant.access_token_expires_at
}
token[:state] = params[:state] unless params[:state].blank?
render :json => token
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment