Upgrade & Secure Your Future with DevOps, SRE, DevSecOps, MLOps!

We spend hours scrolling social media and waste money on things we forget, but won’t spend 30 minutes a day earning certifications that can change our lives.
Master in DevOps, SRE, DevSecOps & MLOps by DevOps School!

Learn from Guru Rajesh Kumar and double your salary in just one year.


Get Started Now!

A Comprehensive Guide to Implementing Single Sign-On (SSO) for Your Application Suite

Uncategorized

SSO Logic and Architecture

At its core, the SSO system works by centralizing the login process. Instead of each application managing its own user credentials, they all delegate authentication to a single, trusted Identity Provider (IdP). Your applications (Dashboard, Trips, Events, Blog, Forum) become Service Providers (SPs) that trust the IdP.

Core logic

Entities Involved:

  • User-Agent: The user’s web browser.
  • SP-Forum: The Service Provider, your Flarum application at HolidayLandmark.com/forum.
  • IdP: The central Identity Provider (your custom Laravel application).
  • SP-Trips: Another Service Provider, your EventMie application at HolidayLandmark.com/trips.

Phase 1: Initial Login at SP-Forum

Step 1: User Initiates Access to SP-Forum
The user navigates their browser to https://HolidayLandmark.com/forum.

Step 2: SP-Forum Checks for Local Session and Redirects

  • SP-Forum checks for a local session cookie to determine if the user is already authenticated with the forum application.
  • Finding no active session, it determines the user must be authenticated.
  • SP-Forum constructs an OAuth 2.0 Authorization Request and redirects the user’s browser to the IdP’s /authorize endpoint. This request includes parameters like client_id (identifying SP-Forum), redirect_uri (where to send the user back), response_type=code, and scope.

Step 3: IdP Authenticates the User

  • The IdP receives the request. It checks for its own session cookie to see if the user is already authenticated with the IdP.
  • Since this is the user’s first visit to any application in the ecosystem, there is no active IdP session.
  • The IdP displays its login page, prompting the user for their username and password.

Step 4: User Submits Credentials
The user enters their credentials and submits the form to the IdP.

Step 5: IdP Validates Credentials and Establishes Session

  • The IdP validates the credentials against its user database.
  • Upon successful validation, the IdP creates a central authentication session for the user and sets a session cookie in the user’s browser. This cookie is scoped to the IdP’s domain.
  • The IdP generates a single-use authorization code.

Step 6: IdP Redirects Back to SP-Forum
The IdP redirects the user’s browser back to the redirect_uri provided by SP-Forum in Step 2. The authorization code is included as a query parameter in the URL.

Step 7: SP-Forum Exchanges Code for Tokens

  • The user’s browser loads the redirect_uri at SP-Forum.
  • SP-Forum’s backend receives the authorization code.
  • It then makes a secure, back-channel (server-to-server) POST request to the IdP’s /token endpoint. This request includes the authorization_code, its client_id, and client_secret.

Step 8: IdP Issues Access and ID Tokens

  • The IdP validates the authorization code, client_id, and client_secret.
  • If valid, it invalidates the authorization code (to prevent reuse) and returns an access token and optionally an ID token to SP-Forum.

Step 9: SP-Forum Fetches User Info and Creates Local Session

  • SP-Forum uses the received access token to make an API call to the IdP’s user info endpoint (e.g., /api/user).
  • The IdP validates the access token and returns the user’s details (e.g., user_id, email, name).
  • SP-Forum checks its database for a user with the user_id from the IdP.
    • If the user doesn’t exist, it creates a new user record in its users table (without a password).
    • If the user exists, it proceeds.
  • SP-Forum creates a local session for the user, setting its own session cookie.

Result of Phase 1: The user is now successfully logged into HolidayLandmark.com/forum. The browser holds two important cookies: one for the SP-Forum session and one for the central IdP session.

Phase 2: Seamless Access to SP-Trips

