NoMethodError (undefined method `id' for nil:NilClass): at /oauth/authorize with doorkeeper - rails-api

I am working on making my API an Oauth provider using Doorkeeper, when I make a request to /oauth/authorize, I get the error
NoMethodError (undefined method `id' for nil:NilClass):
After digging into the gem, I discovered that the error comes from this place in the gem https://github.com/doorkeeper-gem/doorkeeper/blob/326a75a0633fdfd92c3259607636349173bb5fbb/app/controllers/doorkeeper/authorizations_controller.rb#L47
So, I added this to my application_controller
def current_resource_owner
User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
end
I have the configuration for doorkeeper here - https://gist.github.com/kinsomicrote/7ddd438e7cc542d173551a1d0ff4e948
I expect to get back an authorization code. I have no idea what I am doing wrong.

You request to /oauth/authorize so you are using authorization_code flow, or implicit flow of Oauth2 (please also check it out to get some info about those authorization flow of Oauth2)
the current_resource_owner method is defined here, then the authenticate_resource_owner configuration is called here.
That configuration is defined as resource_owner_authenticator at here.
So you need to config your resource_owner_authenticator! There is example here.
But currently you are configuring resource_owner_from_credentials, which indeed is for Resource Owner Password Credentials Grant of Oauth2, which is used as here

Related

How to access current_user with devise-token_authenticatable gem?

I’m working on a small project that is using devise and devise-token_authenticatable in a Rails/GraphQL/Apollo/React setup. Project is setup using webpacker, so the front and back ends are both served from the same domain. Sign-in, register, log-out are all handle by the front end (React). I also need to point out this is not an API only app.
It seems, server is not setting the current_user or the proper cookie and I’m getting a network error.
Heroku logs shows the following error:
NoMethodError (undefined method `authentication_token' for #<User:0x000055ca6c0e4c50>)
Is that mean it’s trying ‘authentication_token’ method on a nil class?
At the same time it’s showing this error in the console:
Network error: Unexpected token < in JSON at position 0 (I have no idea what this is)
In my login component’s sign-in mutation, I’m storing the authentication_token of the user in local storage after a successful login and in my Apollo setup I’m retrieving it from storage and attaching it to each request. But Chrome dev tool’s network tab shows I’m not getting the cookie set by devise after a signin in the response header. I’m pretty new to all of this so not sure this is the problem or something else. PS: I’m not using Devise sessions since sign-in is handle in the from end. I have devise_for: users, skip: :sessions in my routes.
Code snippets:
Apollo Provide
Component UserInfo
SignIn mutation
Any assistance is greatly appreciated. Thank you in advance for your help.
UPDATE: issue was fixed: (also see my answer below for additional info)
Issue was fixed by adding current_user private method in application_controller.rb.
Here's the code...
def current_user
token = request.headers["Authorization"].to_s
User.find_for_database_authentication(authentication_token: token)
end
Marko Kacanski was right I should have elaborate on my findings & how I fixed it. :-(
I was wrong to assume that the current_user is automatically sent by the gem devise-token_authenticatable when it detects a authentication_token in the header. At least the way I have setup my project, I wasn't getting the current_user as expected, instead I get a nil object.
So... I created a current_user private method in application_controller.rb and, it fixed the issue.
Here's the code...
def current_user
token = request.headers["Authorization"].to_s
User.find_for_database_authentication(authentication_token: token)
end
Fixed the issue. It had nothing to do with GraphQl/Apollo code. Thanks

Set basic auth for JSON requests and devise auth for Html requets

I have a controller named topics. When I visit the page that should be authenticated by devise gem. But, using POSTMAN for testing JSON requests, shows a error like this..
{
"error": "You need to sign in or sign up before continuing."
}
This causes due to the devise authentication. In order to avoid this issue, I simply put as a
skip_before_action:authenticate_user!
In my opinion this ignores the authentication. If there is any way to use devise normal authentication for HTML request and API basic authentication for JSON requests?
You can use the code from the Devise documentation.
However, in my opinion, it is better to have separate controllers for users and API. Then, use Devise for users and any other authentication mechanism for the API requests.

Devise 401 response code on failed password

I'm using Rails 4.1.8 and Devise 3.4.1. When a wrong username/password combo is used the resulting page is loaded with a 200 response. I want this response to use response code 401.
How can I make this change?
You have to use custom session controller for devise. See "Configuring controllers" section of the readme.

Rails 3 username password in URL for authenticated Devise resource

I'm confused on why I can't get this to work in the browser. I want to test an authenticated Devise resource using a URL with the username and password in the URL as such
http://joe:1234#localhost:3000/blog/latest
It doesn't authenticate and instead redirects me to Devise login page. If however, I make it a json call, it works
http://joe:1234#localhost:3000/blog/latest.json
It also works if I test it using curl
curl http://joe:1234#localhost:3000/blog/latest
Thoughts?
Devise uses navigational formats to determine if it should issue a 401 when authenticating. JSON and XML requests will 401 by default. HTML request, however, will redirect to the login. To fix this, go to devise.rb in your initializers, uncomment this line and remove HTML from the array:
config.navigational_formats = [:"*/*", "*/*"]
May want to look into token authenticable from devise. This is probably the most effective way to pass credentials right out of the box with devise.
Token Authenticatable: signs in a user based on an authentication token (also known as “single access token”). The token can be given both through query string or HTTP Basic Authentication.
https://github.com/plataformatec/devise/
Going more in depth, and if you need a reusable strategy as this post suggest, here is a How-To: https://github.com/plataformatec/devise/wiki/How-To:-Use-HTTP-Authentication
Devise does have built in HTTP Basic Authentication yet you do need to have two little things in your app to have it working :
* :database_authenticatable strategy in your user/account model
* config.http_authenticatable = true in the devise initializer

Communicating with Rails application via POST after OmniAuth authentication

Hi I'm creating a project in which I use OmniAuth to authenticate a user. Its working correctly, except in my application I would like to send information to the server via javascript using POST.
However when I debug the application, I notice it cannot find the user if I send a request using POST - (I believe also the request.env["omniauth.auth"] variable does not exist according when I browsed at the breakpoint).
I'm outputting some debug information back to the application via JSON.
When I change the XMLHttpRequest to use GET, it works and I get back the correct information.
What is the correct usage, perhaps I have an incorrect route? I'm also not sure about using '_method' - would that help? Maybe I'm just looking in the wrong direction period?
How can I send via POST in javascript after authentication with OmniAuth and still retrieve the current_user
So the issue lies in the way protect_from_forgery works. What you'll have to do is validate that your request is safe and the forgery protection should be ignored, you can do this by implementing the forgery_whitelist? at your ApplicationController class:
def forgery_whitelist?
request.user_agent ~= /iPhone/ || self.current_user || super
end
At this method you can implement the logic to whitelist a request and make Rails ignore the forgery protection.

Resources