Using Subdomain as Parameter


#1

Hello,
I developed an application which is supposed to be used by teams and I’d like to use Subdomains as parameters for my application.
Example:
A user creates a “team” named X and invites some other users. The members of this team can only login via X.mywebsite.com and I want to pass X to the application to “filter” subscriptions.
I did some research and it seems that iron:router doesn’t support subdomains so I’m wondering if there is another way of doing what I want.

Thank you


Blog as a Subfolder instead of Subdomain
#2

You could use a proxy to convert calls to subdomains to specific paths on the meteor application. so proxy sees something like “testdomain.test.com/” but meteor sees “test.com/testdomain”.

I think that might work.


#3

@ricoshady yes, I also tought about that.
How would you avoid users to login into projects they don’t belong to? And how would you manage sessions? Once logged into their “teams” wouldn’t they be able to automatically login into other ones as the session is theorically the same?

Thank you


#4

I think this package may interest you regarding being able to login to only one team as well as doing a lot of what you’re trying to do.


#5

I solve this problem using iron-router and onRun hook:

Router.onRun(Hooks.detectDomains, {except: ["error"]});

Hooks.detectDomains simply check if subdomain is present in Site collection.

To make this working quickly I use also FastRender package to send data together with html.

Session is stored in localStorage so it is specific to subdomain, user logged in subdomain A won’t be logged to subdomain B.


#6

@parhelium What do you use to get the subdomain? Would you mind sharing the Hooks.detectDomains code?
If the subdomain is present in the Site collection how do you filter subscriptions? Do you just pass it as value in a variable?

Sorry for the many questions :grin:

Thank you


#7

Would you like to share Hooks.detectDomains? Or just turn it to be a package? Thx for your hard work on it though.


#8

i’d just second the request to see what you did in a bit more detail if you like to share - highly appreciated.


#9

Using a DNS wildcard to point *.example.com to my app server, I have this in the client code:

var hostnameArray = document.location.hostname.split( "." );

if ( hostnameArray[1] === "example" && hostnameArray[2] === "com" ) {
  var subdomain = hostnameArray[0];  
}

if ( subdomain ) {
  Meteor.call( "findTeamBySubdomain", subdomain, function (err, res) {
    var teamId = res;
    if ( teamId )
      Session.set( "teamId", teamId ); 
    }
  });
}

Tracker.autorun ( function () {
  Meteor.subscribe( "teamInfo", Session.get( "teamId" ) );
});

Seems to work pretty well.


#10

@babrahams aren’t there security problems setting the teamId as session variable as it’s editable by users?


#11

I’ve stripped everything down to the basics here, but yes, you need to check that the user has access rights to the team (in the publish function logic) before sending anything back to the client via the publication.

It doesn’t really matter how the data gets requested from the server – any request method can be faked from the client side – what you need is some strict access control logic on the server that gets run before passing anything back to the client.

If someone sets someone else’s teamId in the Session variable, the publish function needs to check that that user has access to the requested data and, if not, throw an error (or just publish nothing).


#12

I use FastRender to match every first request to subdomain ( on server side):

FastRender.onAllRoutes(function(path) {
        if(/(css|js|html|map)/.test(path)) {
            return;
        }
        // read headers to get subdomain -> domain = headers.host.split(":")[0]
        // _sites is hashmap stored in server memory 
        // for quick mapping of subdomain to Site document
        var site = getSite(this.headers, _sites);
        if(site){
            this.subscribe('site.details', site.domains.default );
            this.subscribe('product.groups');
            this.subscribe('version');
        }
    });

On client side:

Router.onRun(Hooks.detectDomains, {except: ["error"]});

Hooks.detectDomains = function(pause){ 
     //  subscription to Sites collection is done by server side
    var site = Sites.findOne({},{reactive:true});
    if(!site){
        Router.go("error");
        pause();
    }
}

Every user has access to Site document which keep all necessary information for further requests.
This approach performs well for 1 year. Hope that helps.
It is very important to use FastRender, because Site document is sent together with HTML so additional request to server is avoided.


#13

Surely the best way to do this is using

WebApp.connectHandlers.use( funciton(req, res, next) {
// Check the subdomain
});


#14
WebApp.connectHandlers.use( funciton(req, res, next) {
// Check the subdomain
});

this is a good but how can you run this? the meteor should be running and deployed to each subdomain or what???