Step 10: User Navigates to SP-Trips
The user opens https://HolidayLandmark.com/trips in the same browser.

Step 11: SP-Trips Checks for Local Session and Redirects

  • SP-Trips checks for its own local session cookie and finds none.
  • It constructs its own OAuth 2.0 Authorization Request and redirects the user’s browser to the IdP’s /authorize endpoint.

Step 12: IdP Detects Active Session and Skips Login

  • The IdP receives the request from SP-Trips.
  • Crucially, it checks for the IdP session cookie set in Step 5. It finds an active session.
  • Because the user is already authenticated with the IdP, it completely bypasses the login form.
  • The IdP immediately generates a new authorization code for SP-Trips and redirects the user’s browser back to the redirect_uri specified by SP-Trips. This happens automatically and almost instantly.

Step 13-15: SP-Trips Completes the Login Flow
The process now follows the same final steps as the first login, but for SP-Trips:

  • SP-Trips receives the new authorization code.
  • It exchanges the code for its own access token via a back-channel call to the IdP.
  • It uses the token to fetch user info from the IdP.
  • It creates a local user record (if one doesn’t exist) and establishes a local session for the user.

The flow follows the OAuth 2.0 Authorization Code Grant protocol:

  1. Access Request: A user tries to access a protected page on an SP (e.g., the Flarum forum).
  2. Redirect to IdP: The SP sees the user is not logged in and redirects them to the IdP’s login page, including a unique client_id and redirect_uri.
  3. User Authentication: The user enters their single set of credentials on the IdP’s login page.
  4. Authorization Grant: The IdP validates the credentials and redirects the user back to the SP’s specified redirect_uri, providing a temporary authorization code.
  5. Token Exchange: The SP’s backend securely communicates with the IdP, exchanging the authorization code, its client_id, and its client_secret for a permanent access token.
  6. User Info & Login: The SP uses this access token to request the user’s information (like email and name) from the IdP’s API. Upon receiving the data, the SP creates a local session and logs the user in.

If the user then visits a different SP, that SP will also redirect to the IdP, which, recognizing the existing authenticated session, will immediately send back a new authorization code without requiring the user to log in again.

Note: You can visualize the process as a central hub (the IdP) with spokes connecting to each of your applications (the SPs). All user authentication traffic is routed through this hub.

Part 1: Building the Central Identity Provider (IdP) with Laravel Passport

This is the most critical component. It will be a standalone Laravel application responsible for managing all users and authentication.

Step 1.1: Set Up the IdP Project

Create a new Laravel project. This will serve as your authentication server (e.g., auth.holidaylandmark.com).

laravel new holidaylandmark-idp
cd holidaylandmark-idp

Configure your .env file with your database details and APP_URL.

Step 1.2: Install and Configure Laravel Passport

Passport will transform your Laravel app into a full OAuth2 server.

1. Install via Composer:

composer require laravel/passport

2. Run Migrations: This creates the necessary database tables for clients and tokens.

php artisan migrate

3. Run Passport Installer: This command creates encryption keys and default clients.

php artisan passport:install

4. Configure User Model: Add the HasApiTokens trait.

File: app/Models/User.php

php<?php
namespace App\Models;

use Laravel\Passport\HasApiTokens; // <-- Add this
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable; // <-- And add this
    // ... rest of the model
}

5. Configure AuthServiceProvider: Register Passport’s routes.

File: app/Providers/AuthServiceProvider.php

php<?php
namespace App\Providers;

use Laravel\Passport\Passport; // <-- Add this
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    // ...
    public function boot()
    {
        $this->registerPolicies();
        Passport::routes(); // <-- Add this line
    }
}

6. Configure API Auth Guard: Tell Laravel to use Passport for API authentication.

File: config/auth.php

php'guards' => [
    // ...
    'api' => [
        'driver' => 'passport', // <-- Change 'token' to 'passport'
        'provider' => 'users',
    ],
],

Step 1.3: Create an API Route to Fetch User Data

