[SOLVED] Single SignOn oAuth Blank Popup (cross-origin frame error)


#1

I have no idea why this is happening. We finally launched our app, everything works on the staging server, and then I deploy to an identical setup - and now this is happening - and I can’t figure out for the life of me WHY… I’ve tried everything.

You can see it happening for yourself: go to http://www.crunchyserial.com/

Here is the error in the console:

Uncaught DOMException: Blocked a frame with origin "http://www.crunchyserial.com" from accessing a cross-origin frame.
    at http://www.crunchyserial.com/packages/oauth/end_of_popup_response.js:18:39
    at http://www.crunchyserial.com/packages/oauth/end_of_popup_response.js:37:3

Here is the settings.json I use in my ./deploy directory for the production server:

{
  "public": {
    "analyticsSettings": {
      "Google Analytics" : {"trackingId": "//redacted//"}
    }
  },
  "private": {
    "oAuth": {
      "google": {
        "clientId": "//redacted//",
        "secret": "//redacted//",
        "loginStyle": "popup"
      },
      "facebook": {
        "appId": "//redacted//",
        "secret": "//redacted//",
        "loginStyle": "popup"
      },
      "twitter": {
        "consumerKey": "//redacted//",
        "secret": "//redacted//"
        "loginStyle": "popup"
      }
    }
  }

Oddly enough - there seems to be no difference between “popup” and “redirect” as the loginStyle… curious…

This is my mup.js:

module.exports = {
  servers: {
    one: {
      host: '//redacted//',
      username: 'ubuntu',
      pem: "//redacted//"
      // password:
      // or leave blank for authenticate from ssh-agent
    }
  },

  meteor: {
    name: 'CrunchySerial',
    path: '../../CrunchySerial',
    servers: {
      one: {}
    },
    buildOptions: {
      serverOnly: true,
    },
    env: {
      ROOT_URL: 'http://www.crunchyserial.com',
      MONGO_URL: 'mongodb://localhost/meteor'
    },

    dockerImage: 'abernix/meteord:base',
    deployCheckWaitTime: 400
  },

  mongo: {
    oplog: true,
    port: //redacted//,
    servers: {
      one: {},
    },
  },
};

I’ve tried the ROOT_URL with and without a / I’ve updated to all the latest versions… And I still have no idea why this is happening.

ANY help would be greatly appreciated. I’m willing to try anything at this point - we have a hard launch date tomorrow, and if this doesn’t work we’re just going to have to abandon the single-signon/oauth issue.


Solution:

Your oauth script will only work from one domain - and when you have a ROOT_URL, it uses this in the uri that your oauth certs need to work properly. So oauth will only work from ONE subdomain. You have to pick www or no-www. I chose to keep www and setup both a DNS redirect, and a programmatic redirect (just to be sure).

Here is my programmatic redirect:

//[project]/imports/startup/client/force_www_redirect.js
import { Meteor } from 'meteor/meteor'

Meteor.startup(function () {
    if (location.host.indexOf('www.crunchyserial.com') !== 0) {
        location = 'http://www.crunchyserial.com'
    }
})

and I just make sure this is the first code my client startup sees by importing it first.


#2

Does it work for the other services? Have you tried it over SSL?

Also, I don’t think you need service-configuration if you have properly set your values in settings.json


#3

All of them fail, except on the staging server where everything works fine.

I haven’t pushed the current code to the staging server, because everything is working over there. The only difference is the fact that the staging server is using slightly older versions (like it’s not on Meteor 1.5 yet)

I don’t own any SSL certificates.

I’m pretty sure you have to have service-configuration if you’re doing to use settings.json.


#4

Can you go back to an earlier version of Meteor?


#5

I was on an earlier version of meteor when the problem started.

Also, keep in mind - this was actually working… I went to bed, woke up the next day - and it wasn’t working anymore… Maybe this isn’t important… I don’t want to get distracted figuring out WHY this happened… I just want my code to work… lol


#6

Figuring out why it happened may shed light on it. Are you working from git? You could check your commit logs for anything suspicious

This is happening from all three providers?


#7

This happens from all three “providers” (facebook, google, twitter)

I am using git, I can roll back if I must, but rolling back will just put me where I was when the problem started. The difference between here and there is just upgrading Meteor and a few packages related to this problem.

I can get a dump of the server log, one second.

[00.00.00.00]{"line":"431","file":"oauth.js","message":"Error in OAuth Server: Failed to complete OAuth handshake with Google. failed [400] {   \"error\" : \"invalid_grant\",   \"error_description\" : \"Code was already redeemed.\" }","time":{"$date":1497382695634},"level":"warn"}
[00.00.00.00]Exception while invoking method 'login' Error: Failed to complete OAuth handshake with Google. failed [400] {   "error" : "invalid_grant",   "error_description" : "Code was already redeemed." }
[00.00.00.00]    at getTokens (packages/google-oauth/google_server.js:107:7)
    at Object.getServiceData [as handleOauthRequest] (packages/google-oauth/google_server.js:81:35)
    at OAuth._requestHandlers.(anonymous function) (packages/oauth2.js:27:31)
    at middleware (packages/oauth.js:203:5)
    at packages/oauth.js:176:5
{"line":"431","file":"oauth.js","message":"Error in OAuth Server: Failed to complete OAuth handshake with Google. failed [400] {   \"error\" : \"invalid_grant\",   \"error_description\" : \"Code was already redeemed.\" }","time":{"$date":1497382701056},"level":"warn"}
Exception while invoking method 'login' Error: Failed to complete OAuth handshake with Google. failed [400] {   "error" : "invalid_grant",   "error_description" : "Code was already redeemed." }
    at getTokens (packages/google-oauth/google_server.js:107:7)
    at Object.getServiceData [as handleOauthRequest] (packages/google-oauth/google_server.js:81:35)
    at OAuth._requestHandlers.(anonymous function) (packages/oauth2.js:27:31)
    at middleware (packages/oauth.js:203:5)
[00.00.00.00]    at packages/oauth.js:176:5

These “errors” only appear if you “refresh” the popup. Then, it closes and says “internal server error” on the login screen like so:

And when you look at the actual source code of the popup you can see that the oAuth is generating proper codes… so refreshing SHOULD fail - because the oAuth code has already been redeemed the first time.


#8

those are only showing errors for Google - is the same for facebook and twitter?

In my older app that I used with Facebook I have this in my settings:

  "public": {
    "facebook": {
      "permissions": [
        "public_profile",
        "email",
        "user_friends"
      ]
    }

#9

Yes, the errors are the same.

And thank you for posting your settings from your old app, but I don’t need any extra permissions and I don’t see how this addresses the issue at hand.


#10

I’m close to creating a bug for this, there are too many weird things happening. If I don’t get any traction on this by this evening I’m going to go ahead and submit a bug report.


#11

SOLVED!

It was the fact that crunchyserial.com != www.crunchyserial.com - UHG… I lost a week of my life to this.

I think that maybe we should put this in the meteor manual - also, there is no real documentation on the ROOT_URL, maybe we should have some documentation around what this is and how to set it, and also mention the “gotcha” I ran into here with the subdomain www and how that can complicate your life with oauth.

I also have this stackoverflow question documenting my solution: https://stackoverflow.com/questions/44530467/solved-meteor-single-signon-oauth-popup-is-blank-cross-origin-frame-error


#12

OMG, I hate when that happens. AAAAHHH!

I’m glad you got it working.

BTW, I once tried to implement an OAuth handler for WordPress, and found debugging that to be very difficult, and much of it was completely opaque. Better docs would be very nice!


#13

@autoschematic thanks for this… I am doing some testing on local server of a custom OAuth provider I have written with https://<somestring>.ngrok.io to tunnel back to my local host server… this issue seems to happen when I have ROOT_URL set to the https://<somestring>.ngrok.io so the domain/sub-domain is the same.
If I use localhost all works fine.

Any ideas?


#14

Gosh, I’m so far away from figuring this out right now that it’s not loading into the top of my mind. If you’re still experiencing problems with it I would be happy to have a brainstorming session with you on Google Hangouts to try and figure out a path forward - I’d have to review all of this code to load it into my brain “cognitive loading” as I call it (My RAM :wink: so that I can talk intelligently about it. You know how it is when you put something down for more than a week. Let me know if you need to do a hangout session or something.


#15

@autoschematic no worries, I solved it. it was on of the other params (call back URI) in the “state param”.


#16

Hello, I’m totally noob in web rules in general and I’m facing the same problem with my app. I hosted it at Heroku and now I have the same message as you had.

mofactsbr.herokuapp.com.br

This app uses a router so I didn’t understood how should I build that redirect that you proposed,

but if I understood something, my problem would be that my app is an http no-www and the answer is https…

would be it?