Update 5/11/2016: Developing in Lumen? Check out my latest post: Lumen and Stormpath as your Mobile Backend.

We’re pretty excited by the rapid growth of new, lightweight frameworks for building microservices and APIs. First, they rapidly speed the development time for simple web applications, and they also support a flexible, developer-friendly architectural approach.

Lumen, a new project from the creator of Laravel, is one of these great new microframeworks. A leaner version of Laravel that uses some of the same components, it simplifies tasks common to web projects: routing, databases, queueing, and caching.

One of the challenges of micro-frameworks like Lumen, however, is that they often come with very little support for authentication and user management. Because they are designed for services and APIs, support for front-end packages like Bootstrap and functionality like sessions aren’t enabled by default, and authentication functionality can be limited. This can be a hitch for PHP developers who need, but don’t want to spend a lot of time building, user login and registration screens.

Wouldn’t it be nice if you could add authentication to your Lumen application in under 5 minutes? Well, with the new integration of Stormpath’s ID Site feature into our PHP SDK, it is now very simple. This post will show you exactly how to do it.

What is Stormpath ID Site?

Stormpath ID Site is a set of hosted user interface screens pre-built with common identity functions: user login and registration, and password reset. ID Site can be accessed via your own custom domain like id.mydomain.com and shared across multiple applications to create a seamless user experience across your products.

Although everything is pre-built, the screens and even the functionality of ID Site are completely customizable. You have full access to the screen source code so you can make simple changes like adding your own logo and changing CSS or more complex changes like adding fields, adding JavaScript code, and even adding/removing screens and changing how they behave.

Prepping Your System

The next bit of information is only needed if you are starting from scratch (and not included in our 5 minute parameters). Feel free to skip if you have a functional application, but here is how I get a Lumen project set up before I even get to any coding.

What You Need:

Composer is a package manager for PHP and I highly recommend for you to use it in your every day development. If you are unaware of Composer, this guide may be a little too advanced and I would suggest coming back after you check out the information available to you on their website

Local webserver

Lumen

A Free Stormpath Account

Create a Lumen project

The first thing you need to do is create a new Lumen project. This is a simple process with Composer. Open your project file in Terminal (or command prompt) and type composer global require "laravel/lumen-installer=~1.0" . This will install the Lumen installer. After the installer is finished, run the command lumen new my-php-project to create a new Lumen project.

Configure Your Lumen Project

Before we begin, a few configurations will make the Lumen project to behave the way we want it to.

Allow Dotenv to Load

For this project, I will use DOTENV package. This allows me to add my API keys in that file, so I don’t have to worry about what to do with them when I commit.

First, you will need to go into the bootstrap/app.php file and at the top, find the following line:

//Dotenv::load(__DIR__.'/../'); 1 2 //Dotenv::load(__DIR__.'/../');

On this line, replace the contents with the following.

Dotenv::makeMutable(); Dotenv::load(__DIR__.'/../'); Dotenv::makeImmutable(); 1 2 3 4 Dotenv : : makeMutable ( ) ; Dotenv : : load ( __DIR__ . '/../' ) ; Dotenv : : makeImmutable ( ) ;

With this change, we allow the .env file to load. Within the root of your project, you will find a .env.example file. Rename this file to .env ; Now, all key/value pairs in this file will be loaded into your environment variables

Note:

Lumen uses the vlucas/phpdotenv package from Packagist which allows you to set environment variables from a file. It is a very helpful package and I suggest looking it up to find out more.

Turn on Sessions

We will be using sessions in this example, but they are not on by default. To turn sessions on, Go back into your bootstrap/app.php file and find the lines that are commented with the following:

// $app->middleware([ // 'Illuminate\Cookie\Middleware\EncryptCookies', // 'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse', // 'Illuminate\Session\Middleware\StartSession', // 'Illuminate\View\Middleware\ShareErrorsFromSession', // 'Laravel\Lumen\Http\Middleware\VerifyCsrfToken', // ]); 1 2 3 4 5 6 7 8 // $app->middleware([ // 'Illuminate\Cookie\Middleware\EncryptCookies', // 'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse', // 'Illuminate\Session\Middleware\StartSession', // 'Illuminate\View\Middleware\ShareErrorsFromSession', // 'Laravel\Lumen\Http\Middleware\VerifyCsrfToken', // ]);

We want to allow sessions, so you will need to uncomment the line Illuminate\Session\Middleware\StartSession along with the opening and closing $app->middleware([ ])

Tip: For more information on middleware, Check out the Lumen Middleware Documentation

Install the Stormpath PHP SDK

Start the clock.

At the time of writing this article, the Stormpath PHP SDK is at 1.3.0-beta and can be found on Packagist. It is very easy to install with Composer for PHP package management.

There are a couple of ways to add a package to Composer for your project: 1) manually or 2) from the command line. If you want to do it manually, just open your composer.json file and add the line "stormpath/sdk": "1.3.0-beta" to the require section and then run composer update . To do it via the command line, just run the following command: composer require stormpath/sdk:1.3.0-beta and this will install the latest version of the sdk.

