App\Middleware\Auth

Auth Middleware

This class is included with the starter site and is intended as a starting point or template for authentication and provides a number of options for creating secure sites using authentication. This class secure by design and can be used without making any changes or you can remove features that you do not need to reduce the size of the code or to help understand various security options in greater detail.

By default this class uses JSON Web Tokens (JWT) with a 1 hour timeout and session cookie for the storage format. Request and Response headers using a Bearer Token are also included for authentication with API’s and Web Services. In addition to JWT this class supports Signed Cookies, Encrypted Cookies, and PHP Sessions. To change the storage format modify the private [$method] property of this class.

A new token/cookie will be sent to the client with each response so that the user can keep browsing the site as long as they remain active within the expiration time.

When first used this class will create a [.env] file with secure config settings, a SQLite database for users, and a demo admin user. LDAP can be used for network validation (for example: Windows Active Directory on a Corporate Network) instead of a database by modifying the private [$type] property of this class. To use your own database instead of SQLite search for "connectToDb" to find where SQLite is used and then modify the code.

Public functions for routing and for filtering routes:
    login($app, $lang)
    logout($app)
    hasAccess($app)

Public functions for editing users in the demo db:
    addUser($app, $login, $password)
    updateUser($app, $login, $new_password)
    deleteUser($app, $login)

See also:
    setupDemo()
    validateDbUser()
    validateLdapUser()
    How this class is used from [app/app.php], search for "Auth."

IMPORTANT - By default the function [connectToDb()] creates a default user with a known password for the demo so if you end up using this class without making any changes then you MUST change the password on the example Admin user to a strong password or delete the user. This can be done with a temporary route on your site by copying and modifying the example code below:

    $app->get('/admin/update-user', function() use ($app) {
        $auth = new \App\Middleware\Auth();
        return $auth->addUser($app, 'name', 'password');
        return $auth->updateUser($app, 'name', 'new_password');
        return $auth->deleteUser($app, 'name');
    });

Or define routes for a localhost admin user, example:

    $app->get('/auth/add/:name/:password', 'Auth.addUser')->filter('Env.isLocalhost');
    $app->get('/auth/update/:name/:new_password', 'Auth.updateUser')->filter('Env.isLocalhost');
    $app->get('/auth/delete/:name', 'Auth.deleteUser')->filter('Env.isLocalhost');

Source Code

GitHub

Example Code

Starter Site Middleware


// The FastSitePHP Starter Site includes several examples pages and provides
// a basic directory/file structure. The site is designed to provide structure
// for basic content (JavaScript, CSS, etc) while remaining small in size so
// that it is easy to remove files you don’t need and customize it for your site.
//
//     https://github.com/fastsitephp/starter-site
//
// Core Middleware classes are provided and can be modified for your site.
//
// To use them specify the 'Class.method' on route filter functions or
// when mounting additional files.

// Require a user to be logged in in order to use a page
$app->get('/secure-page', 'SecureController')->filter('Auth.hasAccess');

// Require an authenticated user and use CORS
$app
    ->get('/api/:record_type', 'ApiController.getData')
    ->filter('Cors.acceptAuth')
    ->filter('Auth.hasAccess');

// Only run a route from localhost
$app->get('/server-info', function() {
    phpinfo();
})
->filter('Env.isLocalhost');

// Only load a file if running from localhost
$app->mount('/sysinfo/', 'routes-sysinfo.php', 'Env.isLocalhost');

Methods

hasAccess(Application $app)

Check if a user has access based on the Request. This function is intended to be used as a route filter function. If the user does not have access this function will return a 401 Unauthorized Response with a login page.

If the request header [Content-Type] = 'application/json' and the user does not have access then a 401 JSON Response will returned instead of the login page.

Returns: bool

login(Application $app, $lang)

Login method. Returns a JSON response for the login page.

In the starter site template this is called from the URL:
  POST '/:lang/auth/login'

Returns: Response

logout(Application $app, $lang = null)

Logout and redirect to the site root URL.

In the starter site template this is called from the URL:
  GET|POST|{ANY} '/auth/logout'

When JWT, Signed Cookies, or Encrypted Cookies are used the previously used Access Token will still be valid until it expires (or unless the site config crypto keys or settings are changed). The logout feature is simply intended for websites so a user can logout. As long as HTTPS is used then the previous token cannot be monitored and will be cleared from the browser cache on logout. This is by design because tokens are not invalidated from this class once a user logs out. If you need to track tokens per user and include additional limitations then this would be part of the logic for your app.

Returns: Response

addUser(Application $app, $login, $password)

Add a user to the example SQLite database

Returns: array

updateUser(Application $app, $login, $new_password)

Change the password for a user in the example SQLite database

Returns: array

deleteUser(Application $app, $login)

Delete a user from the example SQLite database

Returns: array

validateDbUser($app, $login, $password)

Validate a user and password using a Database. This example uses the demo SQLite Db that is created by this class and can be easily modified to support other databases.

Returns: bool

validateLdapUser($login, $password)

Validate a user and password using LDAP. This would be commonly used to validate users on a corporate network (for example a Windows Domain).

Returns: bool