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

Building an App With Nette and Adding Authentication, Part 2

DZone's Guide to

Building an App With Nette and Adding Authentication, Part 2

In this article, a web developer uses a freely available tool to add authentication to a web application, using PHP to implement our security layer.

· Security Zone
Free Resource

Discover how to provide active runtime protection for your web applications from known and unknown vulnerabilities including Remote Code Execution Attacks.

Welcome back! If you missed Part 1 in which we built a web app using Nette, check it out here

Setting Up Authentication With Auth0

Auth0 issues JSON Web Tokens on every login for your users. This means that you can have a solid identity infrastructure, including single sign-on, user management, support for social identity providers (Facebook, GitHub, Twitter, etc.), enterprise identity providers (Active Directory, LDAP, SAML, etc.) and your own database of users with just a few lines of code.

We can easily set up authentication in our Nette apps by using Auth0. If you don't already have an Auth0 account, sign up for one now for free.

  • Navigate to the Auth0 management dashboard.
  • Create a new client and select the type of app as Regular Web Applications.
  • Take note of the client_id, domain, and secret. You'll need it soon.

Step 1: Install and Configure Auth0 PHP Package

Go ahead and install the official Auth0 PHP Plugin via composer.

composer require auth0/auth0-php

Step 2: Register Auth0 as a Nette Service

Head over to app/config/config.neon and add the following under services::

auth0: Auth0\SDK\Auth0([
    'domain' : '{AUTH0_TENANT_DOMAIN}',
    'client_id' : '{AUTH0_REGULAR_WEBSITE_CLIENT_ID}',
    'client_secret' : '{AUTH0_REGULAR_WEBSITE_CLIENT_SECRET}',
    'redirect_uri' : 'http://localhost:8000/callback',
    'persist_user' : false,
    'store': false
    'debug' : true
  ])

We need to create a new presenter, AuthenticationPresenter to handle our authentication logic.

app/presenters/AuthenticationPresenter.php

<?php

namespace App\Presenters;

use \Tracy\Debugger;
use \Nette\Http\IResponse;
use \Nette\Application\UI\Presenter;
use \Nette\Application\BadRequestException;
use \Nette\Security\AuthenticationException;

class AuthenticationPresenter extends Presenter {

  /** @var \Auth0\SDK\Auth0 @inject */
  public $auth0;

  public function actionLogin() {
    $this->auth0->login();
  }

  public function actionLogout() {
    $this->auth0->logout();
    $this->getUser()->logout();

    $this->redirect('Homepage:');
  }

  public function actionCallback($code) {
    try {
      $this->getUser()->login($code);

      $this->redirect('Homepage:');
    } catch (AuthenticationException $e) {
      Debugger::log($e, Debugger::ERROR);
      throw new ForbiddenRequestException('User not authenticated', IResponse::S403_FORBIDDEN, $e);
    }
  }

}

In the code above, you can see that the Auth0 service is being injected into the presenter using the @inject annotation. The actionLogin method is responsible for invoking the login function that will redirect the user to the Auth0 hosted login page.

The actionLogout method is responsible for clearing the sessions and any Auth0 data stored in the app. It logs the user out and redirects back to the home page.

The actionCallback method is responsible for handling the authentication flow. When the authentication is successful from Auth0, it performs a client credential exchange and returns an authorization code.

Step 3: Configure Auth0 Authenticator

Head over to app/config/config.neon and add the following under services::

services:
  auth0Authenticator: App\Model\Auth0Authenticator

Now, create a model/Auth0Authenticator.php file inside the app directory.

Add code to the file like this:

<?php

namespace App\Model;

use \Tracy\Debugger;
use \Auth0\SDK\Auth0;
use \Nette\Security\Identity;
use \Nette\Security\IIdentity;
use \Nette\Security\IAuthenticator;
use \Nette\Security\AuthenticationException;

class Auth0Authenticator implements IAuthenticator {

  /** @var \Auth0\SDK\Auth0 */
  private $auth0;

  public function __construct(Auth0 $auth0) {
    $this->auth0 = $auth0;
  }

  /**
   *  @param $args[0] Authorization Code
   *  @throws AuthenticationException
   */
  public function authenticate(array $args) : IIdentity {
    if (sizeof($args) > 0 && !empty($args[0])) {
      $code = $args[0];

      if ($this->auth0->exchange()) {
        return new Identity($this->auth0->getUser()['email'], NULL, $this->auth0->getUser());
      } else {
        throw new AuthenticationException('Auth0 code not exchanged successfully; user not authenticated.');
      }
    } else {
      throw new AuthenticationException('Auth0 code not provided; user not authenticated.');
    }
  }

}

This is where the credentials exchange happen, and the user info is gotten from Auth0 and injected into Nette via the Identity class.

Step 4: Configure Routing

The default login and logout routes are /authentication/login, and /authentication/logout respectively. We'll change them to /login and /logout respectively.

Open up app/router/RouterFactory.php and add the following routes:

...
$router[] = new Route('login', 'Authentication:login');
$router[] = new Route('logout', 'Authentication:logout');
$router[] = new Route('callback', 'Authentication:callback');
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');

We also added the callback route.

Note: Head over to your Auth0 client and configure the callback route in Allowed Callback URLs.

Add Callback Route

Step 5: Configure The View

Head over to app/presenters/templates/Homepage/default.latte and replace everything with the code below:

{block content}
    <h1 n:block="title"></h1>

    <div class="container">
      <div class="row">
          <div class="col-md-10 col-md-offset-1">
            {if $user->isLoggedIn()}
            <div class="panel panel-info">
              <div class="panel-heading">You are now logged in, {$user->getIdentity()->nickname} </div>
            </div>
            {/if}
            <div class="panel panel-success">
              <div class="panel-heading">List of Game of Thrones Characters</div>
              {if $user->isLoggedIn()}
                <table class="table">
                    <tr>
                        <th>Character</th>
                        <th>Real Name</th>
                    </tr>
                    {foreach $characters as $key => $value}
                      <tr>
                        <td>{$key}</td><td>{$value}</td>
                      </tr>
                    {/foreach}
                </table>
              {/if}
            </div>
            {if !$user->isLoggedIn()}
              <a href="{link Authentication:login}" class="btn btn-info"> You need to login to see the list ���� >></a>
            {/if}
            {if $user->isLoggedIn()}
              <a href="{link Authentication:logout}" class="btn btn-info"> Logout >></a>
            {/if}
          </div>
      </div>
    </div>
{/block}

In the code above, we have some variables and function call:

  • $user->isLoggedIn(): The $user variable is an object that is injected into the templates by default from Nette presenters and components. It represents the user. There are methods that can be called on it such as isLoggedIn, login, logout, etc. Here, we use to determine if the user is logged in or not.
  • $user->getIdentity()->nickname: The $user->getIdentity() function call is used to get the identity of the user. Identity represents a set of user information, as returned by the authenticator in use. In our app, we used a custom authenticator, auth0Authenticator. And that gives us the full range of user information that Auth0 returns. Therefore, we can access every Auth0 user attribute like so:
$user->getIdentity()->nickname // returns user name
$user->getIdentity()->email // returns user email

Note: Check out Nette's Access control for a deeper understanding of how the user object works.

Step 6: Run Your App

Now that everything is in place, go ahead and run your app.

Homepage

Auth0 Hosted Login

User is logged in

Wrapping Up

Well done! You have just built your first app with Nette. It focuses on simplicity, clarity and getting work done. As we saw in this tutorial, you can easily add authentication to your Nette apps.

This tutorial is designed to help you get started on building and adding authentication to your own apps with the Nette framework. You can leverage the knowledge gained here to build bigger and better apps.

Please, let me know if you have any questions or observations in the comment section. 

Find out how Waratek’s award-winning application security platform can improve the security of your new and legacy applications and platforms with no false positives, code changes or slowing your application.

Topics:
security ,authentication ,web application security

Published at DZone with permission of Prosper Otemuyiwa, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}