Service providers will use this endpoint to get user details after getting an access token.

File: routes/api.php

php<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

Step 1.4: Register Each Service Provider as an OAuth Client

For each of your applications, run this command in your IdP’s terminal. You will receive a Client ID and Client Secret for each one—save these credentials securely.

# For the Dashboard
php artisan passport:client --name="Dashboard" --redirect_uri="https://holidaylandmark.com/auth/callback"

# For the Trips App
php artisan passport:client --name="Trips" --redirect_uri="https://holidaylandmark.com/trips/auth/callback"

# For the Events App
php artisan passport:client --name="Events" --redirect_uri="https://holidaylandmark.com/events/auth/callback"

# For the WordPress Blog (using custom code callback)
php artisan passport:client --name="Blog" --redirect_uri="https://holidaylandmark.com/blogs/wp-login.php?action=hl_sso_callback"

# For the Flarum Forum (using custom code callback)
php artisan passport:client --name="Forum" --redirect_uri="https://holidaylandmark.com/forum/auth/holidaylandmark"

Part 2: Configuring the Laravel Service Providers (Dashboard, Trips, Events)

This section applies to your Dashboard, Trips, and Events applications. The steps are identical for each.

Step 2.1: Install Socialite

composer require laravel/socialite

Step 2.2: Add Credentials

File: config/services.php

php'holidaylandmark_sso' => [
    'client_id' => env('HL_SSO_CLIENT_ID'),
    'client_secret' => env('HL_SSO_CLIENT_SECRET'),
    'redirect' => env('HL_SSO_REDIRECT_URI'),
],

File: .env (Use the unique credentials for each SP)

textHL_SSO_CLIENT_ID=your-client-id-for-this-app
HL_SSO_CLIENT_SECRET=your-client-secret-for-this-app
HL_SSO_REDIRECT_URI=https://your-app-domain.com/auth/callback

Step 2.3: Create a Custom Socialite Provider

Since your IdP is not a standard one like Google, you must teach Socialite how to communicate with it.

1. Install the Socialite Providers Manager:

composer require socialiteproviders/manager

2. Create the Provider Class: This class contains the IdP’s URLs.

File: app/Services/HolidayLandmarkSSOProvider.php (Create the Services folder if needed).

php<?php
namespace App\Services;
use SocialiteProviders\Manager\OAuth2\AbstractProvider;
use SocialiteProviders\Manager\OAuth2\User;

class HolidayLandmarkSSOProvider extends AbstractProvider
{
    public const IDENTIFIER = 'HOLIDAYLANDMARK_SSO';

    protected function getAuthUrl($state) {
        return $this->buildAuthUrlFromBase('https://auth.holidaylandmark.com/oauth/authorize', $state);
    }
    protected function getTokenUrl() {
        return 'https://auth.holidaylandmark.com/oauth/token';
    }
    protected function getUserByToken($token) {
        $response = $this->getHttpClient()->get('https://auth.holidaylandmark.com/api/user', [
            'headers' => ['Authorization' => 'Bearer ' . $token],
        ]);
        return json_decode($response->getBody(), true);
    }
    protected function mapUserToObject(array $user) {
        return (new User())->setRaw($user)->map([
            'id' => $user['id'], 'nickname' => $user['name'],
            'name' => $user['name'], 'email' => $user['email'], 'avatar' => null,
        ]);
    }
}

3. Create the Event Listener: This tells Socialite to use your provider.

File: app/Listeners/HolidayLandmarkSSOExtendSocialite.php (Create the Listeners folder).

php<?php
namespace App\Listeners;
use SocialiteProviders\Manager\SocialiteWasCalled;

class HolidayLandmarkSSOExtendSocialite {
    public function handle(SocialiteWasCalled $socialiteWasCalled) {
        $socialiteWasCalled->extendSocialite('holidaylandmark_sso', \App\Services\HolidayLandmarkSSOProvider::class);
    }
}

4. Register the Listener:

