# FusionAuth QuickStart for PHP QuickStart integration of PHP web application with FusionAuth. > For the index of this section of the site, see [llms.txt](https://4002.18-224-161-104.sslip.io/docs/llms.txt) ![PHP](https://4002.18-224-161-104.sslip.io/img/icons/php.svg) In this QuickStart, you are going to build an application with PHP and integrate it with FusionAuth. You'll be building it for [ChangeBank](https://www.youtube.com/watch?v=CXDxNCzUspM), a global leader in converting dollars into coins. It'll have areas reserved for users who have logged in as well as public facing sections. The Docker Compose file and source code for a complete application are available at [https://github.com/FusionAuth/fusionauth-quickstart-php-web](https://github.com/FusionAuth/fusionauth-quickstart-php-web). Note When developing PHP web applications, it's advisable to consider using a framework. Frameworks provide a structured environment, streamlining development and enhancing code organization. With built-in security features, community support, and time-saving tools, frameworks offer a robust foundation for efficient and maintainable projects. ## Prerequisites For this QuickStart, you'll need: * [PHP](https://www.php.net/downloads.php) 8.1+ * [Composer](https://getcomposer.org/) * [Docker](https://www.docker.com) version 20 or later, which is the quickest way to start FusionAuth. (There are [other ways](https://4002.18-224-161-104.sslip.io/docs/get-started/download-and-install.md).) ## General Architecture Here's a typical application login flow before FusionAuth: ```mermaid sequenceDiagram participant User participant App as Application User ->> App : View Homepage User ->> App : Click Login Link App ->> User : Show Login Form User ->> App : Fill Out and Submit Login Form App ->> App : Authenticates User App ->> User : Display User's Account or Other Info ``` Request flow during login before FusionAuth And here's the same application login flow after introducing FusionAuth: ```mermaid sequenceDiagram participant User participant App as Application participant FusionAuth User ->> App : View Homepage User ->> App : Click Login Link (to FusionAuth) User ->> FusionAuth : View Login Form FusionAuth ->> User : Show Login Form User ->> FusionAuth : Fill Out and Submit Login Form FusionAuth ->> FusionAuth : Authenticates User FusionAuth ->> User: Go to Redirect URI User ->> App: Request the Redirect URI App ->> FusionAuth : Is User Authenticated? FusionAuth ->> App : User is Authenticated App ->> User : Display User's Account or Other Info ``` Request flow during login after FusionAuth In general, you are introducing FusionAuth in order to normalize and consolidate user data. This helps make sure it is consistent and up-to-date as well as offloading your login security and functionality to FusionAuth. ## Getting Started Start with getting FusionAuth up and running and creating a new PHP application. ### Clone The Code First, grab the code from the repository and change to that directory. ```shell-session $ git clone https://github.com/FusionAuth/fusionauth-quickstart-php-web.git ``` ```shell-session $ cd fusionauth-quickstart-php-web ``` All shell commands in this guide can be entered in a terminal in this directory. On Windows, you need to replace forward slashes with backslashes in paths. All the files you'll create in this guide already exist in the `complete-application` subdirectory, if you prefer to copy them to your application. ### Run FusionAuth Via Docker You'll find a Docker Compose file (`docker-compose.yml`) and an environment variables configuration file (`.env`) in the root directory of the repo. Assuming you have Docker installed, you can stand up FusionAuth on your machine with the following. ```shell-session $ docker compose up -d ``` Here you are using a bootstrapping feature of FusionAuth called [Kickstart](https://4002.18-224-161-104.sslip.io/docs/get-started/download-and-install/development/kickstart.md). When FusionAuth comes up for the first time, it will look at the `kickstart/kickstart.json` file and configure FusionAuth to your specified state. Note If you ever want to reset the FusionAuth application, you need to delete the volumes created by Docker Compose by executing `docker compose down -v`, then re-run `docker compose up -d`. FusionAuth will be initially configured with these settings: * Your client Id is `e9fdb985-9173-4e01-9d73-ac2d60d1dc8e`. * Your client secret is `super-secret-secret-that-should-be-regenerated-for-production`. * Your example username is `richard@example.com` and the password is `password`. * Your admin username is `admin@example.com` and the password is `password`. * The base URL of FusionAuth is `http://localhost:9011/`. You can log in to the [FusionAuth admin UI](http://localhost:9011/admin) and look around if you want to, but with Docker and Kickstart, everything will already be configured correctly. Note If you want to see where the FusionAuth values came from, they can be found in the [FusionAuth app](http://localhost:9011/admin). The tenant Id is found on the Tenants page. To see the Client Id and Client Secret, go to the Applications page and click the `View` icon under the actions for the ChangeBank application. You'll find the Client Id and Client Secret values in the `OAuth configuration` section. Caution The `.env` file contains passwords. In a real application, always add this file to your `.gitignore` file and never commit secrets to version control. ### The Basic PHP Application While this guide builds a new PHP project, you can use the same method to integrate your existing project with FusionAuth. Note If you simply want to run the application and not create your own, there is a completed version in the `complete-application` directory. You can use the following commands to get it up and running. ```shell-session $ cd complete-application && \ composer install && \ php -S localhost:9012 -t public ``` View the application at [http://localhost:9012](http://localhost:9012). First create the directory for your application and change to that directory. ```bash mkdir your-application cd your-application ``` Before you start coding, you need to install the PHP module for your application to communicate with FusionAuth. Run the following command. ```bash composer require vlucas/phpdotenv jerryhopper/oauth2-fusionauth ``` ## Authentication Authentication in PHP is managed by [FusionAuth community member Jerry Hopper's FusionAuth Provider](https://github.com/jerryhopper/oauth2-fusionauth) for [The League's OAuth library](https://github.com/thephpleague/oauth2-client). Create an `.env` file within `your-application` directory and insert the following lines. ```shell FUSIONAUTH_CLIENT_ID="e9fdb985-9173-4e01-9d73-ac2d60d1dc8e" FUSIONAUTH_CLIENT_SECRET="super-secret-secret-that-should-be-regenerated-for-production" FUSIONAUTH_SERVER_URL="http://localhost:9011" FUSIONAUTH_BROWSER_URL="http://localhost:9011" FUSIONAUTH_REDIRECT_URL="http://localhost:9012/login.php" ``` This tells PHP where to find and connect to FusionAuth. In this application authentication is handled by two files: `login.php` and `logout.php`. The login file is based almost exactly on Jerry Hopper's code, but is split into neater functions and does two extra things: Starts a session and saves the user details to the session after login. Create a `public` directory within `your-application`. ```shell-session $ mkdir public ``` In the `public` directory, create a `login.php` file and insert the following code. ```php load(); } function startSafeSession() { $cookieParams = [ 'lifetime' => 0, // 0 means "until the browser is closed" 'path' => '/', // entire site can use this cookie // 'domain' => '', // Set your domain here 'secure' => false, // true for HTTPS, false for HTTP 'httponly' => true, // true to make the cookie accessible only through the HTTP protocol 'samesite' => 'Strict' // None, Lax, or Strict ]; session_set_cookie_params($cookieParams); session_start(); } function getFusionAuthProvider(): object { $fusionAuthClientId = $_ENV['FUSIONAUTH_CLIENT_ID'] ?? getenv('FUSIONAUTH_CLIENT_ID'); $fusionAuthClientSecret = $_ENV['FUSIONAUTH_CLIENT_SECRET'] ?? getenv('FUSIONAUTH_CLIENT_SECRET'); $fusionAuthServerUrl = $_ENV['FUSIONAUTH_SERVER_URL'] ?? getenv('FUSIONAUTH_SERVER_URL'); $fusionAuthBrowserUrl = $_ENV['FUSIONAUTH_BROWSER_URL'] ?? getenv('FUSIONAUTH_BROWSER_URL'); $fusionAuthRedirectUrl = $_ENV['FUSIONAUTH_REDIRECT_URL'] ?? getenv('FUSIONAUTH_REDIRECT_URL'); $provider = new \JerryHopper\OAuth2\Client\Provider\FusionAuth([ 'clientId' => $fusionAuthClientId, 'clientSecret' => $fusionAuthClientSecret, 'redirectUri' => $fusionAuthRedirectUrl, 'urlAuthorize' => $fusionAuthBrowserUrl . '/oauth2/authorize', 'urlAccessToken' => $fusionAuthServerUrl . '/oauth2/token', 'urlResourceOwnerDetails' => $fusionAuthServerUrl . '/oauth2/userinfo', ]); return $provider; } function redirectToAccountPageIfAlreadyLoggedIn() { if (isset($_SESSION['id'])) { header('Location: account.php'); exit; } } function redirectUserToFusionAuthIfNotLoggedIn($provider) { if (isset($_GET['code'])) return; $options = [ 'scope' => ['openid email profile'] ]; $authUrl = $provider->getAuthorizationUrl($options); $_SESSION['oauth2state'] = $provider->getState(); header('Location: '.$authUrl); exit; } function checkCSRFToken() { if (empty($_GET['state']) || (!\hash_equals($_SESSION['oauth2state'], $_GET['state']))) { unset($_SESSION['oauth2state']); exit('Invalid CSRF state'); } } function handleFusionAuthCallback($provider) { $token = $provider->getAccessToken('authorization_code', ['code' => $_GET['code']]); try { $user = $provider->getResourceOwner($token); $userArray = $user->toArray(); $email = $user->getEmail(); $name = $userArray['given_name']; session_regenerate_id(); $_SESSION['id'] = $user->getId(); $_SESSION['email'] = $email; $_SESSION['name'] = $name; header('Location: account.php'); } catch (Exception $e) { exit('Failed to get user details from FusionAuth'); } } ``` This setup code: * Prevents errors from being displayed in the browser, for security. * Loads all vendor modules into PHP so you can use them. * Reads your variables from the `.env` file. * Starts a new session using HTTP (not HTTPS since you're on localhost) and ensures your user Id cookie will not be accessible by JavaScript. Next comes the FusionAuth handlers. Starting from the `getFusionAuthProvider()` function, the code: * Creates a FusionAuth provider with your environment variables. * Sends the user to the account page if they already have a login cookie. * Sends the user to the FusionAuth URL if they are not logged in. * Checks the user's FusionAuth token if they are not logged in but are returning from FusionAuth. * Gets the user details from the FusionAuth token and saves them to the server-side session. This also generates a new session or cookie Id for the user for security. The user is then redirected to their account page. PHP automatically links the user's session to their browser by returning a cookie for the site, which is then included in every subsequent request. The login page handles both the initial user request to start the login process and the server callback request from FusionAuth to complete the authentication. Logging out is much simpler. Create a `logout.php` file in the `public` directory and insert the following code. ```php FusionAuth OpenID example

