authenticate grape api with doorkeeper - ruby-on-rails

I have currently configured Devise,Doorkeeper and grape in my rails application.
Devise and Doorkeeper are configured so that I can register and login with Devise on the website and Doorkeeper provides oAuth endpoints that can create tokens.
How can I add a token to a HttpRequest and protect the grape API with it?
Edit:
So I tried to implement the Winebouncer implementation Tom Hert suggested.
I followed the instructions on https://github.com/antek-drzewiecki/wine_bouncer
I have installed the gem.
I have defined config/initializers/wine_bouncer.rb as the following.
WineBouncer.configure do |config|
config.auth_strategy = :default
config.define_resource_owner do
User.find(doorkeeper_access_token.resource_owner_id) if doorkeeper_access_token
end
end
I have registered Winebouncer as middleware in grape in my base api controller.
app\controllers\api\base.rb
module API
class Base < Grape::API
mount API::V1::Base
use ::WineBouncer::OAuth2
end
end
I mounted my projects controller in my V1 base controller
app\controllers\api\v1\base.rb
module API
module V1
class Base < Grape::API
mount API::V1::Projects
end
end
end
And this is my projectscontroller
app\controllers\api\v1\projects.rb
module API
module V1
class Projects < Grape::API
version 'v1'
format :json
resource :projects do
desc "Return list of projects" , auth: { scopes: [] }
get do
Project.all
end
end
end
end
end
To be honest I don't yet know how the ", auth: { scopes: [] }" in the description is suppossed to work. And how to add the token to a request, but I would expect my request but be blocked when no token is added. But the the request is still producing the json data.

I found quite interesting code here: https://github.com/fuCtor/grape-doorkeeper
It seems to be still maintained. But I think this is good just to get the idea of what is going on there.
I would recommend this: https://github.com/antek-drzewiecki/wine_bouncer
As said on the page:
Protect your precious Grape API with Doorkeeper. WineBouncer uses
minimal modification, to make the magic happen.

obedeijn, i just noticed your question on stackoverflow.
WineBouncer works just like doorkeeper, it looks for the Authorizations header with a "Bearer x" where x is the token.

Related

Grape API (swagger doc) - Global configuration of 'desc'

Its been an interesting an busy week. I am working on a Rails project and included Grape to implement the API.
The API has 2 sections
No auth required (no headers)
Auth required
I setup the app with and all is working...
Grape
Grape Swagger
Grape Swagger Rails
For stating that a header is required I use some thing like this...
class ProfilesApi < Grape::API
resource :profiles do
desc 'List all profiles' do
headers Authorization: {
description: 'Validates identity through JWT provided in auth/login',
required: true
}
end
get do
present User.all, with: Presenters::ProfilePresenter
end
end
end
Now the problem is that I this description in a lot of similar mountable API classes.
Is there a way that can kind of make this common (kind of inherited) so that I don't need to define it wit every Grape method.
desc 'List all profiles' do
headers Authorization: {
description: 'Validates identity through JWT provided in auth/login',
required: true
}
end
Thanks in advance and hope you guys enjoy the weekend.
Yes, there's a way. I achieve that by defining a method in class API so that it's accessible in everything that inherits from API. Something like:
module Myapp
class API < Grape::API
def self.auth_headers
{ Authorization: { description: 'Validates identity through JWT provided in auth/login',required: true}}
end
end
end
And you access it like that:
desc "List all profiles", {
headers: Myapp::API.auth_headers
}
Of course, there're much more ways but they depend on your implementation.
i think this may be an updated version of grape-api thing, I've had to get this working with :
desc 'My description text' do
headers Authorization: {description: "pass the access token as Bearer", required: true }
end

Rails - Add custom headers to response based on API version

What I am trying to do is pretty simple. There are multiple versions of a Rails REST API. So, there are routes like:
http://www.example.com/v1/user.json
http://www.example.com/v2/user.json
http://www.example.com/v3/user.json
What I want to do is add custom http headers to the response based on the API version endpoint that is requested.
In my config/application.rb file, I tried:
config.action_dispatch.default_headers.merge!('my_header_1' => 'my_value_1', 'my_header_2' => 'my_value_2')
I have also tried this in my config/routes.rb file:
scope path: "v1", controller: :test do
get "action_1" => :action_1
get "action_2" => :action_2
Rails.application.config.action_dispatch.default_headers.merge!('my_header_1' => 'my_value_1', 'my_header_2' => 'my_value_2')
end
But both of these snippets append custom headers to the response irrespective of the API version endpoint.
I think I can write a middleware that checks the request url and appends the response headers based on that but it sounds a bit hackish.
Is there a better way to achieve this? Preferably via config or some central piece of code?
What about using a before_action on your controllers? I imagine each API version has its own controllers? That way you could do something like:
class API::V1::BaseController < ApplicationController
before_action :set_headers
protected
def set_headers
response.headers['X-Foo'] = 'V1'
end
end