File: app/Providers/EventServiceProvider.php

phpprotected $listen = [
    \SocialiteProviders\Manager\SocialiteWasCalled::class => [
        \App\Listeners\HolidayLandmarkSSOExtendSocialite::class.'@handle',
    ],
];

Step 2.4: Create the Login and Callback Routes

This handles the user-facing login flow.

File: routes/web.php

php<?php
use Illuminate\Support\Facades\Route;
use Laravel\Socialite\Facades\Socialite;
use App\Models\User;
use Illuminate\Support\Facades\Auth;

// Redirects user to the IdP
Route::get('/login', function () {
    return Socialite::driver('holidaylandmark_sso')->redirect();
})->name('login');

// Handles the callback from the IdP
Route::get('/auth/callback', function () {
    $ssoUser = Socialite::driver('holidaylandmark_sso')->user();

    // Find or create a user in this application's database
    $user = User::updateOrCreate(
        ['email' => $ssoUser->getEmail()],
        [
            'name' => $ssoUser->getName(),
            'sso_id' => $ssoUser->getId(), // A new column to store the master user ID from IdP
            'password' => Illuminate\Support\Facades\Hash::make(Illuminate\Support\Str::random(24))
        ]
    );

    // Log the user into this application
    Auth::login($user, true); // 'true' for "remember me"

    return redirect('/dashboard'); // Redirect to a protected page
});

Part 3: Configuring the WordPress Service Provider (Code-Based)

Here’s how to create your own plugin for full control over the WordPress integration.

  1. Create Plugin Directory: In your WordPress site, go to wp-content/plugins/ and create a folder named holidaylandmark-sso-client.
  2. Create Plugin File: Inside that folder, create holidaylandmark-sso-client.php.
  3. Add the Code:

File: wp-content/plugins/holidaylandmark-sso-client/holidaylandmark-sso-client.php

php<?php
/**
 * Plugin Name:       HolidayLandmark SSO Client
 * Description:       A custom SSO client to connect to the HolidayLandmark Identity Provider.
 */

// --- Configuration: Replace with your actual credentials ---
define('HL_SSO_CLIENT_ID', 'your-wordpress-client-id');
define('HL_SSO_CLIENT_SECRET', 'your-wordpress-client-secret');
define('HL_SSO_REDIRECT_URI', site_url('/wp-login.php?action=hl_sso_callback'));
define('HL_IDP_AUTHORIZE_URL', 'https://auth.holidaylandmark.com/oauth/authorize');
define('HL_IDP_TOKEN_URL', 'https://auth.holidaylandmark.com/oauth/token');
define('HL_IDP_USERINFO_URL', 'https://auth.holidaylandmark.com/api/user');

// Adds the login button to the WordPress login form
add_action('login_form', function () {
    if (session_status() === PHP_SESSION_NONE) session_start();
    $state = bin2hex(random_bytes(16));
    $_SESSION['oauth2_state'] = $state;

    $authorization_url = HL_IDP_AUTHORIZE_URL . '?' . http_build_query([
        'client_id' => HL_SSO_CLIENT_ID, 'redirect_uri' => HL_SSO_REDIRECT_URI,
        'response_type' => 'code', 'scope' => '', 'state' => $state,
    ]);
    echo '<a href="' . esc_url($authorization_url) . '" style="display:block; text-align:center; padding:10px; background-color:#3498db; color:#fff; text-decoration:none; margin:10px 0;">Login with HolidayLandmark</a>';
});