Welcome to Changebank

To get started, log in or create a new account.

coins
``` The index page contains nothing to note except a link to the login page ``. Next, create an `account.php` file and paste the following code into it. ```php FusionAuth OpenID example

Your balance

$0.00
``` The account page displays the user's email from FusionAuth with `

`. The account page is only visible to logged in users. If a session Id is not found, the user is redirected to login. Finally, create a `change.php` file and paste the following code into it. ```php false, 'hasChange' => true, 'total' => '', 'nickels' => '', 'pennies' => '', ]; $cents = intval(round(floatval($amount) * 100)); $total = $cents / 100; $state['total'] = is_nan($total) ? '' : number_format($total, 2); $nickels = intval(floor($cents / 5)); $state['nickels'] = number_format($nickels); $pennies = $cents - ($nickels * 5); $state['pennies'] = $pennies; $state['iserror'] = !preg_match('/^(\d+(\.\d*)?|\.\d+)$/', $amount); return $state; } ?> FusionAuth OpenID example

We Make Change

Please enter a dollar amount:
" />
Amount in USD: $
Please enter a dollar amount:
We can make change for $ with nickels and pennies!
" />
Amount in USD: $
" />
``` In addition to verifying login, the code at the top of the change page checks if the CSRF token is valid on POST requests. The CSRF token is hidden in the form in the HTML, `" />`. Although any attacker can make a POST request on behalf of a logged in user, a server will reject a GET request if it's not made from the same origin (URL). Including this CSRF token in your page requires an attacker to make a GET request to obtain it before making the POST request, which isn't possible. The `calculateChange()` method takes the amount given in the form and returns a `$state` array with the amount in nickels and pennies. The HTML at the bottom of the file displays a blank form when the page first loads (GET) or the result of the calculation when returning (POST). ## Run The Application From `your-application` directory run the following command to serve the application using the built-in PHP server. ```bash php -S localhost:9012 -t public ``` Browse to the app at [http://localhost:9012](http://localhost:9012). Log in using `richard@example.com` and `password`. The change page allows you to enter a number. ## Made it this far? Want a free t-shirt? We got ya. Thank you for spending some time getting familiar with FusionAuth. \*Offer only valid in the United States and Canada, while supplies last. [fusionauth tshirt](https://go.fusionauth.io/tshirt) ## Next Steps This QuickStart is a great way to get a proof of concept up and running quickly, but to run your application in production, there are some things you're going to want to do. ### FusionAuth Customization FusionAuth gives you the ability to customize just about everything to do with the user's experience and the integration of your application. This includes: * [Hosted pages](https://4002.18-224-161-104.sslip.io/docs/theme.md) such as login, registration, email verification, and many more. * [Email templates](https://4002.18-224-161-104.sslip.io/docs/email/email-templates.md). * [User data and custom claims in access token JWTs](https://4002.18-224-161-104.sslip.io/articles/tokens/jwt-components-explained.md). ### Security * You may want to customize the [token expiration times and policies](https://4002.18-224-161-104.sslip.io/docs/lifecycle/authenticate-users/oauth.md) in FusionAuth. * Choose [password rules](https://4002.18-224-161-104.sslip.io/docs/get-started/core-concepts/types/tenants.md#password) and a [hashing algorithm](https://4002.18-224-161-104.sslip.io/docs/reference/password-hashes.md) that meet your security needs. ### Tenant and Application Management * Model your application topology using [Applications](https://4002.18-224-161-104.sslip.io/docs/get-started/core-concepts/types/applications.md), [Roles](https://4002.18-224-161-104.sslip.io/docs/get-started/core-concepts/types/roles.md), [Groups](https://4002.18-224-161-104.sslip.io/docs/get-started/core-concepts/types/groups.md), [Entities](https://4002.18-224-161-104.sslip.io/docs/get-started/core-concepts/types/groups.md), and more. * Set up [MFA](https://4002.18-224-161-104.sslip.io/docs/lifecycle/authenticate-users/multi-factor-authentication.md), [Social login](https://4002.18-224-161-104.sslip.io/docs/lifecycle/authenticate-users/identity-providers.md), or [SAML](https://4002.18-224-161-104.sslip.io/docs/lifecycle/authenticate-users/identity-providers/overview-samlv2.md) integrations. * Integrate with external systems using [Webhooks](https://4002.18-224-161-104.sslip.io/docs/extend/events-and-webhooks.md), [SCIM](https://4002.18-224-161-104.sslip.io/docs/lifecycle/migrate-users/scim.md), and [Lambdas](https://4002.18-224-161-104.sslip.io/docs/extend/code/lambdas.md). ### PHP Authentication * [The League OAuth overview](https://oauth2-client.thephpleague.com/usage/) * [Jerry Hopper's FusionAuth provider](https://github.com/jerryhopper/oauth2-fusionauth) ## Troubleshooting * I get "This site can't be reached localhost refused to connect" when I click the login button. Ensure FusionAuth is running in the Docker container. You should be able to log in as the admin user `admin@example.com` with the password `password` at [http://localhost:9011/admin](http://localhost:9011/admin). * I get "Your browser sent a request that this server could not understand. Size of a request header field exceeds server limit". Open the app in an incognito browser window or clear your browser cache and cookies data. * PHP says there is an invalid state exception. Browse to the home page, log out, and try to log in again. If that still doesn't work, delete and restart all the containers. * It still doesn't work. You can always pull down a complete running application and compare what's different. ```shell-session $ git clone https://github.com/FusionAuth/fusionauth-quickstart-php-web.git && \ cd fusionauth-quickstart-php-web && \ docker compose up ``` ```shell-session $ cd complete-application && \ composer install && \ php -S localhost:9012 -t public ``` Browse to the app at [http://localhost:9012](http://localhost:9012). Related [Get Started FusionAuth QuickStart for Laravel API QuickStart integration of a Laravel API application using FusionAuth. php authentication](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/api/quickstart-php-laravel-api.md) [Get Started FusionAuth QuickStart for Laravel QuickStart integration of PHP Laravel web application with FusionAuth. php web login](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-php-laravel-web.md) [SDKs PHP Client Library The FusionAuth PHP Client library allows you to call FusionAuth from PHP applications. php authentication](https://4002.18-224-161-104.sslip.io/docs/sdks/php.md) --- ## Other pages in Web > For the full index of this section, see [Get Started](https://4002.18-224-161-104.sslip.io/docs/llms-get-started.txt). - [FusionAuth QuickStart for Express](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/express.md): Integrate FusionAuth with an example Express website. - [Web](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web.md): Explore step-by-step web application QuickStart guides from FusionAuth to seamlessly integrate authentication into your application. - [FusionAuth QuickStart for .NET](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-dotnet-web.md): QuickStart integration of .NET web application with FusionAuth. - [FusionAuth QuickStart for Golang](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-golang-web.md): QuickStart integration of a Golang web application with FusionAuth using the CoreOS OIDC library. - [FusionAuth QuickStart for Spring Boot With Thymeleaf](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-java-springboot-web.md): QuickStart integration of a Spring Boot web application using Thymeleaf with FusionAuth. - [FusionAuth QuickStart for Next.js](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-javascript-nextjs-web.md): Set up authentication in a Next.js app using FusionAuth. Follow this QuickStart guide to integrate secure login, user management, and authentication in your Next.js project. - [FusionAuth QuickStart for Nuxt](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-javascript-nuxt-web.md): QuickStart integration of a Nuxt web application with FusionAuth. - [FusionAuth QuickStart for Remix](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-javascript-remix-web.md): QuickStart integration of Javascript Remix web application with FusionAuth. - [FusionAuth QuickStart for Drupal](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-php-drupal-web.md): QuickStart integration of Drupal web application with FusionAuth. - [FusionAuth QuickStart for Laravel](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-php-laravel-web.md): QuickStart integration of PHP Laravel web application with FusionAuth. - [FusionAuth QuickStart for Python Django](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-python-django-web.md): QuickStart integration of Python Django web application with FusionAuth. - [FusionAuth QuickStart for Python Flask](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-python-flask-web.md): QuickStart integration of Python Flask web application with FusionAuth. - [FusionAuth QuickStart for Ruby on Rails](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-ruby-rails-web.md): QuickStart integration of Ruby on Rails web application with FusionAuth. - [FusionAuth QuickStart for Rust with Actix](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-rust-actix-web.md): QuickStart integration of a Rust Actix web application with FusionAuth. - [FusionAuth QuickStart for WordPress](https://4002.18-224-161-104.sslip.io/docs/get-started/quickstarts/web/quickstart-wordpress-web.md): QuickStart integration of WordPress application with FusionAuth.