Skip to content

Instantly share code, notes, and snippets.

@jigneshkhokhani
Last active April 30, 2021 12:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jigneshkhokhani/7432669d1d161fd70658b2efe21df4ec to your computer and use it in GitHub Desktop.
Save jigneshkhokhani/7432669d1d161fd70658b2efe21df4ec to your computer and use it in GitHub Desktop.
medium-(Rails API + Doorkeeper + Devise)
class ApplicationController < ActionController::API
# Devise code
before_action :configure_permitted_parameters, if: :devise_controller?
# Doorkeeper code
before_action :doorkeeper_authorize!
respond_to :json
protected
# Devise methods
# Authentication key(:username) and password field will be added automatically by devise.
def configure_permitted_parameters
added_attrs = [:email, :first_name, :last_name]
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
devise_parameter_sanitizer.permit :account_update, keys: added_attrs
end
private
# Doorkeeper methods
def current_resource_owner
User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
end
end
module CustomTokenErrorResponse
def body
{
status_code: 401,
message: I18n.t('devise.failure.invalid', authentication_keys: User.authentication_keys.join('/')),
result: []
}
# or merge with existing values by
# super.merge({key: value})
end
end
module CustomTokenResponse
def body
user_details = User.find(@token.resource_owner_id)
# call original `#body` method and merge its result with the additional data hash
super.merge({
status_code: 200,
message: I18n.t('devise.sessions.signed_in'),
result: user_details
})
end
end
Doorkeeper.configure do
# Change the ORM that doorkeeper will use (needs plugins)
orm :active_record
# This block will be called to check whether the resource owner is authenticated or not.
resource_owner_authenticator do
fail "Please configure doorkeeper resource_owner_authenticator block located in #{__FILE__}"
# Put your resource owner authentication logic here.
# Example implementation:
# User.find_by_id(session[:user_id]) || redirect_to(new_user_session_url)
end
# In this flow, a token is requested in exchange for the resource owner credentials (username and password)
resource_owner_from_credentials do |routes|
user = User.find_for_database_authentication(:username => params[:username])
if user && user.valid_for_authentication? { user.valid_password?(params[:password]) }
user
end
end
...
# Access token expiration time (default 2 hours).
# If you want to disable expiration, set this to nil.
access_token_expires_in 5.days
...
#
# implicit and password grant flows have risks that you should understand
# before enabling:
# http://tools.ietf.org/html/rfc6819#section-4.4.2
# http://tools.ietf.org/html/rfc6819#section-4.4.3
#
# grant_flows %w(authorization_code client_credentials)
grant_flows %w(password)
# Under some circumstances you might want to have applications auto-approved,
# so that the user skips the authorization step.
# For example if dealing with a trusted application.
# skip_authorization do |resource_owner, client|
# client.superapp? or resource_owner.admin?
# end
skip_authorization do
true
end
# WWW-Authenticate Realm (default "Doorkeeper").
# realm "Doorkeeper"
end
Doorkeeper::OAuth::TokenResponse.send :prepend, CustomTokenResponse
Doorkeeper::OAuth::ErrorResponse.send :prepend, CustomTokenErrorResponse
cancel_user_registration GET /api/users/cancel(.:format) api/v1/users/registrations#cancel {:format=>:json}
new_user_registration GET /api/users/sign_up(.:format) api/v1/users/registrations#new {:format=>:json}
edit_user_registration GET /api/users/edit(.:format) api/v1/users/registrations#edit {:format=>:json}
user_registration PATCH /api/users(.:format) api/v1/users/registrations#update {:format=>:json}
PUT /api/users(.:format) api/v1/users/registrations#update {:format=>:json}
DELETE /api/users(.:format) api/v1/users/registrations#destroy {:format=>:json}
POST /api/users(.:format) api/v1/users/registrations#create {:format=>:json}
# frozen_string_literal: true
class Api::V1::Users::RegistrationsController < Devise::RegistrationsController
# before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
# Somehow respond_to is not working so I manually render as json
skip_before_action :doorkeeper_authorize!
# respond_to :json
# GET /resource/sign_up
# def new
# super
# end
# POST /resource
def create
build_resource(sign_up_params)
resource.save
if resource.persisted?
if resource.active_for_authentication?
# set_flash_message! :notice, :signed_up
# To avoid login comment out sign_up method
# sign_up(resource_name, resource)
render json: resource # , location: after_sign_up_path_for(resource)
else
# set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
render json: resource # , location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
set_minimum_password_length
respond_with resource
end
end
# GET /resource/edit
# def edit
# super
# end
# PUT /resource
# def update
# super
# end
# DELETE /resource
# def destroy
# super
# end
# GET /resource/cancel
# Forces the session data which is usually expired after sign
# in to be expired now. This is useful if the user wants to
# cancel oauth signing in/up in the middle of the process,
# removing all OAuth session data.
# def cancel
# super
# end
protected
# Overwrite : Devise method
# Signs in a user on sign up.
# def sign_up(resource_name, resource)
# # Do not sign in user after successfull registration
# # sign_in(resource_name, resource)
# end
# If you have extra params to permit, append them to the sanitizer.
# def configure_sign_up_params
# devise_parameter_sanitizer.permit(:sign_up, keys: [:attributes])
# end
# If you have extra params to permit, append them to the sanitizer.
# def configure_account_update_params
# devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
# end
# The path used after sign up.
# def after_sign_up_path_for(resource)
# super(resource)
# end
# The path used after sign up for inactive accounts.
# def after_inactive_sign_up_path_for(resource)
# super(resource)
# end
end
Rails.application.routes.draw do
# Use for login and autorize all resource
use_doorkeeper do
# No need to register client application
skip_controllers :applications, :authorized_applications
end
scope module: :api, defaults: { format: :json }, path: 'api' do
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
devise_for :users, controllers: {
registrations: 'api/v1/users/registrations',
}, skip: [:sessions, :password]
end
end
end
@coderahool
Copy link

how we have do for sessions controller i.e sign in/login process ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment