Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Inferno JS: Build and Authenticate an App - Part III

DZone's Guide to

Inferno JS: Build and Authenticate an App - Part III

In Part III we are finally going to be wrapping up by authenticating our app using Auth0.

· Web Dev Zone
Free Resource

Discover how to focus on operators for Reactive Programming and how they are essential to react to data in your application.  Brought to you in partnership with Wakanda

Don't forget to read Parts I and II before jumping in!

Authenticate an Inferno App With Auth0

The last thing we'll do is add Auth0 authentication to our Inferno app. At the moment, our sample dinosaur API doesn't have any secured endpoints—but if we need them in the future, Auth0's JSON Web Token authentication can help.

Inferno app with Auth0 JWT authentication

Configure Your Auth0 Client

The first thing you'll need is an Auth0 account. Follow these simple steps to get started:

  1. Sign up for a free Auth0 account.
  2. In your Auth0 Dashboard, create a new client.
  3. Name your new app and select "Single Page Web Applications".
  4. In the Settings for your newly created app, add http://localhost:3000 to the Allowed Callback URLs and Allowed Origins (CORS).
  5. If you'd like, you can set up some social connections. You can then enable them for your app in the Client options under the Connections tab. The example shown in the screenshot above utilizes username/password database, Facebook, Google, and Twitter.

Add Authentication Logic to Inferno App

Use npm to install auth0-lock:

$ npm install auth0-lock --save

Now that auth0-lock is installed, we can use it in our App.js file to implement authentication logic. We'll also need to create two new components, Login and User. These components are referenced in App.js below.

// src/App.js

...
import Auth0Lock from 'auth0-lock';
import Login from './components/Login/Login';
import User from './components/User/User';

function logOut(instance) {
  // Remove token and profile from state
  // (using instance passed in by linkEvent to preserve "this" context)
  instance.setState({
    idToken: null,
    profile: null
  });

  // Remove token and profile from localStorage
  localStorage.removeItem('id_token');
  localStorage.removeItem('profile');
}

class App extends Component {
  constructor() {
    super();

    // Initial authentication state:
    // check for existing token and profile
    this.state = {
      idToken: localStorage.getItem('id_token'),
      profile: JSON.parse(localStorage.getItem('profile'))
    };
  }

  componentDidMount() {
    // Create Auth0 Lock instance
    this.lock = new Auth0Lock('[YOUR_CLIENT_ID]', '[YOUR_DOMAIN].auth0.com');

    // On successful authentication:
    this.lock.on('authenticated', (authResult) => {
      // Use the returned token to fetch user profile
      this.lock.getUserInfo(authResult.accessToken, (error, profile) => {
        if (error) { return; }

        // Save token and profile to state
        this.setState({
          idToken: authResult.accessToken,
          profile: profile
        });

        // Save token and profile to localStorage
        localStorage.setItem('id_token', this.state.idToken);
        localStorage.setItem('profile', JSON.stringify(profile));
      });
    });

    // GET list of dinosaurs from API
    ...
  }

  render(props, state) {
    return(
      <div className="App">
        <header className="App-header bg-primary clearfix">
          <div className="App-auth pull-right">
            {
              !state.idToken ? (
                <Login lock={this.lock} />
              ) : (
                <div className="App-auth-loggedIn">
                  <User profile={state.profile} />
                  <a
                    className="App-auth-loggedIn-logout"
                    onClick={linkEvent(this, logOut)}>Log Out</a>
                </div>
              )
            }
            </div>
          <h1 className="text-center">Dinosaurs</h1>
        </header>
        <div className="App-content container-fluid">
          ...
        </div>
      </div>
    );
  }
}

export default App;

Import auth0-lock as well as the new components we'll create, Login and User. Login will display a link that will launch the Auth0 Lock widget. User will display after login and show the authenticated user's name and picture.

In the constructor(), we'll check for an existing token and profile from a previous login and set them if available. In componentDidMount(), we'll create our Lock instance. Replace [YOUR_CLIENT_ID] and [YOUR_DOMAIN] with your Auth0 client information. On successful authentication, we'll do the following:

  • Use the access token to fetch user profile with lock.getUserInfo().
  • Save the token and profile to state.
  • Save the token and profile to localStorage to persist the session.