Undefined method `resource_owner_id' for nil:NilClass Doorkeeper

I'm in the process of setting up Doorkeeper and OAuth2 for one of my Rails Applications. My goal is to allow api access to a user depending on their access_token, so that only a user can see their 'user_show' json. So far I have my development and production applications set up and authorized on the 'oauth2/applications' route.
My '/config/initializers/doorkeeper.rb'
Doorkeeper.configure do
# Change the ORM that doorkeeper will use.
# Currently supported options are :active_record, :mongoid2, :mongoid3,
# :mongoid4, :mongo_mapper
orm :active_record
# This block will be called to check whether the resource owner is authenticated or not.
resource_owner_authenticator do
# Put your resource owner authentication logic here.
# Example implementation:
User.find_by_id(session[:current_user_id]) || redirect_to('/')
end
end
and my '/api/v1/user/controller.rb' looks as such:
class Api::V1::UserController < Api::ApiController
include ActionController::MimeResponds
before_action :doorkeeper_authorize!
def index
user = User.find(doorkeeper_token.resource_owner_id)
respond_with User.all
end
def show
user = User.find(doorkeeper_token.resource_owner_id)
respond_with user
end
end
I have tried to gain access to the OAuth Applications table to see what is being created but I cannot access it in the rails console.
Thanks in advance for the insight!
It seems that Doorkeeper doesn't find any token.
Make sure you're sending it, either from url with ?access_token=#{token} or ?bearer_token=#{token}, either giving this token in headers using Bearer Authorization.
You also need to have in mind that a token could be associated only to an app, without a resource owner. So resource_owner_id value could be nil even with a valid token. It depends on what grant flow you're using (client credential flow is not associated with a resource owner). See https://github.com/doorkeeper-gem/doorkeeper/wiki#flows
For the OAuth tables, try with Doorkeeper::AccessToken.all in a rails console.
Hope this helped

How to protect rspec_api_documentation apitome route without a controller

I have a set of API documentation pages that I want to password protect using devise. The docs are generated using rspec_api_documentation. The gem uses rspec to execute the API methods and create html or json doc files. I'm generating json and using another gem, apitome, as a viewer.
This is all working beautifully and my api docs can be found at /api/docs, but I can't figure out how to require authentication to view the docs.
The docs are viewed through apitome so it using rails. There isn't a route in routes.rb, but the apitom initializer mounts the docs.
From apitom initializer:
# This determines where the Apitome routes will be mounted. Changing this to "/api/documentation" for instance would
# allow you to browse to http://localhost:3000/api/documentation to see your api documentation. Set to nil and mount
# it yourself if you need to.
config.mount_at = "/api/docs"
https://github.com/zipmark/rspec_api_documentation
https://github.com/modeset/apitome
I found this How-to that is supposed to make every page on the site require authenication, but I'm still able to hit the docs url without signing in.
#https://github.com/plataformatec/devise/wiki/How-To:-Require-authentication-for-all-pages
Thanks for any help.
You can take control of Apitome controller and request auhentication.
configure apitome to not mount itself by setting mount_at to nil
write your controller ApidocsController extending Apitome::DocsController
add before_filter :authenticate_user! in your controller
add a route to your controller: get '/api/docs', to: 'apidocs#index'
Controller implementatin would go like this:
class ApidocsController < Apitome::DocsController
before_filter :authenticate_user!
end
If you have Devise already configured (for example if you already use ActiveAdmin) you can share the same authenticated session.
You have to disable the default mounting of Apitome:
# config/initializers/apitome.rb
Apitome.setup do |config|
config.mount_at = nil
# ...
end
Since this will break links in Apitome, you have to add to your application.rb:
# config/application.rb
# ...
class Application < Rails::Application
config.after_initialize do
Apitome.configuration.mount_at = '/docs'
end
# ...
end
Then force mount of the Apitome engine under Devise authenticated session:
# config/routes.rb
Rails.application.routes.draw do
# ...
authenticated :admin_user do
mount Apitome::Engine => '/docs'
end
# root_to ...
end
Now /docs is accessible only for already authenticated users.
PS: replace :admin_user (default for Active Admin) to :user or any other model name where Devise is configured.
I am using the cut down rails api, so did not have any views or devise and so no simple way to implement password protection. Accordingly I went for the following solution.
Apitome.setup do |config|
config.mount_at = nil
# ...
end
and in the routes.rb file:
mount Apitome::Engine => '/api/docs' unless Rails.env.production?
Finally, I just did a pdf of the api/docs page, and then sent the pdf to anyone what had a right to see the documentation. Obviously not suitable for a large user base, but works fine for a small one, e.g. within a company's IT group.
If anyone is using Raddocs, add mounted route inside authentication block as below:
authenticate :user do
mount Raddocs::App => "/docs"
end

Sinatra with Rails reset session every request

I have a rails web application and I need to create API for mobile clients. I choose a Sinatra web framework for this. But I have a problem with my Sinatra app, after every request all data session lost.
My API looks like this(lib/api/core.rb):
module Api
class Core < Sinatra::Base
set :session_secret, 'secret'
enable :sessions
get '/foo' do
content_type :json
session['foo'] = 'some value'
end
get '/bar' do
content_type :json
session['foo']#everytime is nil
end
end
end
In my route.rb I wrote this:
constraints :subdomain => 'api' do
mount Api::Core => '/'
end
I use Rails 3.2.8, Sinatra 1.3.3
And my questions is how can I store data between requests(it's need me for authentication) ?
Your APIs should be stateless. Authentication is usually done with tokens that are sent along with every request. See RailsCast #352 Securing an API for more info.

Resources