idlackage
idlackage

Reputation: 2863

Sending data from Express to React through a redirect

I have two apps that are linked: one acting as the server (express) on port 5000, and the other as the client (React) on port 3000. I want to send data from the server to the client--to a specific page.

Flow:

  1. User clicks 'login' on localhost:3000
  2. They are redirected to an external site that returns a code and redirects to localhost:5000/api/callback
  3. router.get('/api/callback') fetches an authorization token based on the code and then redirects to localhost:3000/dashboard (where a Dashboard component is shown via React Router)
  4. The dashboard saves the token in its state by grabbing it from the server
  5. The dashboard will then make calls to the server to get other data based on the token

I realize that this is quite convoluted but that's basically where I'm having trouble; I don't fully get how to make Express and React communicate properly.

In server.js:

router.get('/callback', async (req, res) => {
    const code = req.query.code;
    const token = await getAuthorizationTokenFromExternalSite(code);

    // Poor attempt to persist data
    res.cookie('token', token);

    // Poor attempt to let the user see this URL
    res.redirect("http://localhost:3000/dashboard");
});

router.get('/dashboard', (req, res) => {
    res.send({ token: req.cookies['token'] });
});

client/src/App.js

class App extends Component {

    render() {
        return(
            <BrowserRouter>
                <div>
                    <Route exact path="/" component={LoginPage} />
                    <Route path="/dashboard" component={Dashboard} />
                </div>
            </BrowserRouter>
        );
    }

}

export default App;

client/src/Dashboard.js

class Dashboard extends Component {

    state = { token: null };

    componentDidMount() {
        fetch('/api/dashboard')
          .then(res => this.setState({ token: res.token }));
    }

    render() {
        return(
            <div>
                Tis the Dashboard, the token is {this.state.token}.
            </div>
        );
    }

}

export default Dashboard;

What is the correct way to go about bringing the user back to localhost:3000 from the server, and then to pass on the necessary data?

Upvotes: 4

Views: 4757

Answers (1)

Catalyst
Catalyst

Reputation: 3227

I think it is pretty common to put this token in a hash in the #<token here> bit of the uri you redirect the user to the UI. The # segment of a uri is not sent to the backend server you redirect to so is somewhat better than just putting it behind ?. Then you can (in the ui) parse the token out and use it to make requests. Commonly by passing the http header Authorization: Bearer ${token}.

Putting it in a cookie can be OK if its http-only (which means the UI can't programmatically access it), and the backend knows to look at the cookie to get the token. This is more complex long term (in my opinion) than just passing the access token to the UI via the URL.

Reviewing flow/dynamics of auth; in case it turns out to be helpful:

  • User hits page
  • Clicks login, and is iredirected to login provider protal, or has a popup show
  • User enters data and submits it to a backend, which redirects them to the destination platform with a code. Often you can straight up deliver an access token to the UI at this point if you are trying to go serverless. This is based on config in the login provider's settings.
  • Your backend uses the code to request an access/refresh token.
  • Once you get the access/refresh tokens you save them securely, and then you have options:
    1. Hand over the access token directly to the UI in the redirect. So the UI can make requests directly to the provider you authorized with.
    2. Generate your own token (such as a JWT) and refresh token, and give these to the UI. If the UI wants data from the provider, they call your backend with your token, and you internally manage calls to the provider.

Option 2 can be easier if you have multiple providers to work with; e.g. facebook & google & dropbox, AND you have a server to manage the tokens. It is the more classic way of doing things.

Option 1 is serverless, just redirect back to your app and have the UI do whatever auth flow is necessary, managing the tokens and things in the UI code.

Upvotes: 5

Related Questions