4

I've been scouring the inet trying to find anywhere that defines how to handle authentication in meteor and react router 4 .

Basically, I want certain routes to only be available to authenticated users. Is there any documentation on it?

Aseel

Asool
  • 7,423
  • 4
  • 25
  • 41
  • You can use [Accounts](https://docs.meteor.com/api/accounts.html) to indicate if the user is logged and [redirect](https://stackoverflow.com/questions/42123261/programmatically-navigate-using-react-router-v4) away from pages that are only allowed to logged in users. Note, that this is no replacement for [securing methods and publications](https://guide.meteor.com/security.html#checklist). – Jankapunkt Feb 21 '18 at 13:01

3 Answers3

6

Meteor has a very well developed User Accounts system. It provides ready libraries for OAuth authentication with Twitter, Facebook, etc. as well as a basic but useful UI packages. Check Meteor's official guide here first.

For implementing routing you need to track Meteor.userId() and change route via Meteor's reactive system called Tracker. Meteor.userId() returns a userId if currently connected user is logged in, and null otherwise. I provide an example code where React Router is used for routing, below. Notice that you'll will also need the historypackage to be installed and imported while working with React Router v4.

In your client/main.js;

import { Meteor } from 'meteor/meteor';
import React from 'react';
import ReactDOM from 'react-dom';
import { Tracker } from 'meteor/tracker'
import {onAuthChange, routes} from "../imports/routes/routes";


Tracker.autorun(function(){
    const authenticated = !! Meteor.userId();
    onAuthChange(authenticated);
});

Meteor.startup(() => {
    ReactDOM.render(routes, document.getElementById('app'));
});

And in your routes.js file;

import { Meteor } from 'meteor/meteor';
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import createBrowserHistory from 'history/createBrowserHistory'

import Home from './../ui/components/Home';
import Login from './../ui/components/Login';
import NotFound from './../ui/components/NotFound';
import Signup from './../ui/components/Signup';

const history = createBrowserHistory();
const unauthenticatedPages = ['/', '/signup'];
const authenticatedPages = ['/link'];

const publicPage = function  () {
    if (Meteor.userId()) {
        history.replace('/link');
    }
};

const privatePage = function  () {
    if(! Meteor.userId()) {
        history.replace('/');
    }
};

export const routes = (
    <Router history = {history}>
        <Switch>
          <Route exact path='/:id' component= {Login} onEnter={publicPage}/>
          <Route exact path='/signup' component={Signup} onEnter={publicPage}/>
          <Route exact path='/link' render={ () => <Home greet='User'/> } onEnter={privatePage} /> 
          <Route component={NotFound}/>
        </Switch>
    </Router>
);

export const onAuthChange = function (authenticated) {
    console.log("isAuthenticated: ", authenticated);
    const path = history.location.pathname;
    const isUnauthenticatedPage = unauthenticatedPages.includes(path);
    const isAuthenticatedPage = authenticatedPages.includes(path);
    if (authenticated && isUnauthenticatedPage) {   // pages: /signup and /
        console.log(`Authenticated user routed to the path /link`);
        history.replace('/link'); 
    } else if (!authenticated && isAuthenticatedPage) {
        console.log(`Unauthenticated user routed to the path /`);
        history.replace('/');
    }
};
Gokhan Karadag
  • 514
  • 6
  • 14
1

Here's a neat way to have public routes and authenticated routes: https://gist.github.com/lucnat/643988451c783a8428a2811dbea3d168

  • public components are visible by everyone, they use the PublicLayout
  • authenticated components are visible by authenticated users only - they use the AuthenticatedLayout

We could have an arbitrary number of layouts. In the example above, there are two layouts - each with it's own navbar.

Pueggel
  • 522
  • 4
  • 17
0

I've been trying to get a more updated method using functional components. I've tried implementing a conditional check similar to the documentation of React-router. This was working after giving history.push to a desired route after waiting for Meteor.loginWithPassword to complete. But refreshing the browser ended up rendering login page again.

Meteor is having an intermediate state of Meteor.loggingIn(). Handling this state in the Authentication check fixed this issue.

Feel free to give feedback.

I've created a gist with an implementation for authentication of routes in Meteor - React-router stack with functional components and hooks.

Check this gist with basic structure of the implementation. https://gist.github.com/rinturj84/0ef61005bf3a4ca5fb665dfc5f77e3d1

Ann Zen
  • 17,892
  • 6
  • 20
  • 39