Something's gone wrong!An error ocurred performing that action. Please try refreshing the page.

PHP: Implement Azure AD login to your site

By Katy Nicholson, posted on 8 August, 2021

A while ago I wrote some code to enable one of my PHP projects to log in via authentication with ADFS. I've recently updated this to talk directly with Azure AD, and have split this off into a separate project which I'll share here.

Basically this works using oAuth2, browser sessions, a database and a couple of scripts, and on the Azure AD side you need to create an App Registration. Within this sample project the following flow happens:

  • User lands on index.php. If they do not have a session key cookie, one is generated, and this is stored in the database along with the page the user was attempting to access. They are redirected to login.microsoftonline.com to authenticate.
  • If you allowed authentication from any tenant, and used the common endpoint (rather than your specific tenant ID), the user may be asked to allow your app to access their account. If they are on their home tenancy, you will have already approved this for all users.
  • The user is redirected to the oauth.php file, where a background request is made back to login.microsoftonline.com to obtain a token. Once this has been successful, the user is redirected back to their original destination.
  • If the user lands on index.php and their session key cookie already exists, and exists in the database, and has not expired, they will be allocated that token's data.
  • If the user lands on index.php with a session key cookie, but it is going to expire in the next 10 minutes, we will perform a refresh request in the background.
  • If the user lands on index.php with a session key cookie, but it's expired, they are redirected back to login.microsoftonline.com - which may automatically log them back in, or may prompt, depending on their settings.

The code is available on my GitHub repository. The various files within are:

  • database.sql - the table used by this project. Create a database first, and note down the details (host, username, password, database).
  • inc/_config.inc - configuration file, put your database details in here, along with your tenant ID, client ID and client secret or certificate details from the Azure AD App Registration. There's also an entry for URL which is the URL of your site, included rather than automatically determined incase your site is accessible by multiple URLs as this needs to match what you've entered into the App Registration. I've defined constants for all these settings, there is probably a better way to do this but they work.
    Note this file must be renamed config.inc.
  • inc/mysql.php - class used for accessing the database, nothing needs editing in here.
  • inc/auth.php - main authentication class - again nothing to edit in here.
  • www/index.php - sample page which will request login and then display your username and a logout link, along with a print of all the data retrieved during logon.
  • www/oauth.php - callback script, Azure AD login page returns you back to this script.
  • inc/oauth.php - some of the worker functions used by inc/auth.php and www/oauth.php

When putting this on a web server, the web root should be www and the inc directory should not be accessible from the web browser.

Note: You will need to have the PHP CURL library installed on the server for this to work. You will also need openssl if you want to use client certificates instead of a client secret - when I tested this on linux and Windows, it was already installed.

App Registration

To create the App Registration, to to Azure AD > App registrations and click New registration. Fill out your site display name, select the account types, then enter the Redirect URI which will be https://your.domain.name/oauth.php. Make sure that you put https://your.domain.name (with no trailing slash) into _URL within config.inc. Click Register once done.

Screenshot of Azure AD Register an application screen, showing the display name and Redirect URI completed.
Register the application with Azure AD

A quick note on supported account types - if you use "common" as your tenant ID within config.inc, any account on any Azure AD tenant, plus personal (outlook.com etc) accounts can log in. If you use your actual tenant ID, then only accounts which are on your tenant (either as normal accounts, or as guests from other tenancies) can log in, but personal Microsoft accounts will work if they are guests on your tenancy, assuming you've set the supported account type in the App Registration accordingly.

Once you've finished creating the app, you should see the Overview screen. Copy the client ID and tenant ID, pasting them into _OAUTH_TENANTID and _OAUTH_CLIENTID in config.inc. The _OAUTH_TENANTID entry should be either your tenant (directory) ID for a single tenant app, or the word 'common' for the multi-tenant app.

App registration overview screenshot, showing client ID and tenant IDs
ID and Directory (tenant) ID.

Now on the Certificates & secrets page, add a new secret and select the appropriate time. Don't forget you will need to update this before it expires, so make a note in your calendar. Once done, copy the secret value and paste this into _OAUTH_SECRET within config.inc. Make sure _OAUTH_METHOD contains 'secret'.

Alternatively you can use a certificate - which is the preferred route as it's more secure. You will need the private key and certificate on the server file system (in a non-web-accessible location), and you'll need to add the certificate on the Azure AD app registration. If you're going down this route, you will need to set _OAUTH_AUTH_CERTFILE to the full path to the certificate file, and _OAUTH_AUTH_KEYFILE to the full path to the private key. _OAUTH_METHOD will need to be set to 'certificate'.

Hopefully you should now be able to browse to your application and be prompted to log in. On your first go, you'll be asked to allow permissions for everyone on your tenant (assuming you have the appropriate admin rights).

Permissions Requested login prompt
Tick the box to accept for all users on your tenant

Update (1st Sept 2021)

I've updated this to show some basic use of the Graph API. The default index.php page will now pull the logged on user's profile photo and basic profile data. You'll need to configure the _OAUTH_SCOPE constant in config.inc and make sure this includes "user.read" for this bit to work. It's not required but if you want to read the logged on user's directory entry, you can do.

There's more detailed use of Graph API in my other PHP post, Graph Mailer, which demonstrates reading a mailbox and sending mail through Office 365. You'll need to alter the scope in config.inc to add the appropriate permissions in if doing this in your own application, and query using the logged on user's access token (show in this project) rather than the application's own token (show in the Graph Mailer project).

Update (15th & 16th Oct 2021) - Restricting Access

You can further restrict access to your application in Azure AD. Go to the Azure AD > Enterprise Applications page, find your app and then go to the Properties page. Toggle "Assignment required" to "Yes". Now go to the Users and groups page, and add the users/groups you wish to have access.

You can further extend this by adding different roles to the application - in Azure AD > App Registrations, find your app and go to the App roles page. Create an app role for each role you want to assign, e.g. Admin and User:

Screenshot of Create app role
You can create many app roles to help control access within your application, in this sample project I've gone for Role.Admin and Role.User.

The display name is shown when you assign users in Azure AD, and the Value is what is shown in the PHP code on your application. When assigning users in the Enterprise Application screen you will be asked to select their role.

In the index.php sample, you will notice $Auth->userRoles referred to - this will be an array of user roles. You can use the checkUserRole function in auth.php to verify if a user holds the role required for a specific part of your application, i.e. if ($Auth->checkUserRole('Role.Admin')) { //admin only code here }

Further Reading

In this post

Support My Work

I hope you find my content useful. Please consider tipping to support the running costs of hosting, licensing etc on my Ko-fi page.

Support me on Ko-fi

Search