Congratulations! You now have access to the PHP SDK for Stormpath, which allows you to use ID site.

Configuration and API Keys

To use the Stormpath API, you will need to sign up for a Free Stormpath account – the core features of the API, as well as developer support and a good number of API calls every month are available to free Stormpath users.

API Keys are available from the Stormpath Dashboard. It is very easy to create new API Keys.

Go to the Stormpath Dashboard and on the right side of the page, you will see “Developer Tools” where you can manage your API keys. Click “Manage API Keys”. At the bottom of the Manage Keys page, find a button to create an API key: Doing so will remind you of some warnings. Keep the file safe, and you will only be able to download it once. Comfirming and creating the API key will begin the download. Make sure you save your API Key in a location where you can find it later. We will need it in a minute.

When you get the API Keys, open the file and add the info to the .env file, by adding this to the end of the .env file:

STORMPATH_ID={YOUR_API_ID_HERE} STORMPATH_SECRET={YOUR_API_SECRET_HERE} STORMPATH_APPLICATION={YOUR_APPLICATION_ID_HERE} 1 2 3 4 STORMPATH_ID = { YOUR_API_ID_HERE } STORMPATH_SECRET = { YOUR_API_SECRET_HERE } STORMPATH_APPLICATION = { YOUR_APPLICATION_ID_HERE }

Just change out the values match your keys. You will also need your Application ID for the configuration file to successfully use ID Site. The Application ID is a string found on in the Stormpath console. Stormpath console > Applications Tab > Select your application. The Details page will list the ID, which you can copy into your .env file.

Configuration ID Site Settings

While we are in the Stormpath console, we should also set up the callback URL for the application. For the sample application here, we are going to be sending users back to our site at the url http://localhost:8000/idSiteResponse . It is very important that you use the exact url that you want your site to respond to the callback. To set this up, go back into the Stormpath console and click on ID Site in the top menu:

Once you are in the settings, scroll down to the “Authorized Redirect URLs” section and paste in the exact url for the callback.



Creating the Routes

You will be using a total of six routes (url endpoints). These routes are:

/

/login

/logout

/register

/forgotPassword

/idSiteResponse

Go ahead and scaffold these out:

