I have a Rails app that uses Google SSO to sign in / up users. It works fine in Safari, but in Chrome I keep getting this error:
Blocked a frame with origin "[domain]" from accessing a frame with origin "https://accounts.google.com". Protocols, domains, and ports must match.
I have previously used this "solution" to solve it: https://github.com/zquestz/omniauth-google-oauth2/issues/122#issuecomment-60510241
But I recently noticed that it suddenly stopped working for Safari with the above solution instead.
My current implementation looks like this (coffee script):
$(document).ready ->
$.ajax
url: 'https://apis.google.com/js/client:plus.js?onload=gpAsyncInit'
dataType: 'script'
cache: false
window.gpAsyncInit = ->
$('.googleplus-login').click (e) ->
e.preventDefault()
gapi.auth.authorize {
immediate: false
response_type: 'code'
cookie_policy: 'single_host_origin'
client_id: '[id]'
scope: 'email profile'
}, (response) ->
if response and !response.error
# google authentication succeed, now post data to server and handle data securely
jQuery.ajax
type: 'POST'
url: '/auth/google_oauth2/callback'
dataType: 'json'
data: response
success: (json) ->
# response from server
[this doesn't happen]
return
else
# google authentication failed
I haven't seen this error described anywhere in Google's documentation, so I'm not quite sure how to fix it.
I'm sure that I have the same protocol https
, so it must be something else. I'm guessing the domain.
I've seen that other sites (like Stack-overflow) uses a different flow where a popup isn't displayed but the user instead gets redirected to another page. Wonder if that could be a solution (and / or) the recommended way to do it to avoid my error.
In that case, where can I find documentation for this in Google's documentation jungle?
Update
This is the relevant parts of my controller code.
def google_authentication
respond_to do |format|
code = params[:code]
unless code.blank?
[..]
load = { code: code, client_id: client_id, client_secret: client_secret, grant_type: grant_type, redirect_uri: redirect_uri }
url = "https://www.googleapis.com/oauth2/v3/token/"
response = HTTParty.post(url, :query => load, headers: { "content-type" => "application/x-www-form-urlencoded"})
json = JSON.parse(response.body)
unless json.nil?
unless json["error"].present?
[..]
email = decoded_hash["email"]
user = User.find_by_email(email)
if user
sign_in_existing_user(user)
format.json { render :json => {:status => "Success", user_id: "# {user.id}"} }
else
# Create user
[..]
format.html { redirect_to current_user, notice: "Welcome #{current_user.name}!" }
format.json { render :json => {:status => "Success", user_id: "#{current_user.id}"} }
end
else
#format.html { redirect_to root_path, error: "Could not sign up / in" }
format.json { head :no_content }
end
end
end
end
end
I have updated my JS based on the answer below by @EugZol, to:
data: {access_token: response['access_token'], error: response['error'], expires_in: response['expires_in']}
And I'm currently getting the following error:
Started POST "/auth/google_oauth2/callback" [..]
Processing by UsersController#google_authentication as JSON
Parameters: {"expires_in"=>"86400", "provider"=>"google_oauth2"}
Completed 406 Not Acceptable in 1ms (ActiveRecord: 0.0ms)
ActionController::UnknownFormat (ActionController::UnknownFormat):
app/controllers/users_controller.rb:237:in `google_authentication'
The only thing I could assume that here, when you are trying to make request to your own server:
data: response
...your code is accessing in an indirect way a frame created by GAPI. I.e., response
object references in one of its internal fields that frame, and jQuery is trying to serialize that.
The solution is to pick required fields manually:
data: {
state: response['state'],
code: response['code'],
scope: response['scope'],
client_id: response['client_id'],
g_user_cookie_policy: response['g_user_cookie_policy']
}