In the render() function, we'll add the Login and User components to the <header> element as well as a logout link. These will show conditionally based on the presence or absence of an access token. We'll pass properties to these components:

<Login lock={this.lock} />

and:

<User profile={state.profile} />

The logOut() function (pulled out near the top of the App.js file) clears the user's token and profile from state and removes this data from local storage.

Update App CSS

We'll add a few more styles to our App.css to support our new markup:

/* src/App.css */

...
.App-auth {
  font-size: 12px;
  padding: 20px 10px;
}
.App-auth a {
  color: #fff;
  cursor: pointer;
  display: inline-block;
}
.App-auth a:hover {
  color: #fff;
}
.App-auth-loggedIn-logout {
  border-left: 1px solid rgba(255,255,255,.6);
  margin-left: 4px;
  padding-left: 4px;
}

Create Login Component

Next we'll create the Login component. When the user is logged out, the app will have a "Log In" link in the header like so:

Inferno app with login link

Add the necessary folder and files for our Login component:

src
  |-components |-Login
      |-Login.css |-Login.js

Our Login.js should look like this:

// src/components/Login/Login.js

import Inferno, { linkEvent } from 'inferno';
import Component from 'inferno-component';
import './Login.css';

// Use the "lock" prop passed in App.js to
// show the Auth0 Lock widget so users can log in
function showLock(instance) {
  instance.props.lock.show();
}

class Login extends Component {
  render() {
    return(
      <div className="Login"> <a onClick={linkEvent(this, showLock)}>Log In</a> </div>
    );
  }
}

export default Login;

We passed our App.js's Lock instance to Login so we could access its show() method. The Login component has a link that shows the Lock widget when clicked.

We'll add just a little bit of CSS to support this component:

/* src/components/Login/Login.css */

.Login {
  padding: 10px 0;
}

Create User Component

Finally, we'll build the User component. This will show the user's profile picture and name when authenticated:

Inferno app with login link

Add the necessary folder and files for our User component:

src
  |-components |-User
      |-User.css |-User.js

The User.js file should look like this:

// src/components/User/User.js

import Inferno from 'inferno';
import Component from 'inferno-component';
import './User.css';

class User extends Component {
  render(props) {
    let profile = props.profile;
    let idp = profile.user_id.split('|')[0];

    return(
      <div className="User" title={idp}> <img src={profile.picture} alt={profile.name} /> <span>{profile.name}</span> </div> ); } } export default User; 

We'll display the user's picture and name. As a bonus, we can add a title attribute that shows the identity provider that the user signed in with (ie.: twitter, facebook, etc.).

Add a few styles to User.css for alignment and a circular profile image:

/* src/components/User/User.css */

.User {
  display: inline-block;
}
.User img {
  border-radius: 100px;
  display: inline-block;
  height: 36px;
  margin-right: 6px;
  width: 36px;
}

We now have working authentication in our Inferno app. In the future, we can use identity management to secure routes, conditionally render UI, control user access, and more. Check out these additional resources to learn about packages and tutorials that will be helpful for authentication with Inferno / React-like apps:

Conclusion

We've learned how to create a basic real-world application with Inferno. We've also explored some of the features Inferno has that its predecessors lack, such as linkEvent. We've demonstrated how simple it can be to utilize Inferno with external methods. Inferno author Dominic Gannaway's favorite feature is lifecycle hooks for functional components, something we didn't explore in this tutorial but should certainly be utilized by developers who prefer a functional component approach.

To learn more about the Inferno JS library, you can get in touch with the community and development team by checking out the Inferno GitHub and the Inferno Slack.

If you're a JavaScript developer trying to improve performance and reduce filesize in your web apps, check out Inferno. Even if you don't have React experience, Inferno is easy to learn thanks to the abundance of React resources and tutorials available. Hopefully you're now ready to get started with Inferno in your projects!

Learn how divergent branches can appear in your repository and how to better understand why they are called “branches".  Brought to you in partnership with Wakanda

Topics:
inferno ,auth0 ,authentication ,web dev ,javascript

Published at DZone with permission of Kim Maida, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}