I am trying to get in place editing working but I am running into this error:
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken)
I understand that rails now wants to protect against forgery and that I need to pass a form authenticity token but I am not clear on how to do this with the in_place_edit plugin.
This isn't a complete tested answer, but I took a look at the plugin code, and it looks like you could use the :with option to tack the authenticity token onto the end of the request parameters. Something along the lines of:
in_place_editor("my_element", :with => "form.serialize() + '&authenticity_token=#{form_authenticity_token}';")
(I have not tested the above code).
I found a solution. I put the instructions here. Take a look at the part on patching in_place_edit.
Related
I have a project where I am setting up a Rails API with Graphql and React/Apollo. I've purpled all the google links looking for the best authentication solution, but it seems I haven't been able to find a clear answer.
I settled on using the graphql_devise gem, which leverages devise & devise_token_auth. I would have preferred to find a JWT solution, but just couldn't. (If you have any obvious suggestions please tell me!)
First I mounted a separate auth route, but ran into problems with multiple endpoints when I was setting up ApolloClient. I couldn't figure out how to direct auth related requests to my auth endpoint, while letting the rest go through to my graphql one. (If figuring this out is the easiest solution, please tell me!) Instead, I mounted the auth routes in my own schema, as instructed by the docs:
class MyApiSchema < GraphQL::Schema
use GraphqlDevise::SchemaPlugin.new(
query: Types::QueryType,
mutation: Types::MutationType,
resource_loaders: [
GraphqlDevise::ResourceLoader.new('User', only: [:login, :logout])
]
)
mutation(Types::MutationType)
query(Types::QueryType)
And edited the execute line in graphql_controller.rb:
result = MyApiSchema.execute(query, variables: variables, context: graphql_context(:user), operation_name: operation_name)
At this point, running a test query in postman is successful. I can access the graphql route with a userLogin mutation without any headers set, and get a successful response with client, uid & token. Authentication of my other queries also works—success with headers, denied without.
But when I try to perform the same queries using useQuery in react, it doesn't work. In the Apollo Client Developer Tools plugin in Chrome, it doesn't work either, returning only [Object object]. By looking at the request in my Network tab, I can see that this is the result of the same error: "photo field requires authentication".
When I pry into the rails server, I can see that the headers are being received. I can even authenticate the user manually in my graphql_controller before the execute method is called, so I don't think that it is a CORS issue. I have set up the rack-cors gem in Rails to expose the required headers.
When I drill into the code, it seems that the graphql_devise method set_current_resource is failing to return my user. This seems to stem from the devise method set_user_by_token, but I have not been able to figure out why it is failing.
If anyone has any experience with implementing this gem & stack, I would very much appreciate your input! If you have a better way of approaching authentication, I'd love to know what your strategy is. If you can help me solve this ... field requires authentication error, I will love you forever.
Apologies if I've provided too much/too little info, or if my question is too vague. Please let me know if there's something specific I should know to ask/show in my code. Hope you can help! Thanks.
I've managed to find the issue, and I thought I'd explain.
Having traced the problem to the set_user_by_token method in the devise_token_auth gem, I bundle open devise_token_auth'd, and put a byebug inside. This revealed that #token.token was not being extracted correctly from the headers.
The problem was that my header access-token was somehow being converted to accessToken, so when devise tried to set the token info from the request headers using this key, it returned nil.
I do not know why or where this conversion takes place. I suspect it originates from Apollo/React rather than Rails, since the headers on my postman query were not altered. In react, when I set the headers they are set with access-token, as below, but it seems that at some point in the life of my request they are changed.
How I have set the headers in React:
const client = new ApolloClient({
cache,
link: new HttpLink({
uri: 'http://localhost:3000/graphql',
headers: {
accessToken: localStorage.getItem('access-token'),
client: localStorage.getItem('client'),
uid: localStorage.getItem('uid')
},
}),
});
The keys that devise_token_auth uses to select the headers from the request can be changed in the initializers/devise_token_auth.rb file.
I edited them as follows:
config.headers_names = {:'access-token' => 'accessToken',
:'client' => 'client',
:'expiry' => 'expiry',
:'uid' => 'uid',
:'token-type' => 'token-type' }
This means that my front-end is now working smoothly, and I can perform queries/mutations with authentication. However, now in my postman queries I have to change the header to accessToken if I want them to work.
It would be great to know exactly at what point my header from React is changed to camelCase, but for now, it's working. Hope this helps if anyone goes through the same frustrations!
I've been following the AngularJS Tutorial for Rails on Thinkster and right now I'm nearly at the end of User Authentication with Devise. The app seems to run properly on my local server, but when I look at the console I always see the message:
Failed to load resource: the server responded with a status of 401
(Unauthorized) http://localhost:3000/users/sign_in.json
A few sections of the tutorial have been outdated and I've found answers through here and blog posts, for example there was a routing error that required bundle update which had been addressed at the question AngularJS and Rails routing error. (it won't let me post all relevant links because I am a newbie so I can't post more than 2, but there were many small things like that so far in the tutorial).
So far I can't figure out why I'm getting the 401, why it's relevant when the app is still functional, and how to fix it.
I'm not completely sure which parts of the code would be relevant. I have the whole repo on github/KellyTeresa/angular-news but will be glad to pull out and add relevant code blocks if you can point me in the right direction.
You're probably missing your CSRF token, which is accessible as the form_authenticity_token variable in Rails. You can include it in your form like so:
<input name="authenticity_token" type="hidden" ng-model="myModal.token" ng-init="myModel.token='<%= form_authenticity_token %>'">
Then ensure your model has the token attributes like so:
$scope.myModel = {
email: $scope.email,
password: $scope.password,
token: $scope.token
}
I'm seeing this along with the 401 status codes in chrome devtools E.g.:
{error: "You need to sign in or sign up before continuing."}
and
{error: "Invalid email or password."}
I think these are 401 status codes returned when Devise is checking to see if we're logged in / trying to log us in.
I'm not sure whether they have a huge negative impact when left as is (they don't seem to) what the best way to handle them is (interceptors looks possible) but these looks like starting points:
https://github.com/cloudspace/angular_devise
https://technpol.wordpress.com/2013/09/23/angularjs-and-devise-authentication-with-a-rails-server/
in your config/initializers/devise.rb ensure you have changed
#config.navigational_formats = ['*/*', :html]
to
config.navigational_formats = ['*/*', :html, :json]
I am trying to read and display activities of a G+ user. Using Google oauth2 I could able to recieve the access_token of a user after authorization has completed.
I use google_plus gem to make calls to G+, i could able to recieve user information using below code
#person = GooglePlus::Person.get("user_id_goes_here", :key => "google_api_key_here")
but when i try to get the activities using below
activity = GooglePlus::Activity.get("user_id_goes_here")
i could able to see the below error,
i tried searching the web for a solution, and some suggest that the api call limit exceeded. (10,000 hits/day is default). But i am sure i have used this only with 20-30 calls today.
Any suggestions for this issue is appreciated.
FYI : I have just added config code for google_oauth2 in /config/initializers/omniauth.rb file as below provider :google_oauth2,Rails.application.config.client_id , Rails.application.config.client_secret
Note: Below is the screenshot when i try to authenticate with Oauth2.
I hope this doesnot include Google plus scope, to make it i know i should add {:scope => "REQUIRED_URL_HERE_GOOGLE_PLUS_RELATED"} in omniauth.rb. But not sure what url should i give in there.
Thanks,
Balan
The Google_Plus gem requires you to pass your app key with every request. You can either do this inline:
GooglePlus::Activity.get("user_id_goes_here", key: "api_key_goes_here")
Or set up a global variable in an initializer
GooglePlus.api_key = 'api_key_goes_here'
The examples in the gem spec assume you have included a global variable, and hence don't show the key: strings. This may be what is causing you problems?
In answer to your second question, you will need to specify a scope with your oauth requests. A list of scopes is given here https://developers.google.com/gdata/faq#AuthScopes, but it is worth noting that the url format seems to have changed from that published. Try https://www.googleapis.com/auth/xxxxx instead, where xxx is the service you require.
I could able to find a solution for my question..
1) Used {:scope => "https://www.googleapis.com/auth/plus.me"} in /config/initializers/omniauth.rb file
2) Used the code
activities = GooglePlus::Activity.for_person("user_id", :key => "GOOGLE_API_KEY").items
Hope someone will find this useful.
I tried the auto_complete text field in rails 2.3.3 and the server says it denied request because of no authenticity token. I can see that the helper doesn't automatically create a parameter for it.
How I can manually do this? And I do not want to disable forgery prevention for this autocomplete.
Honestly, disabling the forgery protection isn't a bad idea if you scope this to just JS.
def index
respond_to |format| do
format.html
format.js do
# your autocomplete code
end
end
end
Make your autocomplete call /things.js instead of /things.
As far as I understand it, forgery protection is not needed for JS responses, and ensuring your autocomplete uses a GET method should also solve your problem. You're displaying a list, you're not modifying state, so use a GET and use the js response.
The forgery prevention is part of the form helper, not the field helper. If you use the full RoR form helper it should work. If it doesn't, please edit your question to include the form code and I'll try to help.
having had a similar problem I found just adding ":method => :get" to the "text_field_with_auto_complete" tag fixed it (as per Brian) - I didn't need to disable forgery protection
I'm playing with the authlogic-example-app and I'm failing to get the email address from the OpenID provider (in my case: Google and Yahoo) when I register a user, resp. I get an empty response instead of an email address (check the comments in code below).
This is how my user model looks like (everything else looks like the "with_openid"-branch of the authlogic-example-app mentioned above). Besides the missing 'email', the openid-authentication-process works as expected:
class User < ActiveRecord::Base
acts_as_authentic do |c|
# not needed because I use OpenID
c.validate_login_field = false
# avoid failed validation before OpenID request
c.validate_email_field = false
# this one sets 'openid.sreg.required=email'
c.required_fields = [:email]
end
private
# overwriting the existing method in '/lib/authlogic_openid/acts_as_authentic.rb'
def map_openid_registration(registration)
# this is my problem: 'registration' is an empty hash
self.email ||= registration[:email] if respond_to?(:email) && !registration[:email].blank?
end
end
Any idea how to solve this? Has anyone here done this before using authlogic? Or even better: Do you have a working example?
Update: I checked the Google Account Authentication API and compared the request submitted by authlogic (using ruby-openid-gem and openid-authentication-plugin) with the example requests on the Google Account Authentication API docs:
Example request to authenticate and fetch email address by Google:
https://www.google.com/accounts/o8/ud
?openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0
&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select
&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select
&openid.return_to=http%3A%2F%2Fwww.example.com%2Fcheckauth
&openid.realm=http%3A%2F%2Fwww.example.com%2F
&openid.assoc_handle=ABSmpf6DNMw
&openid.mode=checkid_setup
&openid.ns.ext1=http%3A%2F%2Fopenid.net%2Fsrv%2Fax%2F1.0
&openid.ext1.mode=fetch_request
&openid.ext1.type.email=http%3A%2F%2Faxschema.org%2Fcontact%2Femail
&openid.ext1.required=email
Request submitted by my appliation:
https://www.google.com/accounts/o8/ud
?openid.assoc_handle=AOQobUcdICerEyK6SXJfukaz8ygXiBqF_gKXv68OBtPXmeafBSdZ6576
&openid.ax.mode=fetch_request
&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select
&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select
&openid.mode=checkid_setup
&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0
&openid.ns.ax=http%3A%2F%2Fopenid.net%2Fsrv%2Fax%2F1.0
&openid.ns.sreg=http%3A%2F%2Fopenid.net%2Fextensions%2Fsreg%2F1.1
&openid.realm=http%3A%2F%2Flocalhost%3A3000%2F
&openid.return_to=http%3A%2F%2Flocalhost%3A3000%2Faccount%3Ffor_model%3D1%26_method%3Dpost%26open_id_complete%3D1
&openid.sreg.required=email
While debugging the whole setup, I've found out that the openid-authentication-plugin never receives an email in the response it receives from the openid provider, this at least explains why the registration hash in my user-model is empty...
UPDATE: If you're playing around with authlogic and openid, don't forget to check out the latest railscast on this subject!
As nobody could help me, I helped myself. :-)
The short answer to my question is:
c.required_fields = [:email,"http://axschema.org/contact/email"]
Using this line, the application requests the email-address using sreg and ax (request-type supported by Google).
You can find a more detailed answer and a working implementation of authlogic-openid with the Javascript OpenID-Selector right here:
http://github.com/vazqujav/authlogic_openid_selector_example/
While this pointed me in the right direction, what I needed was:
c.openid_required_fields = [:email,"http://axschema.org/contact/email"]
This pulled in the email and set it.
# fetch email by ax
c.openid_required_fields = [
"http://axschema.org/contact/email",
"http://axschema.org/namePerson/first",
"http://axschema.org/namePerson/last",
"http://axschema.org/contact/country/home",
"http://axschema.org/pref/language"
]
This fetches in multiple values as specified # http://code.google.com/apis/accounts/docs/OpenID.html#Parameters
Though I'm still unable to fetch in the country name... name, email, language works perfectly!
Test against an OpenID server you control, since it'll let you debug every part of the OpenID sequence. There are no guarantees that Google's OpenID provider is doing the right thing. Try checking against Verisign's server, since I'm pretty sure that one at least should do the right thing with the openid.sreg.required=email field.
Your code snippet looks right to me.
the thing is i am able to fetch the parameters from the provider but am not able to extract them from the response...
i have used OpenID::AX::FetchResponse.from_success_response(open_id_response)
as the object to hold the response... what method do i use to extract email,nickname,country,etc...