Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usage with Grape #73

Closed
cp opened this issue Nov 11, 2014 · 16 comments
Closed

Usage with Grape #73

cp opened this issue Nov 11, 2014 · 16 comments

Comments

@cp
Copy link

cp commented Nov 11, 2014

Does anyone have experience using this and ng-token-auth with Grape? I'm looking to access the helpers such as current_user in my Grape endpoints.

@cp cp changed the title Using with Grape Usage with Grape Nov 11, 2014
@lynndylanhurley
Copy link
Owner

@ColbyAley - have you tried it and found that it's not working, or is this a general inquiry?

@cp
Copy link
Author

cp commented Nov 11, 2014

@lynndylanhurley It's a general inquiry. I'm currently working on doing it manually, but I'm wondering if there are any existing resources. If not, I'll be sure to share what I learn.

@lynndylanhurley
Copy link
Owner

I don't know of anything that would prevent it from working. Let me know how it goes if you decide to try it!

@lynndylanhurley
Copy link
Owner

I'm gonna close this one out for now. Please re-open if you run into any issues!

@joannatdl
Copy link

I'm having the same issue. When using Grape for API, we don't use Controllers, so I'm not able to do this:

class ApplicationController < ActionController::Base
  include DeviseTokenAuth::Concerns::SetUserByToken
end

The user is not set and we get 401. :(

I tried to copy the methods from the Concern and paste it to Grape's helpers and to run the set_user_by_tokenbut I get errors and it doesn't seem to be the correct way to deal with the issue. I also tried to call the authenticate_user! method, but I always get 401.

What else could I do to make it work?

@cp
Copy link
Author

cp commented Dec 9, 2014

@rajaaa92 I ended up butchering some of the code from DeviseTokenAuth::Concerns::SetUserByToken and building my own class for handling requests like these. The code's pretty shitty, I just haven't had time to do much refactoring. Once I do I plan on publishing something.

class AuthenticatedRequest
  include Devise::Controllers::SignInOut
  attr_accessor :resource

  def initialize(opts={})
    @uid       = opts[:uid]
    @token     = opts[:token]
    @client_id = opts[:client] || 'default'
    resource   = opts[:resource]
  end

  # Start the request.
  def begin
    return resource if resource
    return nil if @token.nil?
    return nil if @uid.nil?

    user = User.find_by_uid(@uid)
    if user && user.valid_token?(@token, @client_id)
      #sign_in(:user, user, store: false, bypass: true)
      @resource = user
    else
      @resource = nil
    end

    return resource
  end

  # Finish the request, create and save new tokens, then return them as headers.
  #
  # @return Array<String> headers
  def finish
    return nil unless resource && resource.valid? && @client_id
    # Lock the user record during any auth_header updates to ensure
    # we don't have write contention from multiple threads
    @resource.with_lock do
      auth_headers = {}

      if @is_batch_request
        auth_headers = resource.extend_batch_buffer(@token, @client_id)
        # update Authorization response header with new token
      else
        auth_headers = resource.create_new_auth_token(@client_id)
      end

      return auth_headers
    end
  end
end

Then, in Grape (in my case, /lib/api.rb):

    before do
      next if @resource
      @req = AuthenticatedRequest.new(
        uid:      request.headers['Uid'],
        token:    request.headers['Access-Token'],
        client:   request.headers['Client'],
        resource: @resource
      )
      @resource = @req.begin
      if @resource
        env['warden'].set_user(@resource, scope: :user)
      end
    end

    after do
      headers = @req.finish
      next if headers.nil?
      env['warden'].authenticate(scope: :user)

      headers.each{|k,v| header(k,v)}
    end

This seems to work for me, but I pared it down quite a bit so it doesn't currently work with batched requests, and probably some other features I'm not currently using.

@joannatdl
Copy link

Thanks @ColbyAley ! It looks like it's working! :) For now I don't need batched requests so your code is enough for me. Thanks again :)

@raviada
Copy link

raviada commented Jan 12, 2015

I also have the same setup as you are. I am wondering where in the grape you have before and after blocks defined?

I know you mentioned /lib/api.rb but I don't have that file.

Or you actually added the custom class and added before and after blocks Grape repo or to your rails project?

Thanks

@joannatdl
Copy link

My app/api/api.rb:

class API < Grape::API
  format :json
  formatter :json, Grape::Formatter::ActiveModelSerializers
  logger Rails.logger

  mount ::V1::Base
end

My app/api/v1/base.rb:

require 'authenticated_request'

module V1
  class Base < Grape::API

    version 'v1', using: :path

    before do
      next if @resource
      @req = ::AuthenticatedRequest.new(
        uid:      request.headers['Uid'],
        token:    request.headers['Access-Token'],
        client:   request.headers['Client'],
        resource: @resource
      )
      @resource = @req.begin
      if @resource
        env['warden'].set_user(@resource, scope: :user)
      else
        h = {'Access-Control-Allow-Origin' => "*", 'Access-Control-Request-Method' => %w{GET POST OPTIONS}.join(",")}
        error!('You need to log in to use the app.', 401, h)
      end
    end

    mount V1::Something

    after do
      headers = @req.finish
      next if headers.nil?
      env['warden'].authenticate(scope: :user)

      headers.each{|k,v| header(k,v)}
      header 'Access-Control-Allow-Origin', "*"
      header 'Access-Control-Request-Method', %w{GET POST OPTIONS}.join(",")
    end
  end
end

The code from authenticated_request is pasted into app/lib/authenticated_request.rb

I hope that helps!

@lynndylanhurley
Copy link
Owner

Thanks @rajaaa92!! When I get a chance, I'll add a Grape case to the test suite.

I don't have much Grape experience - let me know if there's anything this gem can do to provide better support for Grape.

@cp
Copy link
Author

cp commented Jan 23, 2015

this is so great, thanks for sharing @rajaaa92!

@shicholas
Copy link

👍, it would be nice to use this w/ grape.

@mcordell
Copy link

Hi everybody,

I created a gem that allows grape to authenticate using an existing devise_token_auth installation in a rails app. Its called grape_devise_token_auth and you can also find an example setup of jToker + devise + devise_token_auth + grape_devise_token_auth here.

@mcordell
Copy link

Hi again,

So I've created a full port of devise_token_auth for grape. It can be found here at grape_token_auth. This is different from the above gem in that it is purely dependent on grape and does not depend on rails, devise, or devise_token_auth.

I'm approaching an initial 0.1.0 release and I'd love it if @lynndylanhurley or @booleanbetrayal could give it a review and tell me what they think.

Cheers!

@lynndylanhurley
Copy link
Owner

Fantastic work @mcordell! I'll make a note in the README that directs grape users to your project.

@booleanbetrayal
Copy link
Collaborator

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants