Flex and PHP: Authentication With an HTML Login Page

One of the first things to think about when building a Flex application is how you’re going to do authentication. Most people seem to include a username and password box in Flex and then make an HTTPService or AMF call to pass the authentication credentials. But I hate that solution. Most major browsers now have support to save usernames and passwords with autocomplete and that’s become something people expect from their logins. I think it’s also important to be able to clear the “remember me” cookie just like any other cookie as opposed to having it saved in a Flash cookie. Whenever you can provide the behavior people expect from their browser, you should.

So in this example I’m going to show how you might implement an HTML form with PHP for a Flex application. As I’m new to PHP there may be some bad practices here but I’ll update the post as I get feedback.

Creating the login page in PHP and HTML

To start, we can just use PHP’s built in session functions to create the session variables and build the login page called login.php. You start off by creating a session with session_start() and then you set some session variables to their defaults. Then you’ll show the username and password fields only if the form hasn’t been submitted and use the $_SESSION variables to store the information from the user. Finally, when everything is authenticated you use the header() function to send the user to the Flex application.

<?php
session_start();
$_SESSION['logged_in'] = false;
$_SESSION['username'] = "";
 
if(isset($_POST['is_submitted']))
{
$username = $_POST['username'];
$password = $_POST['password'];
 
// If the "Remember my username" box is checked
// then we use the setcookie function to save it.
// Otherwise, we clear it out. 
if($_POST['keep_username'] == true)
     {
          setcookie("username",$username,time()+36000);
     } else {
          setcookie("username");
     }
 
// This is where you would look up the username
// and password. Normally this would be an LDAP call
// or a query to a database. In this case, I'm just
// accepting everything.
if($username && $password)
     {
// Set our session variables.
$_SESSION['logged_in'] = true;
$_SESSION['username'] = $username;
 
// Redirect to the Flex application
          header("location:flex/index.php");
     } else
{
echo "Go back and put in a username and password.";
     }
} else {
?>
 
<form name="login" action="<?php$_SERVER['PHP_SELF'] ?>" method="post">
     Username: <input type="text" name="username" value="<?php echo $_COOKIE['username']; ?>" /><br/>
     Password: <input type="password" name="password" /><br/>
     Remember my username: <input type="checkbox" name="keep_username" value="true"><br/>
<input type="hidden" name="is_submitted" value="true" />
<input type="submit" value="Submit" />
</form>
 
<?php 
}
?>

Notice the keep_username checkbox above. If the user checks that, you use the setcookie() method to create a cookie that will store the username on the next visit. If it is unchecked, the username will be blank.

Setting up the Flex Project

Even though most Flex applications take up the entire page, nearly all of the time you embed the actual SWF file on an HTML page. In Flash Builder when you create a new Flex application in creates the SWF files and the HTML files for you that embed your application. To do that it uses a template file that you can find in the html-template folder of your project. If you haven’t done so yet, go ahead and create a new Flex project. Use the defaults (do not use PHP as the server, leave it at None/Other). When you get to the second screen, set the output folder to a subdirectory named “flex” in the directory where your login.php file is located.

With the project created the first thing you’ll want to do is edit the template file. Go into the html-template directory and rename index.template.html to index.template.php. That will let you run PHP code inside of the template file. Flash Builder will automatically create an index.php file in the flex folder you specified in the create project wizard. Next you need to make sure your application will use the right file when you run or debug it. Right click on your project, select properties, and then select Run/Debug Settings. Now select your project in that box and click the “Edit” button. On the next screen, uncheck “Use default” in the lowest box and type the path to your application. You can see mine below (I’ve got http://localhost:8888 mapped to http://rainier.cascade.mtn but your local PHP server will probably use http://localhost).

Modifying the Index Template

Next you need to edit the template you just renamed. Open it up in Flash Builder (or your favorite text editor) and you should see a bunch of HTML. At the very top of that page you’re going to add some PHP code. First, you are going to check for a url parameter named logout to be passed. If it is, you destroy the session and log the user out. If that isn’t passed, you’re going to use the session information from your login page and save that information to variables on this page. This code goes at the very top before all of the HTML in your template page.

<?php     
// Always start the session first.
     session_start();
 
     // You will also use this page to log out. If 
     // ?logout=1 is passed in the URL, destroy the 
     // session and log the user out.
     if(isset($_GET['logout']))
     {
          if($_GET['logout'] == 1)
          {
              $params = session_get_cookie_params();
              setcookie(session_name(),"", time()-3600,
                  $params["path"], $params["domain"],
                  $params["secure"], $params["httponly"]);
               session_unset();
               session_destroy();
          }
     }
 
     // Create the default values for our session.    
     $session_id = "";
     $logged_in = false;
     $username = "";
 
     // If the session is valid, replace the default
     // values with our session values.
     if($_SESSION['logged_in'] == true)
     {
          $logged_in = true;
          $session_id = $_COOKIE['PHPSESSID'];
          $username = $_SESSION['username'];
?>

Now that your variables are set, you’ll send those to Flash Player. There are a number of ways to get data into your Flex application but the most straightforward is to use a concept referred to as “flashvars”. Flashvars are parameters you can put within the embed code that will then be accessible by the Flex application. Flashvars are a great way to take a dynamic site, like one written in PHP, and change the behavior of a Flex or Flash application based on that dynamic PHP data. Look for the JavaScript in the template that includes var flashvars = {} and replace it with this code.

var flashvars = {session_id:"<?php echo $session_id; ?>",               
logged_in:"<?php echo $logged_in; ?>",
username:"<?php echo $username; ?>"};

That code will make those three variables available to your Flex application. That way before you let the user do anything in your Flex application you can check to make sure the user is logged in correctly.

Finally, at the end of the template you’ll add some code to show the user an error message if they try to access the page without logging in.

<?php              
} else {
     echo "Not authorized, go back and log in.";
}
?>

Creating the Flex Application

In this example you’ll just create a very, very basic Flex application with two states, a beginning state and a logged in state. When the application loads, check the flashvars you added to the embed code and then change to the logged in state. The logged in state also contains a button that uses the logout functionality you added to the template code. Here’s the whole Flex application.

<?xml version="1.0" encoding="utf-8"?><s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
                  xmlns:s="library://ns.adobe.com/flex/spark" 
                  xmlns:mx="library://ns.adobe.com/flex/mx" 
                  minWidth="955" minHeight="600" currentState="startingScreen"
                  creationComplete="application1_creationCompleteHandler(event)">
 
<fx:Script>
     <![CDATA[
          import mx.controls.Alert;
          import mx.events.FlexEvent;
          import mx.utils.ObjectUtil;
 
          protected function btn_clickHandler(event:MouseEvent):void
          {
               navigateToURL( new URLRequest( encodeURI("index.php?logout=1")), "_self");
          }
 
          protected function application1_creationCompleteHandler(event:FlexEvent):void
          {
               if(this.parameters.logged_in == 1)
               {
                    currentState = 'loggedIn';
               }
          }
 
     ]]>
</fx:Script>
 
<fx:Declarations>
     <s:State name="startingScreen" />
     <s:State name="loggedIn" />
</fx:Declarations>
 
     <s:Panel name="Test" left="25" right="25" top="20" 
               bottom="25" title="My Application">
          <s:Button id="btn" left="10" top="10" 
                    click="btn_clickHandler(event)" 
                    label="Log Out" includeIn="loggedIn" />
          <s:Label id="lbl" left="10" top="10" 
                    text="You need to log in" 
                    includeIn="startingScreen" />
     </s:Panel>
 
</s:Application>

Conclusion and Warnings

There are a couple of notes and warnings about this method. By using two states and checking the login parameters you aren’t just depending on the embed code. That means if someone browses right to the SWF file they won’t be able to access the application because it won’t move to the next state unless it gets those parameters. That’s also part of the problem in this very simple application.

In the Flex code that changes the state I just check to see if the flashvar logged_in is set to 1. If you were to download a local version of the PHP file as well as the SWF and change that embed code you’d have access to the application. In a more robust example you would want to add a couple of hooks into the database. One way to do that would be to store the session id and the username in the database in the login.php file. Then when your Flex application loaded you could make a call to another PHP page and pass the session id and username parameters to a function which would compare it to the session and username that were stored during login to make sure it matches up.

You might also want to implement a token system with a shared secret which is a good way to authenticate against external APIs, the kind that you would create in PHP and consume in a Flex application using AMF or REST.

So keep in mind that this isn’t ready for production. But hopefully it gets you started in the right direction when creating a PHP/Flex application that is going to use an HTML login form. The fewer Flex/Flash login forms there are the better. Update: I’ve added a GitHub repository with the code. I’m hoping to add to this as I fill in some of the gaps that I warned about above.

HTML5 Versus Flash Versions

Serge has a great post on Adobe and the open web. I don’t think Adobe gets enough credit for contributing to the open web. That takes a couple of approaches. One is, as Serge said, we participate in a lot of open source and open web initiatives. But we also spend a lot of time and money investing in the web and solving problems that we come across. Cross-domain support is a perfect example. It was a problem we saw coming long before Ajax and we created a solution in the Flash Player to support cross domain requests. I ran down some of the new APIs and changes between HTML5 and HTML4 according to Wikipedia and compared them to what we have in Flash and when we added it.

Not all of this is 100% accurate but it’s the best guess I have at 2:00 AM. I’ll update it as I get new info.

HTML5 Flash Version
Canvas Tag (2D Drawing and Animation) FutureSplash (Flash Player 1)
Video/Audio Support Flash 2 (Audio) Flash 6 (Video)
Offline Storage Database No real offline storage in Flash Player, Adobe AIR added it in version 1
Drag-and-drop Supported in ActionScript 1(Flash Player 5)
Cross-Document Messaging Cross-Domain support in Flash Player 7
MIME type and protocol handler registration I don’t think there is anything analogous to this in Flash.
New parsing rules N/A
New elements such as progress, nav, time, etc Largely covered with ActionScript 2 (Flash Player 7)
New form controls (dates, times, email, url) Shipped with Flash authoring (Flash Player 3/4)

Talking to Chris Brichford about HTML and JavaScript in AIR

For Tech Talk with Ryan Stewart I sat down with Chris Brichford who works on the HTML side of the AIR Runtime. We talk about some of the history behind HTML support in AIR and some of the history on the team. It’s just a bit over 6 minutes but there’s some cool background on how decisions were made around HTML and Adobe AIR as well as how Adobe is working with the HTML and WebKit communities.

The “War” Between Flash and HTML/Ajax

There is a pretty good rundown of the RIA space and HTML versus Flash/Silverlight on CNet today. If you read through the comments a lot of people trash the article for arguing Apples and Oranges which I think is an encouraging sign that we’ve come a long way. No matter how you slice it, HTML/Ajax and Flash are competitors in a sense. They do very different things but the “5 year convergence” for the technologies looks very similar I think. Frankly, companies like Google and the browsers that have bought into Ajax and HTML must be feeling a little bit frustrated at the speed of innovation that a company like Adobe can achieve with Flash. So there’s tension there. But I hope that we don’t ever get to the point where we have a “winner”.

Flash can do some great, great stuff as a platform. It goes beyond animation because from our platform we’ve built up an ecosystem of servers, tools, and services that enable things like real-time collaboration, powerful video streaming, and system integration. We’ve been able to do that because the Flash Player allows us to do some very, very cool stuff. I hope our direction as a company is to figure out how to get that to merge more into the HTML/JS world.

The first comment on Digg nails it on the head (aside from the last few sentances):

Firstly, HTML has to be in any of these regardless. HTML is the building blocks of any web page, regardless of the other technologies it uses.

We need to bring Flash and HTML/Ajax closer together. You absolutely should be able to reach inside of the Flash Player as a JavaScript developer and pull out some of the good bits that make the Flash experience so great. We shouldn’t force the “1 pixel SWF” or a sand-boxed Flex application. With AIR you get a glimpse of what that’s like. To me, that’s win-win for everyone. You get to use Flash for things at which it excels. You can tap into Adobe’s services, tools, and infrastructure, and we enhance the entire web – including the HTML/JS side.