Adding Enterprise SSO / SAML to Laravel
Laravel is a PHP-based web application framework. If you read through their marketing site, you’ll see a few common words like elegant, simple, and clean.
And that’s because they focus heavily a great developer experience (DX), providing a lot of common functionality, like validation, object storage, db migration support, queues, rate limiting and more. Their utilities for testing are one of my personal favorite things.
In this post, we’ll look at how to expand their authentication and authorization support to include Enterprise SSO / SAML.
Setting up Enterprise SSO will allow your users to log in to your product with their existing work accounts, like Okta, Entra (previously Azure AD), ADFS, OneLogin, JumpCloud, Duo, and more. But first, let’s look at what Enterprise SSO is and why you might need it.
What is Enterprise SSO?
SSO stands for Single Sign On and refers to when a user uses a single account to access more than one application.
You are likely familiar with it from interacting with “Sign in with Google” buttons like these:
You are able to leverage your single Google account to log in to any application that’s added “Sign in with Google” functionality.
Importantly, this is not Enterprise SSO. This is a form of SSO usually referred to as a Social login, since it’s often tied to logging in to an account from a social network (LinkedIn, Twitter, Facebook, etc.).
Enterprise SSO, on the other hand, is reserved for when a user is logging in to your product with their employer-provided account (e.g. joe@acme.com but not jdawg90@gmail.com). It often comes up in B2B applications, where your customers aren’t just individuals, but teams/companies.
A common workflow is you enter your email address, and then are redirected to a login page just for your company:
We have a longer explanation here, which also covers features like SCIM, but the other important distinction is unlike social logins that are set up once for all customers, enterprise SSO connections need to be set up on a per-customer basis.
Do you need Enterprise SSO?
Enterprise SSO is often added as customers need it. It can frequently be a requirement for working with larger customers, but they won’t all use the same language. They may say things like:
- “Can I log into your product with my Okta account?”
- “Can I connect ADFS to you?”
- “We’ll also need sso support”
- “Do you support SAML / SCIM?”
If you get requests like that, the answer is almost certainly yes.
If you don’t, you likely don’t need it yet.
Adding Enterprise SSO to Laravel
We’re going to use the PropelAuth Socialite Provider to connect Laravel’s authentication to PropelAuth. PropelAuth will then handle setup/onboarding for your enterprise customers, as well as logging them in.
Ultimately, we’ll only need to add two endpoints. The first is a redirect endpoint which will redirect the user to a login page just for their organization:
Route::get('/auth/redirect', function (\Illuminate\Http\Request $request) {
$email = $request->query('email');
$queryParams = ['email' => $email];
return Socialite::driver('propelauth')->with($queryParams)->redirect();
});
And the second is an endpoint to set up the user & log them in:
Route::get('/auth/callback', function (Request $request) {
$propelauthUser = Socialite::driver('propelauth')->user();
$user = UserHelper::upsert($propelauthUser);
Auth::login($user);
return redirect('/');
});
But before we can do this, we’ll need to set up PropelAuth for enterprise SSO.
Setting up PropelAuth for Enterprise SSO
PropelAuth is an auth provider designed for B2B applications. Since we’re going to continue to use Laravel for Authn/Authz and use PropelAuth just for Enterprise SSO - the first step is to disable all login methods except for Enterprise SSO.
You can do this in the dashboard under Signup / Login:
Next, we need an organization for our users to log in to. You can create one by going to Organizations in the sidebar and creating one via the dashboard:
After you create the organization, you can set up Enterprise SSO for it by going to the settings tab for that organization and enabling “Can this organization setup SAML?”
And then finally, we can generate a SAML setup link which our customers can use to set up Enterprise SSO. Enterprise SSO often has a lengthy back-and-forth for enabling (you need to collect fields from them like their issuer and certificate, they need to collect fields from you like the ACS URL, they need to map the right attributes to you, etc.).
This is often made worse by each identity provider using different terminology for the same fields. PropelAuth makes all this easy by providing your users with a step-by-step guide for each provider - meaning you can just send them the setup link, and that’s all they’ll need.
Connecting Laravel and PropelAuth
We actually have Enterprise SSO set up already! Our users can set up connections, test those connections, and even log in with their work accounts. There’s only one problem… we need to tell Laravel when they log in.
This is where the PropelAuth Socialite Provider comes in. Let’s start by installing it:
composer require socialiteproviders/propelauth
Then we’ll add the following values to our .env file for the provider:
# You can find these values in the PropelAuth dashboard under
# Frontend Integration => Advanced Settings => Edit OAuth Config
PROPELAUTH_CLIENT_ID=0166...
PROPELAUTH_CLIENT_SECRET=f92ac31...
# This can be any URL, make sure to save it in our OAuth Config
PROPELAUTH_CALLBACK_URL=http://localhost:8000/auth/callback
# You can find this in the PropelAuth dashboard under Frontend Integration
PROPELAUTH_AUTH_URL=https://auth.example.com
Next, head over to config/services.php
and add the PropelAuth provider.
'propelauth' => [
'client_id' => env('PROPELAUTH_CLIENT_ID'),
'client_secret' => env('PROPELAUTH_CLIENT_SECRET'),
'redirect' => env('PROPELAUTH_CALLBACK_URL'),
'auth_url' => env('PROPELAUTH_AUTH_URL'),
],
We now need to register an event listener to extend Socialite with the PropelAuth provider. This will allow us to authenticate users via PropelAuth.
// /app/Providers/AppServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Event;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
}
public function boot(): void
{
// NEW CODE IS HERE
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
$event->extendSocialite('propelauth', \SocialiteProviders\PropelAuth\Provider::class);
});
}
}
Lastly, we are ready to bring back those two routes from before:
Route::get('/auth/redirect', function (\Illuminate\Http\Request $request) {
$email = $request->query('email');
$queryParams = ['email' => $email];
return Socialite::driver('propelauth')->with($queryParams)->redirect();
});
Route::get('/auth/callback', function (Request $request) {
$propelauthUser = Socialite::driver('propelauth')->user();
$rawUser = $propelauthUser->getRaw();
$user = User::updateOrCreate([
// You can also do this lookup by ID depending on your schema
'email' => $propelauthUser->email,
], [
'name' => trim($propelauthUser->first_name . ' ' . $propelauthUser->last_name),
'email' => $propelauthUser->email,
// The user's org info. This will include the org who's SAML connection
// they logged in through, as well as their role within the org.
'orgMemberInfo' => $rawUser['org_member_info'] // user's org info
]);
Auth::login($user);
return redirect('/');
});
And now we are ready to test! If you go to http://localhost:8000/auth/redirect?email=youremail@domain.com (assuming you set up Enterprise SSO for the domain.com
org), you’ll be prompted to log in with your work account. After logging in, a new account within Laravel will be created which includes the org you just logged in through.
Updating our login UI
Our users probably won’t stumble upon the /auth/redirect
path randomly, we need to update our login UI.
How you do this will vary from application to application. Some applications have a separate login page for enterprise customers. Some applications prompt for an email address and fall back to password login if there’s no enterprise SSO connection associated with that user.
Whichever you choose, the only thing you need to do is redirect the user to /auth/redirect
and after they login, they’ll come back to /auth/callback
.
Bringing it all together
Enterprise SSO can be a daunting task - each provider is different and each customer needs to be onboarded individually.
In this post, we looked at how we can connect Laravel to PropelAuth to make the process as simple as:
- Send the customer a link which guides them through onboarding
- The employees at that customer will then be able to log in to our application with their work accounts
Since we are creating the user within Laravel as well, this all naturally works with built-in authn/authz features like gates and session timeouts / invalidation.
If you have any questions, feel free to reach out at support@propelauth.com.