Prisma 1 Forum

How to handle Redirect after signinUser?

I’m using Email-Password Auth to authenticate my users.
React and Apollo on the frontend.

All of my routes are going to be protected besides /login and /signup and therefore I am trying to end up with something like this from React Training.

I have only managed to get it partially working, the thing is when the user gets signed in I’m not able to retrieve data from this.props.data.user , which keeps the user on the /login page of course.

But if i do refresh the page, it will receive the data and redirect to whatever page the user was trying to access.

.
App.js:

...

import Login from './Login';

class App extends Component {

  _isLoggedIn = () => {
    return this.props.data.user;
  };

  render() {
    const PrivateRoute = ({ component: Component, ...rest }) => (
      <Route {...rest} render={props => (
        this._isLoggedIn() ? (
          <Component {...props}/>
        ) : (
          <Redirect to={{
            pathname: '/login',
            state: { from: props.location }
          }}/>
        )
      )}/>
    );

    if (this.props.data.loading) {
      return (<div>Loading</div>);
    }
    
    return (
      <div>
        <Route path="/login" component={Login}/>
        <PrivateRoute path="/protected" component={Protected}/>
      </div>
    )
  }
}

const GET_CURRENT_USER_ID = gql`
  query GetCurrentUsersHandlerIdQuery {
    user {
      id
    }
  }
`;

export default graphql(GET_CURRENT_USER_ID, { options: { fetchPolicy: 'network-only'}})(App);

.
Login.js:

...

class Login extends Component {
  state = {
    email: '',
    password: '',
    redirectToReferrer: false,
  }

  render() {
    const { from } = this.props.location.state || { from: { pathname: '/' } };
    const { redirectToReferrer } = this.state;
    
    if (redirectToReferrer) {
      return (
        <Redirect to={from}/>
      )
    }

    return (
      <div>
        <input
          value={this.state.email}
          onChange={(e) => this.setState({ email: e.target.value })}
          type='email'
        />
        <input
          value={this.state.password}
          onChange={(e) => this.setState({ password: e.target.value })}
          type='password'
        />
        <div onClick={() => this._confirm()}>login</div>
      </div>
    );
  }

  _confirm = async () => {
    const { email, password } = this.state;
    
    const result = await this.props.signinUserMutation({
      variables: {
        email,
        password,
      }
    });
    const token = result.data.signinUser.token;
    await this._saveUserData(token);
    this.setState({ redirectToReferrer: true });
  }

  _saveUserData = (token) => {
    localStorage.setItem('graphcool-auth-token', token);
  }

}

const SIGNIN_USER_MUTATION = gql`
  mutation SigninUserMutation($email: String!, $password: String!) {
    signinUser(
      email: {
        email: $email,
        password: $password
      }
    ) {
      token
    }
  }
`;

export default graphql(SIGNIN_USER_MUTATION, { name: 'signinUserMutation' })(Login);

Is the way I have done it all wrong and needs to be refactored completely? Or can I make it work with any minor changes?

Any help is much appreciated!

// Anton

I’ve implemented PrivateRoute like this:

import React, { Component } from 'react'
import { Route, Redirect } from 'react-router-dom'

export const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    localStorage.getItem('graphcool-auth-token') ? (
      <Component {...props}/>
    ) : (
      <Redirect to={{
        pathname: '/login',
        state: { from: props.location }
      }}/>
    )
  )}/>
)

So I don’t use props, I use localStorage.getItem directly.

1 Like

Fantastic, thanks!
It was pretty simple then.

A bit off topic. But do you encrypt the user password here before executing the signinUser mutation? If so how?

_confirm = async () => {
    const { email, password } = this.state;
    
    const result = await this.props.signinUserMutation({
      variables: {
        email,
        password,
      }
    });
    const token = result.data.signinUser.token;
    await this._saveUserData(token);
    this.setState({ redirectToReferrer: true });
  }

I didn’t use it with email/password, but with Facebook authentication. So I have no password to encrypt.