$app->get('/', function() { }); $app->get('login', function() { }); $app->get('logout', function() { }); $app->get('register', function() { }); $app->get('forgotPassword', function() { }); $app->get('idSiteResponse', function() { }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $ app - > get ( '/' , function ( ) { } ) ; $ app - > get ( 'login' , function ( ) { } ) ; $ app - > get ( 'logout' , function ( ) { } ) ; $ app - > get ( 'register' , function ( ) { } ) ; $ app - > get ( 'forgotPassword' , function ( ) { } ) ; $ app - > get ( 'idSiteResponse' , function ( ) { } ) ;

Now your project should start to look like an application with authentication. No? Then, let’s prep the homepage view. Lumen uses the idea of views, but by default the homepage view is returned from a function. To change this, create a new file resources/views/welcome.php with the following:

<title>Lumen</title> body { margin: 0; padding: 0; width: 100%; height: 100%; color: #B0BEC5; display: table; font-weight: 100; font-family: 'Lato'; } .container { text-align: center; display: table-cell; vertical-align: middle; } .content { text-align: center; display: inline-block; } .title { font-size: 96px; margin-bottom: 40px; } .quote { font-size: 24px; } <div class="container"> <nav> Welcome, givenName; ?> | <a href="/logout">Logout</a> <a href="/login">Login</a> | <a href="/register">Register</a> | <a href="/forgotPassword">Forgot Password</a> </nav> <div class="content"> <div class="title">Lumen.</div> </div> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 < title > Lumen < / title > body { margin : 0 ; padding : 0 ; width : 100 % ; height : 100 % ; color : #B0BEC5; display : table ; font - weight : 100 ; font - family : 'Lato' ; } . container { text - align : center ; display : table - cell ; vertical - align : middle ; } . content { text - align : center ; display : inline - block ; } . title { font - size : 96px ; margin - bottom : 40px ; } . quote { font - size : 24px ; } < div class = "container" > < nav > Welcome , givenName ; ? > | < a href = "/logout" > Logout < / a > < a href = "/login" > Login < / a > | < a href = "/register" > Register < / a > | < a href = "/forgotPassword" > Forgot Password < / a > < / nav > < div class = "content" > < div class = "title" > Lumen . < / div > < / div > < / div >

Note: The code examples here are a little condensed. There are best practices for encapsulating and packaging services that I am not using here for the sake of clarity.

Time To Code

With the addition of ID Site in the SDK, it introduces the use of JWTs (JSON Web Tokens). The Stormpath API makes it easy for you to generate one of these tokens and a url to redirect the user to.

Next, create some base code, which will instantiate the Client for the Stormpath SDK.

$id = $_ENV['STORMPATH_ID']; $secret = $_ENV['STORMPATH_SECRET']; \Stormpath\Client::$apiKeyProperties = "apiKey.id=$id

apiKey.secret=$secret"; $application = \Stormpath\Resource\Application::get($_ENV['STORMPATH_APPLICATION']); 1 2 3 4 5 $ id = $ _ENV [ 'STORMPATH_ID' ] ; $ secret = $ _ENV [ 'STORMPATH_SECRET' ] ; \ Stormpath \ Client : : $ apiKeyProperties = "apiKey.id=$id

apiKey.secret=$secret" ; $ application = \ Stormpath \ Resource \ Application : : get ( $ _ENV [ 'STORMPATH_APPLICATION' ] ) ;

For now, place this in the top of your routes.php file. For final production apps, you would not want to do this, but rather store it in a service provider or even its own package.

To create the logic for the PHP API login, you will need to give access to the $application variable within the closure and then create the ID Site url to redirect to.

$app->get('login', function() use ($application) { $url = $spapplication->createIdSiteUrl(['callbackUri'=>'http://localhost:8000/idSiteResponse']); return redirect($url); }); 1 2 3 4 5 $ app - > get ( 'login' , function ( ) use ( $ application ) { $ url = $ spapplication - > createIdSiteUrl ( [ 'callbackUri' = > 'http://localhost:8000/idSiteResponse' ] ) ; return redirect ( $ url ) ; } ) ;

This is all you need for ID Site to generate the url for you to redirect to. You will notice that there is no logic in here for the login itself and we do not generate the url until the user clicks on login. This is because the JWT expires after one minute and will no longer be valid. The one-minute expiration is part of the SDK and not customizable.

Important Gotcha: Make sure that the callback URL used here is the one that we set up earlier in the Stormpath ID Site settings. If you do not do this part correctly, you will not be able to continue.

Half way there for the login! Now, you just need to deal with handling the callback to your site. You will do that at the /idSiteResponse url and take care of some logic and storing a reference to the user that logged in from that route.

$app->get('idSiteResponse', function() use ($application) { $response = $application->handleIdSiteCallback($_SERVER['REQUEST_URI']); switch($response->status) { case 'AUTHENTICATED' : Session::put('user', $response->account); Session::flash('notice', 'You have been logged in'); return redirect('/'); break; } }); 1 2 3 4 5 6 7 8 9 10 11 12 $ app - > get ( 'idSiteResponse' , function ( ) use ( $ application ) { $ response = $ application - > handleIdSiteCallback ( $ _SERVER [ 'REQUEST_URI' ] ) ; switch ( $ response - > status ) { case 'AUTHENTICATED' : Session : : put ( 'user' , $ response - > account ) ; Session : : flash ( 'notice' , 'You have been logged in' ) ; return redirect ( '/' ) ; break ; } } ) ;

The route here will again use the application variable and call a method on it of handleIdSiteCallback and pass in the URL. This URL will include a JWTResponse token which will be decoded and checked. Within the JWT, is a status in which you can use to make sure the user was authenticated. At this point, there is some code that is custom to Lumen which will set the user session with the account object from the callback.

Now that wasn’t too bad, was it?

Next up, you will finish the rest of the methods for logout, forgotPassword, and Register.

Logout

$app->get('logout', function() use ($application) { $url = $application->createIdSiteUrl(['logout'=>true, 'callbackUri'=>'http://localhost:8000/idSiteResponse']); return redirect($url); }); 1 2 3 4 5 6 7 $ app - > get ( 'logout' , function ( ) use ( $ application ) { $ url = $ application - > createIdSiteUrl ( [ 'logout' = > true , 'callbackUri' = > 'http://localhost:8000/idSiteResponse' ] ) ; return redirect ( $ url ) ; } ) ;

Register

$app->get('register', function() use ($application) { $url = $application->createIdSiteUrl(['path'=>'/#/register','callbackUri'=>'http://localhost:8000/idSiteResponse']); return redirect($url); }); 1 2 3 4 5 6 7 $ app - > get ( 'register' , function ( ) use ( $ application ) { $ url = $ application - > createIdSiteUrl ( [ 'path' = > '/#/register' , 'callbackUri' = > 'http://localhost:8000/idSiteResponse' ] ) ; return redirect ( $ url ) ; } ) ;

Forgot Password

$app->get('forgotPassword', function() use ($application) { $url = $application->createIdSiteUrl(['path'=>'/#/forgot','callbackUri'=>'http://localhost:8000/idSiteResponse']); return redirect($url); }); 1 2 3 4 5 6 7 $ app - > get ( 'forgotPassword' , function ( ) use ( $ application ) { $ url = $ application - > createIdSiteUrl ( [ 'path' = > '/#/forgot' , 'callbackUri' = > 'http://localhost:8000/idSiteResponse' ] ) ; return redirect ( $ url ) ; } ) ;

So, Why Should I Use Stormpath ID Site?

ID Site fully decouples your identity screens from your applications, making it incredibly easy to provide the same login / registration pages for multiple applications — achieving a centralized authentication system with a clean and easy user experience. It’s also a dang easy way to roll simple login screens for a new application or proof of concept.

However, Stormpath ID Site is different from traditional from traditional, SAML-based Single Sign-On, and may not be the right option for an internal application focused on your employees.

Resources

Feel free to hit me up on Twitter or in the comments below with any questions or comments!