// Handles the callback from the IdP
add_action('login_init', function () {
    if (!isset($_GET['action']) || $_GET['action'] !== 'hl_sso_callback') return;
    if (session_status() === PHP_SESSION_NONE) session_start();
    if (empty($_GET['state']) || !isset($_SESSION['oauth2_state']) || $_GET['state'] !== $_SESSION['oauth2_state']) {
        wp_die('Invalid state parameter.');
    }
    unset($_SESSION['oauth2_state']);

    // Exchange code for token
    $response = wp_remote_post(HL_IDP_TOKEN_URL, [
        'body' => [ 'grant_type' => 'authorization_code', 'client_id' => HL_SSO_CLIENT_ID,
                    'client_secret' => HL_SSO_CLIENT_SECRET, 'redirect_uri' => HL_SSO_REDIRECT_URI,
                    'code' => sanitize_text_field($_GET['code']), ],
    ]);
    if (is_wp_error($response)) wp_die('Failed to get access token.');
    $token_data = json_decode(wp_remote_retrieve_body($response), true);
    if (empty($token_data['access_token'])) wp_die('Access token not found.');
    
    // Fetch user info
    $user_info_response = wp_remote_get(HL_IDP_USERINFO_URL, ['headers' => ['Authorization' => 'Bearer ' . $token_data['access_token']]]);
    if (is_wp_error($user_info_response)) wp_die('Failed to fetch user info.');
    $user_info = json_decode(wp_remote_retrieve_body($user_info_response), true);
    if (empty($user_info['email'])) wp_die('User email not found.');
    
    // Find or create user and log them in
    $user = get_user_by('email', $user_info['email']);
    if (!$user) {
        $username = sanitize_user(explode('@', $user_info['email'])[0], true);
        $base_username = $username; $i = 1;
        while (username_exists($username)) $username = $base_username . $i++;
        $user_id = wp_create_user($username, wp_generate_password(20), $user_info['email']);
        wp_update_user(['ID' => $user_id, 'display_name' => sanitize_text_field($user_info['name'])]);
        $user = get_user_by('id', $user_id);
    }
    
    wp_set_current_user($user->ID, $user->user_login);
    wp_set_auth_cookie($user->ID, true);
    do_action('wp_login', $user->user_login, $user);
    wp_redirect(admin_url());
    exit;
});

4. Activate Plugin: In your WordPress admin panel, go to “Plugins” and activate the “HolidayLandmark SSO Client” plugin.

Part 4: Configuring the Flarum Service Provider (Code-Based)

This requires creating a Flarum extension. The process is more complex due to Flarum’s architecture.

  1. Set up Extension Skeleton: Use flarum-cli or manually create the extension folder (e.g., packages/your-vendor/flarum-ext-holidaylandmark-sso) with composer.json, extend.php, and js directories.
  2. Add Backend Logic: This code handles the entire OAuth2 flow.

File: extend.php (in your extension’s root)

php<?php
namespace YourVendor\FlarumHolidayLandmarkSSO;
use Flarum\Extend;
use Psr\Http\Message\ServerRequestInterface;
use GuzzleHttp\Client;
use Flarum\Http\Rememberer;
use Flarum\Http\SessionAuthenticator;
use Flarum\User\User;
use Laminas\Diactoros\Response\RedirectResponse;

