In this article, we’re going to explore the Auth0 service, which provides authentication and authorization as a service. Auth0 allows you to set up basic authentication and authorization features for your apps in the blink of an eye.
What Is Auth0?
Auth0 is an authentication as a service tool that makes implementation of authentication-related features in your site a breeze. If you’ve built an app and you want to just outsource the authentication and authorization features, a service like Auth0 is something you should consider.
Let me quickly summarize what Auth0 has to offer:
- single sign-on
- multifactor authentication
- passwordless logins
- user management
- and much more
In this article, we’ll go through a couple of single sign-on methods that you could implement in your web apps in order to leverage authentication features provided by the Auth0 service.
In the first half of the article, we’ll explore how to set up basic authentication functionality in a server-side PHP web app. In the second half, I’ll explain how you could secure your custom APIs by setting up OAuth authorization using the Auth0 service.
Server-Side Authentication Integration
In this section, we’ll go through how you could quickly set up basic authentication for server-side web apps using Auth0. In fact, the Auth0 team already provides a handy GitHub sample that demonstrates basic examples, so we’ll use that instead of reinventing the wheel.
Before moving ahead, make sure to install Composer as that will be used to install actual Auth0 SDKs using the composer.json
file. Also, if you want to follow along with the examples in this article, go ahead and get yourself a free account with Auth0.
Set Up the Project
Let’s go ahead and grab the clone of the samples project.
git clone https://github.com/auth0-samples/auth0-php-web-app.git .
Go ahead the run the composer install
command to install the dependencies.
cd 00-Starter-Seed composer install
According to the composer.json file, it should have installed the vlucas/phpdotenv
and auth0/auth0-php
packages.
{ "name": "auth0/basic-webapp-sample", "description": "Basic sample for securing a WebApp with Auth0", "require": { "vlucas/phpdotenv": "2.4.0", "auth0/auth0-php": "~5.0" }, "license": "MIT", "authors": [ { "name": "Martin Gontovnikas", "email": "[email protected]" }, { "name": "Germán Lena", "email": "[email protected]" } ] }
The vlucas/phpdotenv
library is used to initialize environment variables from the .env file. Thus, it allows you to separate configuration from the code that changes between environments.
On the other hand, the auth0/auth0-php
package is the one that will help us set up authorization in our application.
Next, let’s set up the configuration for our application in the .env file. Go ahead and create the .env file by copying it from the .env.example file.
cp .env.example .env
It contains configuration values that will be used by the Auth0 library.
AUTH0_CLIENT_ID={CLIENT_ID} AUTH0_DOMAIN={DOMAIN_NAME} AUTH0_CLIENT_SECRET={CLIENT_SECRET} AUTH0_CALLBACK_URL={CALLBACK_URL} AUTH0_AUDIENCE=
You should be able to find most of the settings under Applications > Default App > Settings on the Auth0 dashboard. Please note that I’m using the default application created by the system. Of course, you could go ahead and create a new application if you want to do so.
The AUTH0_CALLBACK_URL
is the URL of your application where Auth0 will redirect users after login and logout. The value that you set in this field must be configured under the Allowed Callback URLs
under the application settings on the Auth0 dashboard.
You’ll find three main files implementing most of the authentication logic.
- index.php: This is the main page that displays either a login or logout button based on the state of the user.
-
login.php: This script will be initiated when you click on the login button, and it will redirect users to the Auth0 login interface for login. Post login, they’ll be redirected back to the
AUTH0_CALLBACK_URL
. -
logout.php: This script will be initiated when you click on the logout button, and it will redirect users to Auth0 in the background, log them out, and get them back to the
AUTH0_CALLBACK_URL
.
Key Project Files
Let’s quickly go through each file in the starter project.
The Login Script
We’ll start with the login.php file.
$domain, 'client_id' => $client_id, 'client_secret' => $client_secret, 'redirect_uri' => $redirect_uri, 'audience' => $audience, 'scope' => 'openid profile', 'persist_id_token' => true, 'persist_access_token' => true, 'persist_refresh_token' => true, ]); $auth0->login();
At the start, we’ve included autoloaders that are responsible for loading Auth0 and environment variable related classes. Following that, we initialize configuration variables from the .env file using the getenv
function.
Next, we instantiate the Auth0 object and call the login method that redirects users to Auth0 for login. Upon login, users will be redirected back to our site.
You can log in using your social accounts like Facebook, Google and the like, or create a new account during login. In either case, Auth0 will create records for the new users on their end. You can enable different social logins under Connections > Social on the Auth0 dashboard. Also, you can check the list of users that are logged in using Auth0 on the Auth0 dashboard under the Users link.
The Logout Script
Next, let’s have a quick look at the logout.php file.
$domain, 'client_id' => $client_id, 'client_secret' => $client_secret, 'redirect_uri' => $redirect_uri, 'audience' => $audience, 'scope' => 'openid profile', 'persist_id_token' => true, 'persist_refresh_token' => true, ]); $auth0->logout(); $return_to = 'http://' . $_SERVER['HTTP_HOST']; $logout_url = sprintf('http://%s/v2/logout?client_id=%s&returnTo=%s', $domain, $client_id, $return_to); header('Location: ' . $logout_url); die();
This works pretty much the same as the login.php file, except that it’ll be called when users log out. The logout
method is called to expire a user session in your app. Following that, the user will be redirected to Auth0 so that the service is informed about the logout activity of the user. Finally, the user will be redirected back to your application.
The Index File
Finally, let’s go through the index.php file, which is the entry point of our application.
$domain, 'client_id' => $client_id, 'client_secret' => $client_secret, 'redirect_uri' => $redirect_uri, 'audience' => $audience, 'scope' => 'openid profile', 'persist_id_token' => true, 'persist_access_token' => true, 'persist_refresh_token' => true, ]); $userInfo = $auth0->getUser(); ?>Auth0 Example
Zero friction identity infrastructure, built for developers
Sign InWelcome
Logout
Here, we’ve used the getUser
method of the $auth0
object to see if there is any active session. If there’s no active session, we’ll display the Sign In link, which takes a user to login.php and initiates the login flow. On the other hand, we’ll greet the user and display the Logout link if the user is already logged in.
So that was the implementation of a basic authentication flow for server-side apps.
Secure Your Custom APIs With OAuth2
In this section, we’ll see how you could secure your custom APIs by implementing the OAuth2 authorization code grant flow. I hope you’re familiar with the standard flow of the authorization code grant since we won’t go into details of that. Check out some of our other posts here on Envato Tuts+ if you want to get up to speed with OAuth2.
-
OAuth 2.0 – The Good, The Bad & The Ugly
-
How to Authenticate Users With Twitter OAuth 2.0
Instead, we’ll straight away dive into the actual implementation. Go ahead and create an auth_code_grant_example.php file with the following contents.
'{AUDIENCE}', 'scope' => 'profile', 'response_type' => 'code', 'client_id' => '{CLIENT_ID}', 'state' => 'SomeRandomString', 'redirect_uri' => '{CALLBACK_URL}' ); $_SESSION['oauth2state']=$params['state']; $str_params = ''; foreach($params as $key=>$value) { $str_params .= $key . "=" . urlencode($value) . "&"; } ?> "> Sign In 'authorization_code', 'client_id' => '{CLIENT_ID}', 'client_secret' => '{CLIENT_SECRET}', 'code' => $_GET['code'], 'redirect_uri' => '{CALLBACK_URL}' ); $str_params = ''; foreach($params as $key=>$value) { $str_params .= $key . "=" . urlencode($value) . "&"; } $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => "https://{AUTH0_DOMAIN}/oauth/token", CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => $str_params )); $curl_response = curl_exec($curl); $curl_error = curl_error($curl); curl_close($curl); if ($curl_error) { echo "Error in the CURL response:" . $curl_error; } else { $arr_json_data = json_decode($curl_response); if (isset($arr_json_data->access_token)) { $access_token = $arr_json_data->access_token; $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => "http://{YOUR_API_DOMAIN}/demo_api_server.php", CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_HTTPHEADER => array( "Authorization: Bearer {$access_token}" ) )); $curl_response = curl_exec($curl); $curl_error = curl_error($curl); curl_close($curl); if ($curl_error) { echo "Error in the CURL response from DEMO API:" . $curl_error; } else { echo "Demo API Response:" . $curl_response; } } else { echo 'Invalid response, no access token was found.'; } } }
Let’s take a look at how this code works!
Beginning the Authorization Flow
First, we prepared a link that sends the user to the Auth0 server to begin the authorization flow.
// Check if we need to show the "Sign In" link $params = array ( 'audience' => '{AUDIENCE}', 'scope' => 'profile', 'response_type' => 'code', 'client_id' => '{CLIENT_ID}', 'state' => '{SOME_RANDOM_STRING}', 'redirect_uri' => '{CALLBACK_URL}' ); $_SESSION['oauth2state']=$params['state']; $str_params = ''; foreach($params as $key=>$value) { $str_params .= $key . "=" . urlencode($value) . "&"; } ?> "> Sign In
Please replace {AUDIENCE}
, {CLIENT_ID}
, and {CALLBACK_URL}
with values corresponding to your application. The {AUDIENCE}
parameter should be replaced with the value of the Identifier field found under APIs > {YOUR API APPLICATION} > Settings on the Auth0 dashboard.
The {SOME_RANDOM_STRING} should be replaced with a unique value that’s hard to guess. This string is used to prevent CSRF attacks. Also, make sure to replace {AUTH0_DOMAIN}
with your domain name, as we discussed earlier.
Getting the Access Token
When a user clicks on the Sign In link, they’ll be taken to the Auth0 server for authentication. After authentication, they’ll be asked to authorize the application access to your profile. Post authorization, the user will be redirected back to your application with the code
as a $_GET
parameter.
Next, we can exchange this code
to get the access token.
// If the auth "code" is present in the $_GET // let's exchange it for the access token $params = array ( 'grant_type' => 'authorization_code', 'client_id' => '{CLIENT_ID}', 'client_secret' => '{CLIENT_SECRET}', 'code' => $_GET['code'], 'redirect_uri' => '{CALLBACK_URL}' ); $str_params = ''; foreach($params as $key=>$value) { $str_params .= $key . "=" . urlencode($value) . "&"; } $curl = curl_init(); $curl_response = curl_exec($curl); curl_setopt_array($curl, array( CURLOPT_URL => "https://{AUTH0_DOMAIN}/oauth/token", CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => $str_params ));
As you can see, it takes a single CURL call to fetch the access token.
Call Your Custom API Endpoint
Once you have the access token, you can call your custom API endpoint by including it in the header.
$access_token = $arr_json_data->access_token; $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => "http://{YOUR_API_DOMAIN}/demo_api_server.php", CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_HTTPHEADER => array( "Authorization: Bearer {$access_token}" ) )); $curl_response = curl_exec($curl); $curl_error = curl_error($curl); curl_close($curl); if ($curl_error) { echo "Error in the CURL response from DEMO API:" . $curl_error; } else { echo "Demo API Response:" . $curl_response; }
An Auth0-Protected API Endpoint
The fictitious API resource file demo_api_server.php might look something like this:
['{HASHING_ALGORITHM}'], 'valid_audiences' => ['{AUDIENCE}'], 'authorized_iss' => ['{DOMAIN}'] ]); $access_token = getBearerToken(); $token_info = $verifier->verifyAndDecode($access_token); echo json_encode(array('date'=>'API Resource Data!!')); } catch(Auth0SDKExceptionCoreException $e) { throw $e; echo json_encode(array('error'=>$e->getMessage())); } function getAuthorizationHeader() { $headers = null; if (isset($_SERVER['Authorization'])) { $headers = trim($_SERVER["Authorization"]); } else if (isset($_SERVER['HTTP_AUTHORIZATION'])) { //Nginx or fast CGI $headers = trim($_SERVER["HTTP_AUTHORIZATION"]); } elseif (function_exists('apache_request_headers')) { $requestHeaders = apache_request_headers(); // Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization) $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders)); //print_r($requestHeaders); if (isset($requestHeaders['Authorization'])) { $headers = trim($requestHeaders['Authorization']); } } return $headers; } function getBearerToken() { $headers = getAuthorizationHeader(); // HEADER: Get the access token from the header if (!empty($headers)) { if (preg_match('/Bearers(S+)/', $headers, $matches)) { return $matches[1]; } } return null; }
Let’s quickly go through the important parts of this code.
Validating the Access Token
It’s your responsibility to validate the incoming access token before you grant access to the protected resource. And that’s exactly what we’ve done in the following snippet. We’ve used the JWTVerifier
utility class to validate the access token.
try { $verifier = new JWTVerifier([ 'supported_algs' => ['{SIGNING_ALGORITHM}'], 'valid_audiences' => ['{AUDIENCE}'], 'authorized_iss' => ['{DOMAIN}'] ]); $access_token = getBearerToken(); $token_info = $verifier->verifyAndDecode($access_token); echo json_encode(array('date'=>'API Resource Data!!')); } catch(Auth0SDKExceptionCoreException $e) { throw $e; echo json_encode(array('error'=>$e->getMessage())); }
The {SIGNING_ALGORITHM}
should be replaced with the value of the Signing Algorithm field found under APIs > {YOUR API APPLICATION} > Settings.
So, that’s how you can protect your custom APIs should you wish to use the OAuth2 flow in the Auth0 service.
Conclusion
Today, we went through the Auth0 service, which provides authentication and authorization as a service. After introducing the Auth0 service, we went through a couple of practical examples to demonstrate how you could integrate it with your PHP applications.
Please feel free to post your suggestions and queries using the feed below!
Powered by WPeMatico