return [
    (new Extend\Routes('forum'))
        ->get('/auth/holidaylandmark', 'auth.holidaylandmark', function (ServerRequestInterface $request, SessionAuthenticator $authenticator, Rememberer $rememberer) {
            // --- Config (Store these in Flarum's settings DB or config.php) ---
            $idp_authorize_url = 'https://auth.holidaylandmark.com/oauth/authorize';
            $idp_token_url = 'https://auth.holidaylandmark.com/oauth/token';
            $idp_user_url = 'https://auth.holidaylandmark.com/api/user';
            $client_id = 'your-flarum-client-id';
            $client_secret = 'your-flarum-client-secret';
            $redirect_uri = app('flarum.config')['url'] . '/auth/holidaylandmark';
            
            $session = $request->getAttribute('session');
            $queryParams = $request->getQueryParams();

            if (!isset($queryParams['code'])) { // Step 1: Redirect to IdP
                $session->put('oauth2state', ($state = \Illuminate\Support\Str::random(40)));
                $query = http_build_query(['client_id' => $client_id, 'redirect_uri' => $redirect_uri,
                    'response_type' => 'code', 'scope' => '', 'state' => $state]);
                return new RedirectResponse($idp_authorize_url . '?' . $query);
            }
            
            // Step 2: Handle Callback
            if (empty($queryParams['state']) || $queryParams['state'] !== $session->get('oauth2state')) throw new \Exception('Invalid state');
            
            $httpClient = new Client();
            $response = $httpClient->post($idp_token_url, [ 'form_params' => [ 'grant_type' => 'authorization_code',
                'client_id' => $client_id, 'client_secret' => $client_secret, 'redirect_uri' => $redirect_uri,
                'code' => $queryParams['code'] ]]);
            $token = json_decode((string) $response->getBody(), true)['access_token'];

            $response = $httpClient->get($idp_user_url, ['headers' => ['Authorization' => 'Bearer ' . $token]]);
            $ssoUser = json_decode((string) $response->getBody(), true);
            
            $user = User::where('email', $ssoUser['email'])->first();
            if (!$user) {
                $user = User::register(['username' => $ssoUser['name'], 'email' => $ssoUser['email'], 'password' => \Illuminate\Support\Str::random(20)]);
                $user->activate(); $user->save();
            }
            
            $authenticator->logIn($session, $user->id);
            return $rememberer->remember(new RedirectResponse(app('flarum.config')['url']));
        }),
];

3. Add Frontend Login Button:

File: js/src/forum/index.js

javascriptimport { extend } from 'flarum/common/extend';
import LogInButtons from 'flarum/forum/components/LogInButtons';
import Button from 'flarum/common/components/Button';

app.initializers.add('your-vendor-holidaylandmark-sso', () => {
    extend(LogInButtons.prototype, 'items', function (items) {
        items.add('holidaylandmark',
            <Button className="Button LogInButton--holidaylandmark"
                icon="fas fa-id-card" path="/auth/holidaylandmark">
                Login with HolidayLandmark
            </Button>
        );
    });
});

4. Build and Activate: You must compile the JavaScript and then enable the extension in the Flarum admin panel.

The Strategy: Central Roles, Local Mapping

  1. Define a Superset of Roles in the IdP: In your Laravel IdP, you will define roles that are descriptive of their function across the entire ecosystem. This creates a single source of truth for a user’s permissions. Instead of creating roles like blog_editor or events_organizer, you create more generic roles.For your specific case, you could define these roles in your IdP:
    • Super Admin: Has administrative rights everywhere.
    • Content Editor: Can create and manage content (maps to Editor in WordPress, could be a Moderator in Flarum).
    • Event Organizer: Specific to the Events app.
    • General User: The default role for all basic users.
  2. Pass Roles from IdP to SPs: As established in the previous answer, you must modify your IdP’s /api/user endpoint to include an array of the user’s assigned roles in the JSON response.
  3. Implement Mapping Logic in Each SP: This is the most important step. Each application’s SSO callback handler will contain logic to map the IdP’s roles to its own internal roles.

Here’s how you would implement this for each of your applications:

1. Events App (holidaylandmark.com/events)

This Laravel application has the roles userorganizer, and admin. You will map the IdP roles to these local roles within your /auth/callback route.

Let’s assume your users table has a role column.

File: routes/web.php (in your Events app)

php// ...
Route::get('/auth/callback', function () {
    $ssoUser = Socialite::driver('holidaylandmark_sso')->user();

    // Get roles from the IdP.
    // The key 'roles' depends on your IdP's API response structure.
    $idpRoles = array_column($ssoUser->getRaw()['roles'] ?? [], 'name');

    // --- Role Mapping Logic ---
    $localRole = 'user'; // Default role

    if (in_array('Super Admin', $idpRoles)) {
        $localRole = 'admin';
    } elseif (in_array('Event Organizer', $idpRoles)) {
        $localRole = 'organizer';
    }
    // --- End Mapping Logic ---

    // Find or create the user and assign the mapped role
    $user = User::updateOrCreate(
        ['email' => $ssoUser->getEmail()],
        [
            'name' => $ssoUser->getName(),
            'sso_id' => $ssoUser->getId(),
            'password' => Illuminate\Support\Facades\Hash::make(Illuminate\Support\Str::random(24)),
            'role' => $localRole // Assign the determined local role
        ]
    );

    Auth::login($user, true);
    return redirect('/dashboard');
});

Result: If a user logs in with the Super Admin role from the IdP, they are assigned the admin role in the Events app. If they have the Event Organizer role, they become an organizer. Otherwise, they are a regular user.

2. WordPress Blog (holidaylandmark.com/blog)

Your WordPress blog has the roles user (Subscriber), editor, and admin (Administrator). You will implement the mapping in your custom SSO plugin.

File: wp-content/plugins/holidaylandmark-sso-client/holidaylandmark-sso-client.php

php// ... inside the add_action('login_init', ...) function, after you fetch user_info

$user_info = json_decode(wp_remote_retrieve_body($user_info_response), true);
$idpRoles = array_column($user_info['roles'] ?? [], 'name');

// --- Role Mapping Logic ---
$role_mapping = [
    'Super Admin' => 'administrator',
    'Content Editor' => 'editor',
    'General User' => 'subscriber'
];

$wp_role = 'subscriber'; // Default role

// Find the highest-priority role the user has that exists in our mapping
if (in_array('Super Admin', $idpRoles)) {
    $wp_role = $role_mapping['Super Admin'];
} elseif (in_array('Content Editor', $idpRoles)) {
    $wp_role = $role_mapping['Content Editor'];
} elseif (in_array('General User', $idpRoles)) {
    $wp_role = $role_mapping['General User'];
}
// --- End Mapping Logic ---

$user = get_user_by('email', $user_info['email']);
if (!$user) {
    // (user creation logic from the guide)
    $user_id = wp_create_user(...);
    $user = get_user_by('id', $user_id);
}

// Update the user's role every time they log in
wp_update_user([
    'ID' => $user->ID,
    'role' => $wp_role
]);

// ... rest of the login logic

Result: A user with the IdP role Content Editor is granted the editor role in WordPress, and Super Admin gets administrator.

3. Flarum Forum (holidaylandmark.com/forum)

Flarum uses Groups for permissions. Let’s assume you’ve created groups in your Flarum admin panel named AdministratorsModerators, and the default Members.

File: extend.php (in your Flarum SSO extension)

php// ... inside the ->get('/auth/holidaylandmark', ...) route, after you fetch $ssoUser

$ssoUser = json_decode((string) $response->getBody(), true);
$idpRoles = array_column($ssoUser['roles'] ?? [], 'name');

$user = User::where('email', $ssoUser['email'])->first();
if (!$user) {
    // (user registration logic)
}

// --- Role Mapping Logic ---
$groupMapping = [
    'Super Admin' => 'Administrators',
    'Content Editor' => 'Moderators'
    // 'General User' maps to the default 'Members' group, which is automatic for new users
];

// Find the IDs of the Flarum groups to assign
$groupNamesToAssign = [];
foreach ($idpRoles as $role) {
    if (isset($groupMapping[$role])) {
        $groupNamesToAssign[] = $groupMapping[$role];
    }
}

$groupIds = \Flarum\Group\Group::whereIn('name_singular', $groupNamesToAssign)->pluck('id')->all();

// Always include the default Member group (ID 3)
if (!in_array(3, $groupIds)) {
    $groupIds[] = 3;
}

// Sync the user's groups based on their IdP roles
$user->groups()->sync($groupIds);
$user->save();
// --- End Mapping Logic ---

$authenticator->logIn($session, $user->id);
return $rememberer->remember(new RedirectResponse(app('flarum.config')['url']));

Result: A user with the Content Editor role in the IdP will be added to the Moderators group in Flarum upon login, giving them the specific permissions you have configured for that group.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x